Objective-C:何时调用self.myObject vs只调用myObject
在Objective-C中,这一点语法对我来说有点混乱。
什么时候应该调用self.myObject vs只调用myObject?
它似乎是多余的,但它们不可互换。
有人请赐教吗?
如果你只是访问他们,没有太多的理由使用self.member
。 如果你正在执行任务,那么如果你做的不仅仅是简单的@property (assign)
参数,比如retain,copy等等,这样可以节省你写的代码。 一个例子:
myObject = anotherObject; self.myObject = anotherObject;
第二个select将确保您实际上按照您想要的方式分配对象(获取副本,增加保留计数等)。 这与[self setMyObject:anotherObject]
没有什么不同。
由于编译器用点符号代替消息(类似于x[5]
在常规数组工作中变成*(x + 5*sizeof(x))
),所以在使用点符号时没有额外的开销或者额外的效率通过常规的消息。
呃,我不能说我同意Mark或Cinder6。
那么,我在第一部分同意。 🙂 self.foo
调用-foo
方法。 平原foo
正在访问foo
伊娃。
在大多数情况下,你应该总是通过你的方法。 他们在那里把你从实际存储中抽象出来,远离其他可能需要的行为。 想想如果你以后再上课,会发生什么事情。 大部分情况下,您希望在您访问其覆盖的function的地方调用您自己的公共方法。
对象init和teardown中的exception,以及属性访问器本身在不合成属性的时候。 在对象初始化和拆卸过程中,你不想调用方法的子类实现,因为这些方法不应该处理你的对象的部分设置状态。
你几乎不应该在同一个类的实现中调用属性访问器。 类的实例方法可以方便地访问内部状态,因此直接访问该状态通常是有意义的。
如果你使用合成的accesors,那么调用它们只会增加(可能)不必要的开销。 如果访问者有一个更复杂的实现,那么你只是模糊了代码的目的。
最后,一些Objective-C的新手使用self.property语法和合成访问器来避免理解Cocoa内存pipe理。 你确实需要了解它是如何工作的,所以试图避免这样做会适得其反。
如果您使用的是核心数据,那么您应该始终使用访问器,因为有些属性可能不会从持久存储中加载直到需要。 (无论如何,假设你正在使用SQLite存储。)
如果你不使用核心数据,那么如果你只是读取这个值,那么直接使用myObject
通常是安全的。 如果您正在修改myObject
的值,则需要使用访问器以确保任何观察该属性值的其他对象都得到了正确的通知。 换一种说法:
// Not changing the value of myObject, so no accessor needed [someMutableArray addObject:myObject]; // Changes the value, so you need to use the accessor self.myObject = newObject; [self setMyObject:newObject]; // Exactly identical to the previous line.
总的来说,这个开销很小, 我更喜欢总是使用访问器,即使在同一个对象内。 (当然,在初始化程序中使用它们是有争议的,但这是一个单独的问题。)
没有切和干的答案。 但是,请记住,过早优化是不好的。 在Mac上的Cocoa或iPhone上,使用访问器/属性需要符合KVO标准。 核心数据和cocoa绑定需要KVO一致性才能自动运行。 在核心数据中,修改属性不仅需要确保KVO,而且在访问时也是如此。
当你想要确保属性内存pipe理行为时,也就是说,当设置一个ivar来使用setter或点符号,并根据你所遵循的内存pipe理模式,总是使用访问器/属性访问者/物业时得到一个伊娃。
有许多不同的内存pipe理模式。 所有未被破坏的函数确保访问器返回的对象至less能够存活到当前自动释放范围的末尾。 意思是,对象在当前的自动释放范围中被明确地保留并自动释放。 苹果推荐的方法在getter中明确地做了这个:
- (id)foo {return [[foo retain] autorelease]; } - (void)setFoo:(id)aFoo { if(! [aFoo isEqual:foo]) { [foo release]; foo = [aFoo retain]; } }
这暗示着他们在合成访问器中遵循的模式。 就我个人而言,我更喜欢在setter中自动释放:
- (id)foo {return foo;} - (void)setFoo:(id)aFoo { [foo autorelease]; foo = [aFoo retain]; }
在用新值replace之前,这个autoreleasees旧值。 这与在getter中保留和自动释放的效果完全一样,但是只需要将对象添加到autorelease池中一次。 大多数情况下,保留数为1,而不是自动释放,所以无论发生什么事,它都不会到达任何地方。 如果在某些代码仍然保留的情况下(例如在委托callback中)该属性被replace,它不会从它下面消失。
这意味着使用访问器/属性会让你放心,只要你需要它们,代码中的其他部分就不会从你的下面释放出来。
总是使用访问器/属性的最后一个也是最好的理由是每个属性只需要less一个假设:这个属性有一个底层ivar,并且名称相同(我猜这是两个假设)。 也许将来你会想用一个派生的访问器replace一个ivar。 财产符号将仍然工作。 也许你想重新命名伊娃; 该物业仍将工作。 幸运的是,通常可以依赖Xcode中的重构,但为什么还要麻烦呢?
面向对象编程的重点是使用类中定义的接口。 没有什么好的理由(虽然有许多偏见和合理的理由)让一个阶级忽略了自己的界面。 除了访问者本身以外,每种方法在一般情况下都应该将对象视为神圣不可侵犯的内部状态。 把每个方法写成一个类或者一个子类,把Ivars作为私有状态,除非特定的devise需要指导你做别的事情。 直接访问ivars有很多很好的理由,但它们是根据具体情况确定的。