美文网首页开发小技巧
Objective-C分析之二

Objective-C分析之二

作者: MrSong | 来源:发表于2017-10-17 16:10 被阅读6次

发送消息(Sending Messages)

  • performSelector:withObject:afterDelay:

    • 在当前线程延迟执行某个方法,定时器会以默认模式NSDefaultRunLoopMode运行。也就是说如果当前runloop不是默认模式的话,定时器不会执行。
  • performSelector:withObject:afterDelay:inModes:

    • 可以指定mode延迟执行某个方法。
  • performSelectorOnMainThread:withObject:waitUntilDone:

    • 在主线程延迟执行某个方法
  • performSelectorOnMainThread:withObject:waitUntilDone:modes:

    • 在主线程指定mode延迟执行某个方法
  • cancelPreviousPerformRequestsWithTarget:

    • 取消执行某个方法
  • cancelPreviousPerformRequestsWithTarget:selector:object:

    • 取消执行某个方法
  • performSelectorInBackground:withObject:

    • 在新的子线程执行某个方法

消息转发(Forwarding Messages)

  • forwardingTargetForSelector:

    • 消息转发,对象中找不到方法时会调用这个方法,如果可以执行就返回可用的方法,否则执行methodSignatureForSelector:方法对方法进行签名,如果返返回nil就抛出异常,否则就调用forwardInvocation:进行尝试,如果还是不行就调用doesNotRecognizeSelector:抛出异常。
  • forwardInvocation:

    • 有子类重写来实现消息转发到其他对象。如果执行失败就调用doesNotRecognizeSelector:抛出异常。

动态执行(Dynamically Resolving Methods)

  • resolveClassMethod:
    • 动态给类方法选择实现函数,返回YES标示找到了方法,否则就是找不到方法。然后就进入消息转发流程。
  • resolveInstanceMethod:
    • 动态给对象方法选择实现函数,返回YES标示找到了方法,否则就是找不到方法。然后就进入消息转发流程。
    • OC方法就是一个C函数,包含self和_cmd至少两个参数,使用class_addMethod方法可以将C函数添到的OC类上。

错误处理(Error Handling)

  • doesNotRecognizeSelector:
    • 消息转发的最后一步,抛出异常。如果重写这个方法,必须调用super或者自己抛出异常。

归档(Archiving)

  • 这个方式很少用,不是很了解,就不写那么多了。

对象方法(Instance Methods)

  • addObserver:forKeyPath:options:context:

    • KVO监听属性
  • awakeFromNib

    • xib加载完毕后会调用这个方法,可以这里做一些界面的处理
  • dictionaryWithValuesForKeys:

    • 根据字典数组的key拿去对应的数据,必须保证key存在,否则返回nil
    NSDictionary *temp1 = @{@"1":@"111",@"2":@"2222",@"3":@"333"};
    NSDictionary *temp2 = [temp1 dictionaryWithValuesForKeys:@[@"1",@"4"]];
    NSLog(@"temp2",temp2);
  • observeValueForKeyPath:ofObject:change:context:
    • KVO监听属性的回调方法,这里会有新值旧值得回调
- (void)viewDidLoad {
    [super viewDidLoad];
    self.label = [UILabel new];
    [self.label addObserver:self forKeyPath:@"text" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"text"];
    self.label.text = @"111";
    self.label.text = @"333";
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    NSLog(@"%@",change);
    /*
     // 第一次拿到的old是null,如果用的话要注意判断
     {
     kind = 1;
     new = 111;
     old = "<null>";
     }
     
     {
     kind = 1;
     new = 333;
     old = 111;
     }
     */
}
  • removeObserver:forKeyPath:

    • 停止kvo监听,确保有注册kvo监听,否则调用这个方法回报错。
  • removeObserver:forKeyPath:context:

    • 指定context去停止kvo监听,这个可以更加具体停止某一个kvo监听。确保有注册kvo监听,否则调用这个方法回报错。
  • setValue:forKey:

    • 通过key设置属性的值
    self.label = [UILabel new];
    [self.label setValue:@"ddddd" forKey:@"text"];//self.label.text = @"dddd";
    NSLog(@"text:%@",self.label.text);
  • setValue:forKeyPath:
    • 指定路径设置属性的值,但是keypath是一个字符串容易出错,少用
    [self setValue:@"eeee" forKeyPath:@"self.label.text"];
    NSLog(@"text:%@",self.label.text);
  • setValue:forUndefinedKey:
    • 在子类中重写这个方法,可以控制给一个不存在的key赋值不闪退,一般在model中会实现这个方法,这样就算服务端返回的字典和model不一致也不会报错。
 - (void)viewDidLoad {
    [super viewDidLoad];
    
    // 这样随便写都不会闪退
    [self setValue:@"dddd" forUndefinedKey:@"ddddd"];
 }

