KVO的使用
KVO的使用
KVO是一种设计模式,名为观察者.
addObserver:forKeyPath:options:context:
通知其他对象的方法,这个方法在NSObject中就已经申明了,也就是说任何继承自NSObject的对象都可以使用KVO.
我们来实现一个对象a值改变的时候去通知对象b.
新建两个ModelA ModelB 类.
ModelA.h + ModelA.m
#import <Foundation/Foundation.h> @interface ModelA : NSObject @property (nonatomic, strong) NSString *name; @end
#import "ModelA.h" @implementation ModelA @end
ModelB.h + ModelB.m
#import <Foundation/Foundation.h> @interface ModelB : NSObject @property (nonatomic, strong) NSString *sex; @end
#import "ModelB.h" @implementation ModelB -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { self.sex = @"female"; } @end
请将如下延时执行的代码添加进工程当中
- (void)delay:(int64_t)delta execute:(dispatch_block_t)block { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta * NSEC_PER_SEC), dispatch_get_main_queue(), block); }
然后再写如下的代码:
执行结果如下:
2014-05-06 17:40:35.346 FileManager[20208:60b] Application windows are expected to have a root view controller at the end of application launch
2014-05-06 17:40:37.347 FileManager[20208:60b] female
如果注释掉ModelB中的方法observeValueForKeyPath:ofObject:change:context:,运行时会导致崩溃:
如果重复移除了两次,也会导致崩溃-_-!!!!
也就是这么一层关系:
A对象要通知B对象,B对象必须实现监听的方法,否则一旦有消息发送就会导致崩溃.
A对象不想通知B对象了,需要从B对象身上移除掉通知.
要想程序不出现问题,我们需要实现3步.
(主动添加B的通知) A -------> B(不实现一个方法就崩溃)
(主动移除B的通知) A ---X--> B
(重复移除B的通知) A ---X--> B(崩溃)
用起来很恶性,还好,我们可以重复添加B的通知而不崩溃......
问题:在ARC中我们需要移除KVO的observer么?
You should explicitly remove the observer even you use ARC
. Create a dealloc
method and remove there..
-(void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:self];}
If you see the method you don't need to call [super dealloc];
here, only the method without super dealloc needed.
你需要非常明确的移除你的通知者,即使是在ARC中.创建一个dealloc
方法然后在方法里面移除.
ARC中你不需要调用[super dealloc].
问题:ARC给一个对象添加了observer有可能会导致循环应用什么的么?
You need to call removeObserver
, ARC only automates retain counts. removeObserver
does not impact the retain count.
你需要调用removeObserver
,ARC只是自动管理了retain counts,removeObserver
并不影响retain count.(这一点我不确定,有待验证)
问题:当要通知的对象已经nil了,这个通知会自动移除吗?
Observers are not removed automatically. From the NSNotificationCenter Class Reference:
观察者不会自动移除,请查看NSNotificationCenter类的原文引述:
Important: The notification center does not retain its observers, therefore, you must ensure that you unregister observers (using removeObserver: or removeObserver:name:object:) before they are deallocated. (If you don't, you will generate a runtime error if the center sends a message to a freed object.)
很重要:通知中心并不会retain他的观察者,所以,你必须确保你那些对象销毁之前注销掉观察者,否则就会出现错误.
You should therefore call
[[NSNotificationCenter defaultCenter] removeObserver:self];
in your dealloc
method if you are not 100% sure that the observer was not removed previously.
addObserver:forKeyPath:options:context:
Registers anObserver to receive KVO notifications for the specified key-path relative to the receiver.
Parameters
- anObserver
-
The object to register for KVO notifications. The observer must implement the key-value observing method
observeValueForKeyPath:ofObject:change:context:
. - keyPath
-
The key path, relative to the receiver, of the property to observe. This value must not be
nil
. - options
-
A combination of the
NSKeyValueObservingOptions
values that specifies what is included in observation notifications. For possible values, see “NSKeyValueObservingOptions.” - context
-
Arbitrary data that is passed to anObserver in observeValueForKeyPath:ofObject:change:context:.
Discussion
Neither the receiver, nor anObserver, are retained.