方法#1
(AnObject *)theObject{ if (theObject == nil){ theObject = [[AnObject createAnAutoreleasedobject] retain]; } return theObject; }
方法#2
(AnObject *)theObject{ if (theObject == nil){ self.theObject = [AnObject createAnAutoreleasedobject]; } return theObject; }
首先,我不确定是否可以访问访问者中的另一个访问者功能(但不知道为什么不这样做).但似乎设置类变量而不通过setter可能同样糟糕,如果setter执行某些特殊操作(或者如果属性更改为除了retain之外的某些内容并且未检查getter).
解决方法
使用#1,您可以避开setter,因此,观察到更改的任何内容都不会看到更改.通过“观察”,我特别指的是键值观察(包括Cocoa Bindings,它使用KVO自动更新UI).
使用#2,您将触发更改通知,更新UI,否则就像调用setter一样.
在这两种情况下,如果对象的初始化调用getter,则可能无限递归.这包括如果任何观察者要求将旧值作为更改通知的一部分.不要那样做.
如果您要使用任何一种方法,请仔细考虑后果.一个人有可能使应用程序处于不一致状态,因为属性的状态更改未通知而另一个可能存在死锁.
最好完全避免这个问题.见下文.
考虑(垃圾收集,标准Cocoa命令行工具:
#import <Foundation/Foundation.h> @interface Foo : NSObject { Nsstring *bar; } @property(nonatomic,retain) Nsstring *bar; @end @implementation Foo - (Nsstring *) bar { if (!bar) { NSLog(@"[%@ %@] lazy setting",NsstringFromClass([self class]),NsstringFromSelector(_cmd)); [self willChangeValueForKey: @"bar"]; bar = @"lazy value"; [self didChangeValueForKey: @"bar"]; } return bar; } - (void) setBar: (Nsstring *) aString { NSLog(@"[%@ %@] setting value %@",NsstringFromSelector(_cmd),aString); bar = aString; } @end @interface Bar:NSObject @end @implementation Bar - (void)observeValueForKeyPath:(Nsstring *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context; { NSLog(@"[%@ %@] %@ changed\n\tchange:%@",keyPath,change); } @end int main (int argc,const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Foo *foo = [Foo new]; Bar *observer = [Bar new]; CFRetain(observer); [foo addobserver:observer forKeyPath:@"bar" options: NSkeyvalueObservingOptionPrior | NSkeyvalueObservingOptionNew context:NULL]; foo.bar; foo.bar = @"baz"; CFRelease(observer); [pool drain]; return 0; }
这不会挂起.它喷出:
2010-09-15 12:29:18.377 foobar[27795:903] [Foo bar] lazy setting 2010-09-15 12:29:18.396 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed change:{ kind = 1; notificationIsPrior = 1; } 2010-09-15 12:29:18.397 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed change:{ kind = 1; new = "lazy value"; } 2010-09-15 12:29:18.400 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed change:{ kind = 1; notificationIsPrior = 1; } 2010-09-15 12:29:18.400 foobar[27795:903] [Foo setBar:] setting value baz 2010-09-15 12:29:18.401 foobar[27795:903] [Bar observeValueForKeyPath:ofObject:change:context:] bar changed change:{ kind = 1; new = baz; }
如果你要将NSkeyvalueObservingOptionOld添加到观察选项列表中,它就会挂起.
回到我之前发表的评论;最好的解决方案是不要将延迟初始化作为getter / setter的一部分.它太精细了.在更高级别管理对象图状态会好得多,作为其中一部分,状态转换基本上是“哟!我现在要使用这个子系统!温暖那个坏孩子! “这是懒惰的初始化.
原文地址:https://www.jb51.cc/c/111550.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。