在kvo多线程程下使用kvo要注意什么

ios 使用kvo需要注意哪些地方_百度知道
ios 使用kvo需要注意哪些地方
我有更好的答案
逻辑并不复杂:检查对象的类有没有相应的 setter 方法.Apple 的文档真是一笔带过, pointing to an intermediate class rather than at the true class 。不仅如此,Apple 还重写了 -class 方法,又知道如何去实现一个 KVO,那就尝试自己动手写一个简易的 KVO 玩玩。首先,这个中间类: 方法;t implement the setter
SEL setterSelector = NSSelectorFromString(setterForGetter(key));
if (!setterMethod) {
/&#47,不行;想要传一个 block ,以及获得不少分享讨论的KVO Considered Harmful 都把 KVO 拿出来吊打了一番,并把 isa 指向这个新建的子类;检查对象的 KVO 类重写过没有这个 setter 方法,所有被掩盖的细节都会原形毕露。Mike Ash 早在 2009 年就做了这么个探究,对象就神奇的变成了新创建的子类的实例。原来,去跑一下 Mike Ash 的那篇文章里的代码就能明白,Apple 并不希望过多暴露 KVO 的实现细节。不过。KVO 缺陷KVO 很强大。这个类继承自该对象的原本的类,并重写了被观察属性的 setter 方法,就能使用 KVO ;
NSString *clazzName = NSStringFromClass(clazz);
&#47?KVO 实现机制KVO 的实现也依赖于 Objective-C 强大的 Runtime 。Apple 的文档有简单提到过 KVO 的实现:Automatic key-value observing is implemented using a technique called isa-swizzling.。如果没有抛出异常;检查对象 isa 指向的类是不是一个 KVO 类。自己实现 KVO如果没找到理想的,就自己动手做一个,代码写的很别扭KVO 是 Objective-C 对观察者模式(Observer Pattern)的实现。也是 Cocoa Binding 的基础,你只能通过重写 -observeValueForKeyPath,一个新的类会动态被创建。所以在实际开发中 KVO 使用的情景并不多。简单概述下 KVO 的实现。有意思的是; throw invalid argument exception
Class clazz = object_getClass(self),我们创建 NSObject 的 Category,并在头文件中添加两个 API:forKeyPath:options:context: 传进去一个父类不知道的 context: Throw exception if its class or superclasses doesn&#39,更多时候还是用 Delegate 或 NotificationCenter,你不需要给被观察的对象添加任何额外代码: 方法来获得通知。想要提供自定义的 selector :(NSString *)key
withBlock:(NSObject *)observer
forKey:(NSString *)key
withBlock:(PGObservingBlock)- (void)PG_removeObserver:(NSObject *)observer forKey:(NSString *)@end接下来,实现 PG_addObserver:forKey。这是怎么做到的。既然我们对官方的 API 不太满意。如果没有,添加重写的 setter 方法;添加这个观察者- (void)PG_addObserver:(NSObject *)observer
forKey:typedef void(^PGObservingBlock)(id observedObject.. When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, id newValue);@interface NSObject (KVO)- (void)PG_addObserver,没错。知道它内部实现,或许能帮助更好地使用它,或在它出错时更方便调试。但官方实现的 KVO 提供的 API 实在不怎么样。比如..:withBlock:当你观察一个对象时,唯一有用的信息也就是:被观察对象的 isa 指针会指向一个中间类,而不是原来真正的类。看来,企图欺骗我们这个类没有变,就是原本那个类。更具体的信息; Step 1,要是你用 runtime 提供的方法去深入挖掘, NSString *observedKey, id oldValue。自然,重写的 setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象值的更改。Mike Ash 的 Key-Value Observing Done Right。最后把这个对象的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么 ) 指向这个新创建的子类。但有时候,你不知道父类是不是对这个消息有兴趣。虽然 context 这个参数就是干这个的,也可以解决这个问题 - 在 -addObserver,继承自原本的那个类:context。至少至少,也应该支持 block 吧。有不少人都觉得官方 KVO 不好使的,这里就不再重复:ofObject:change,门都没有。而且你还要处理父类的情况 - 父类同样监听同一个对象的同一个属性。但总觉得框在这个 API 的设计下。当被观察对象的某个属性发生更改时,观察者对象会获得通知:(PGObservingBlock)block{
/// Step 2: Make KVO class if this is first time adding observer and
its class is not an KVO class yet
if (![clazzName hasPrefix:kPGKVOClassPrefix]) {
clazz = [self makeKvoClassWithOriginalClassName:clazzName];
object_setClass(self, clazz);
// Step 3: Add our kvo setter method if its class (not superclasses)
hasn't implemented the setter
if (![self hasSelector:setterSelector]) {
const char *types = method_getTypeEncoding(setterMethod);
class_addMethod(clazz, setterSelector, (IMP)kvo_setter, types);
// Step 4: Add this observation info to saved observation objects
PGObservationInfo *info = [[PGObservationInfo alloc] initWithObserver:observer Key:key block:block];
NSMutableArray *observers = objc_getAssociatedObject(self, (__bridge const void *)(kPGKVOAssociatedObservers));
if (!observers) {
observers = [NSMutableArray array];
objc_setAssociatedObject(self, (__bridge const void *)(kPGKVOAssociatedObservers), observers, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[observers addObject:info];}附上出处链接:;
Method setterMethod = class_getInstanceMethod([self class], setterSelector)。如果不是,新建一个继承原来类的子类
专注培养IT技术人才
主营:PHP培训,JAVA培训,HTML5培训,UI培训,Linux培训,Python培训
为您推荐:
其他类似问题
ios的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。使用KVO体会 - pengyingh - 博客园
学习并使用KVO有段时间了,在之前也简单的介绍了KVO机制,
这种机制提供了监听某些类属性变化的机制.在MVC中,简单的说,通过监听M的变化,可以及时更新V.因为监听属性明确,当有变化时就直接传递到观察者.
考虑这样一种情况:请求某网站的rss,并将内容解析出来在tableview中显示出来.因为网络请求以及数据解析需要时间,如果我们把获得的全部数据解析后再显示出来,在用户体验上就会非常不好:用户启动程序后,风火轮可能需要转很久,然后突然就冒出来一大堆的数据.
改进的方法之一就是使用KVO,当有一条数据解析好后,就解析出来,直到全部数据解析完.具体的实现步骤:
在controller注册一个属性,通常是NSMutableArray,然后实现KVO的accessory.
实现KVO的方法--observeValueForKeyPath:ofObject:change:context:,在此方法中我们设置好属性变化时view的变化情况.具体说来,就是当NSMutableArray添加数据,替换或删除数据时的UI更新操作
当数据有变化时,调用属性相应的方法,来激发KVO机制.
可是某一天,突然有人问我:为什么需要使用KVO啊,你使用KVO代码量未必会减少,并且更新UI的操作我完全可以在数据有变化时进行&手工&操作啊.
当时我确实被问到了,可是细细想来KVO还是有不少&好处&的:
避免了所谓的胶水代码,也就是说我不需要每次在有数据更新的地方都加上UI的更新操作
你或者说,数据更新的来源单一,我通常只需要在一处实现UI更新即可.那么考虑下,在手机平台上, 通常为了用户体验会将获取数据操作放到后台或次线程中,那么你更新UI操作又必须回到主线程.而使用KVO你就不需要操这些心.
从程序的结构而言,程序&&分离&&的比价彻底:获取数据的部分和UI更新的部分没有交叠,由KVO将两者联系了起来,这样看来难道不算是优雅吗?
对kvo/kvc做了简单的介绍,可作为入门读物。
有些术语描述不够精确请指正。
欢迎讨论。
Kvo是Cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据A(数据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用的地方非常广泛。(这样的机制听起来类似Notification,但是notification是需要一个发送notification的对象,一般是notificationCenter,来通知观察者。而kvo是直接通知到观察对象。)
适用kvo时,通常遵循如下流程:
-(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context
keyPath就是要观察的属性值,options给你观察键值变化的选择,而context方便传输你需要的数据(注意这是一个void型)
2 实现变化方法:
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)objectchange:(NSDictionary *)change context:(void*)context
change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。
是不是很简单?kvo的逻辑非常清晰,实现步骤简单。
说了这么多,大家都要跃跃欲试了吧。可是,在此之前,我们还需要了解KVC机制。其实,知道了kvo的逻辑只是帮助你理解而已,要真正掌握的,不在于kvo的实现步骤是什么,而在于KVC,因为只有符合KVC标准的对象才能使用kvo(强烈推荐要使用kvo的人先理解KVC)。
KVC是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor方法或是直接访问成员对象。
key就是确定对象某个值的字符串,它通常和accessor方法或是变量同名,并且必须以小写字母开头。Key path就是以&.&分隔的key,因为属性值也能包含属性。比如我们可以person这样的key,也可以有key.gender这样的key path。
获取属性值时可以通过valueForKey:的方法,设置属性值用setValue:forKey:。与此同时,KVC还对未定义的属性值定义了valueForUndefinedKey:,你可以重载以获取你要的实现(补充下,KVC定义载NSKeyValueCoding的非正式协议里)。
在O-C 2.0引入了property,我们也可以通过.运算符来访问属性。下面直接看个例子:
@property NSIinstance.number =3;[instance setValue:[NSNumber numberWithInteger:3] forKey:@"number"];
注意KVC中的value都必须是对象。
以上介绍了通过KVC来获取/设置属性,接下来要说明下实现KVC的访问器方法(accessor method)。Apple给出的惯例通常是:
-key:,以及setKey:(使用的name convention和setter/getter命名一致)。对于未定义的属性可以用setNilValueForKey:。
至此,KVC的基本概念你应该已经掌握了。之所以是基本,因为只涉及到了单值情况,kvc还可以运用到对多关系,这里就不说了,留给各位自我学习的空间
接下来,我们要以集合为例,来对掌握的KVC进行一下实践。
之所以选择array,因为在ios中,array往往做为tableview的数据源,有这样的一种情况:
&假设我们已经有N条数据,在进行了某个操作后,有在原先的数据后多了2条记录;或者对N中的某些数据进行更新替换。不使用KVC我们可以使用reloadData方法或reloadRowsAtIndexPaths。前一种的弊端在于如果N很大消耗就很大。试想你只添加了几条数据却要重载之前N数据。后一种方法的不足在于代码会很冗余,你要一次计算各个indexPath再去reload,而且还要提前想好究竟在哪些情况下会引起数据更新,
倘若使用了KVC/kvo,这样的麻烦就迎刃而解了,你将不用关心追加或是更新多少条数据。
下面将以添加数据为例,说明需要实现的方法:
实现insertObject:inKeyAtIndex:或者insertKey:atIndexes。同时在kvo中我们可以通过change这个dictionary得知发生了哪种变化,从而进行相应的处理。他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)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 *
#import "ModelA.h"
@implementation ModelA
ModelB.h + ModelB.m
#import &Foundation/Foundation.h&
@interface ModelB : NSObject
@property (nonatomic, strong) NSString *
#import "ModelB.h"
@implementation ModelB
-(void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
self.sex = @"female";
请将如下延时执行的代码添加进工程当中
- (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);
然后再写如下的代码:
执行结果如下:
&17:40:35.346&FileManager[20208:60b] Application windows are expected to have a root view controller at the end of application launch&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.
-&(void)addObserver:(&*)anObserver&forKeyPath:(&*)keyPath&options:()options&context:(void *)context
Parameters
anObserver
The object to register for KVO notifications. The observer must implement the key-value observing method&.
The key path, relative to the receiver, of the property to observe. This value must not be&nil.
A combination of the&&values that specifies what is included in observation notifications. For possible values, see&
Arbitrary data that is passed to&anObserver&in&.
Discussion
阅读(...) 评论()}

我要回帖

更多关于 多线程的使用场景 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信