// 这样重写一下就好
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
    
}
  • setValuesForKeysWithDictionary:
    • 通过字典给多个属性同时赋值,要保证字典的key对应的属性都存在或者实现setValue:forUndefinedKey:方法,否则就会报错。
    NSDictionary *temp = @{@"text":@"ddddddddddddddd",@"title":@"song"};
    [self setValuesForKeysWithDictionary:temp];
    NSLog(@"title:%@",self.title);
  • valueForKey:

    • 获取指定key的值
  • valueForKeyPath:

    • 获取指定keypath的值
  • valueForUndefinedKey:

    • 返回未定义的key的值,默认是抛出异常,可以在子类中重写这个类,返回一个默认值。
   self.label.text = @"1234567890-=";
    self.title = @"song"
    NSLog(@"title:%@",[self valueForKey:@"title"]);
    NSLog(@"text:%@",[self valueForKeyPath:@"self.label.text"]);
  • willChangeValueForKey:
    • kvo过程中获取属性的值时会调用这个方法,但是如果要重写这个方法,必须使用super调用父类方法

类型方法(Type Methods)

  • debugDescription
    • debug描述信息
  • hash
    • 对象的hash值

NSObject相关方法到这里就完了,接下来看一下Object对象

Protocol NSObject

  • NSObject 协议,NSObject直接遵守了NSObject协议,所以所以类和对象都遵守了这些协议。
  • class 当前类
  • superclass 父类
  • isEqual: 是否一致
  • hash 对象的hash值,唯一标识符
  • self 当前对象
  • isKindOfClass: 是否是属于某个类,会对父类也进行比较。
  • isMemberOfClass: 是否属于某个类,精确比较当前类,不对父类进行比较。
  • respondsToSelector: 是否相应某一个方法
  • conformsToProtocol: 是否遵守某协议
  • description 打印类或者对象的描述信息。
  • debugDescription 调试状态下打印的描述信息。
  • performSelector:
    • 执行某个方法。执行时机有运行时时决定,如果执行的方法有返回值则无法保证可以获取最终结果。最好是使用performSelectorOnMainThread:withObject:waitUntilDone:或者dispatch_block来实现回调。
  • performSelector:withObject: 带有一个参数的执行某个方法
  • performSelector:withObject:withObject: 带有两个参数的执行某个方法
  • retain 引用计数加一
  • release 引用计数减一
  • autorelease 自动释放池
  • retainCount 引用计数数量
    NSLog(@"self class %@",[self class]);
    NSLog(@"self superclass %@",[self superclass]);
    NSLog(@"self isEqual %zd",[self.label isEqual:lab]);
    NSLog(@"self hash %zd - label %zd",self.hash,self.label.hash);
    NSLog(@"self self %@",self);
    
    // 这个会比较父类
    NSLog(@"self isKindOfClass %zd",[self.label isKindOfClass:[UIView class]]);
    NSLog(@"self isKindOfClass %zd",[self.label isKindOfClass:[UILabel class]]);
    NSLog(@"self isKindOfClass %zd",[self.label isKindOfClass:[UIButton class]]);
    
    // 这个精准比较当前类
    NSLog(@"self isMemberOfClass %zd",[self.label isMemberOfClass:[UILabel class]]);
    NSLog(@"self isMemberOfClass %zd",[self.label isMemberOfClass:[UIButton class]]);
    NSLog(@"self isMemberOfClass %zd",[self.label isMemberOfClass:[UIViewController class]]);
    
    NSLog(@"self conformsToProtocol %zd",[self conformsToProtocol:@protocol(NSObject)]);
    
    NSLog(@"self description %@",self.description);
    NSLog(@"self isProxy %zd",[self isProxy]);
    NSLog(@"self.label isProxy %zd",[self.label isProxy]);

相关文章

网友评论

    本文标题:Objective-C分析之二

    本文链接:https://www.haomeiwen.com/subject/eymduxtx.html