-
OC 和 C的本质区别
C语言在编译的时候我就知道你等下会调用哪一个函数
OC在编译的时候,不知道不要调用哪一个函数(动态编译) -
消息发送机制
#import "ViewController.h"
#import "Person.h"
#import <objc/message.h> // 默认导入Runtime
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
Person *p = [[Person alloc] init];
// [p run];
// 在Xcode5.0之后 苹果不建议使用底层函数
// 发送一个消息给 p
objc_msgSend(p,@selector(run));
objc_msgSend(p, @selector(earWithFoot:),@"香蕉");
// 调用类方法 Class类型也是一个特殊的对象
Class personClass = [Person class];
// 不管是对象还是类 都可以发送消息
objc_msgSend(personClass, @selector(run));
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
#import <Foundation/Foundation.h>
@interface Person : NSObject
+ (void)run;
- (void)run;
- (void)earWithFoot:(NSString *)foot;
@end
#import "Person.h"
@implementation Person
- (void)earWithFoot:(NSString *)foot{
NSLog(@"吃%@",foot);
}
- (void)run{
NSLog(@"跑起来了");
}
+ (void)run{
NSLog(@"类方法");
}
@end```
- 测试
![Paste_Image.png](https://img.haomeiwen.com/i189984/211e905c33804fde.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
###使用Runtime进行方法替换
-
(void)viewDidLoad {
[super viewDidLoad];// 平时这么写 创建URL 但是有可能为空! 如果字符串有中文 那么发送请求就会出错 那么就会Crash 我们想不到Url为空。。
NSURL *url = [NSURL URLWithString:@"www.baidu.com/中文"];
NSLog(@"%@",url);
}```
Paste_Image.png- 使用Category+load实现方法交换
1:第一步 写个url Category
#import <Foundation/Foundation.h>
@interface NSObject (url)
+ (instancetype)JYF_URLWithString:(NSString *)URLString;
@end```
- 第二部分 进行方法交换
import "NSObject+url.h"
import <objc/runtime.h> // 使用Runtime进行方法的交换
@implementation NSObject (url)
// 只要加载这个类 只要参与了加载 就会调用load方法
-
(void)load{
NSLog(@"%s",func);
// 1:拿到两个方法 苹果原来的URLWithString和我们自己扩展的JYFURLWithString
// 获取类方法 class_getClassMethod 实例方法 class_getInstanceMethod
// 参数 1:类型 2:方法编号
Method mURLWithStr = class_getClassMethod([NSURL class], @selector(URLWithString:));
Method mHK_URLWithStr = class_getClassMethod([NSURL class], @selector(JYF_URLWithString:));// 2:交换这两个方法
method_exchangeImplementations(mURLWithStr, mHK_URLWithStr);
} -
(instancetype)JYF_URLWithString:(NSString *)URLString{
NSURL *url = [NSURL JYF_URLWithString:URLString]; // 会找URLWithString这个方法 跑出去了 然后找系统的方法去执行
if (url == nil) {
NSLog(@"哥们是个空的Url");
}
return url;
}
@end
- 测试
![Paste_Image.png](https://img.haomeiwen.com/i189984/cbc6b83e627ccc84.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
- 方法替换成功!!!
- 降低消耗
###使用Runtime进行方法的懒加载:
那么方法的懒加载用过么?懵逼??
- 怎么去懒加载OC中的方法?
- 先加载一个没有的方法 直接报错后 我们在m文件中进行处理
-
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.Person *p = [[Person alloc] init];
// 懒加载:用到的时候再加载方法!!
[p performSelector:@selector(eat)];
[p performSelector:@selector(eat:) withObject:@"板烧鸡腿堡"];
}
import "Person.h"
import <objc/message.h>
@implementation Person
// C语言
// 所有的C语言函数都有这两个隐士参数!只要调用 系统都会传递进来!那个对象的那个方法
void eat(id self, SEL _cmd){
NSLog(@"调用了%@对象的%@方法",self,NSStringFromSelector(_cmd));
NSLog(@"哥们吃了");
}
void eat1(id self, SEL _cmd, id obj){
NSLog(@"哥们今晚吃五个%@", obj);
}
// 当这个类被外界调用了没有实现的方法!!!就会来到这里了!!!
-
(BOOL)resolveInstanceMethod:(SEL)sel{
NSLog(@"您没有实现这个方法%@",NSStringFromSelector(sel));
if (sel == @selector(eat)) {
/*
1 cls:类类型
2 sel: 方法编号
3 imp: 方法实现 传入函数指针!
4 types: 函数类型 C字符串 (代码)void === "v" 需要动态判断 写法根据文档来写
*/
class_addMethod([Person class], sel, (IMP)eat, "v@:");
}else if (sel == @selector(eat:)){
class_addMethod([Person class], sel, (IMP)eat1, "v@:");
}return [super resolveInstanceMethod:sel];
}
@end
- 运行之后
![Paste_Image.png](https://img.haomeiwen.com/i189984/06cb64bcf1cc20ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
网友评论