Why shouldn't I use Objective C 2.0 accessors in init/dealloc?
在@mmalc对这个问题的回答中,他指出"一般来说,您不应该在dealloc(或init)中使用accessor方法。"mmalc为什么这么说?
我能想到的唯一真正原因是性能和避免@dynamic setter未知的副作用。
讨论?
它基本上是一个最小化潜在错误的指导方针。
在这种情况下,(可能)您的setter/getter可能无意中对对象的状态做出直接或间接的假设。当对象处于设置或销毁过程中时,这些假设可能是一个问题。
例如,在下面的代码中,观察者不知道"example"正在被销毁,可能会假定已经释放的其他属性是有效的。
(您可能会争辩说,您的对象应该在分解之前删除所有观察者,这是一个很好的实践,也是防止意外问题的另一个准则)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | @implementation Example -(void) setFoo:(Foo*)foo { _foo = foo; [_observer onPropertyChange:self object:foo]; } -(void) dealloc { ... self.foo = nil; } @end |
这一切都是关于使用习惯上一致的代码。如果您对所有代码都进行了适当的模式化,那么有一些规则可以保证在init/dealloc中使用访问器是安全的。
最大的问题是(正如mmalc所说)设置属性默认状态的代码不应该通过访问器,因为它会导致各种各样的棘手问题。catch是init不必设置属性的默认状态。出于许多原因,我一直在转向自初始化的访问器,如下面的简单示例:
1 2 3 4 5 6 7 | - (NSMutableDictionary *) myMutableDict { if (!myMutableDict) { myMutableDict = [[NSMutableDictionary alloc] init]; } return myMutableDict; } |
这种类型的属性初始化允许延迟许多实际上不需要的初始化代码。在上述情况下,in it不负责初始化属性状态,并且在init方法中使用访问器是完全安全的(甚至是必要的)。
诚然,这确实对代码施加了额外的限制,例如,具有自定义访问器的子类对于超类中的属性必须调用超类访问器,但这些限制与cocoa中常见的各种其他限制并不冲突。
你回答了自己的问题:
如果类可能是子类的话,后者尤其是一个问题。
但是,还不清楚为什么要在Objective-C2访问器中专门解决这个问题?无论您自己使用声明的属性还是写访问器,同样的原则都适用。
可能是setter具有应该运行的逻辑,或者可能是实现使用了与getter/setter不同的名称的ivar,或者可能是需要释放和/或将其值设置为nil的两个ivar。唯一可靠的方法是调用setter。setter的职责是以这样的方式编写:在in it或dealloc期间调用时,不会出现不良的副作用。
从"可可图案",巴克,雅克特曼,第115页:"…当您将合成实例变量与现代的Objective-C运行时一起使用时,没有实际的替代方法来使用访问器,或者……
您可以通过在分配/解除分配时不调用setter来创建相同的问题。
我认为您不能通过直接在in i t/dealloc中使用retain/release来实现任何目的。您只需更改一组可能的错误。
每次你都要考虑财产分配/解除分配的顺序。
事实上,对于一个经常来来去去的类(像一个细节视图控制器),您希望在init中使用访问器;否则,您可能最终在viewdidUnload中释放一个您稍后尝试访问的值(它们在cs193p中显示…)