类属性何时需要?例如:
self.MyProperty = @"hi there";
VS
MyProperty = @"hi there";
MyProperty是一个NSString设置为(非原子,复制)。上述两个内存管理有什么不同吗?
什么时候没有属性,并且在头文件中声明了变量MyProperty?如果从未在类之外引用,是否需要属性?这会对内存管理产生影响吗?
答案 0 :(得分:8)
是的,内存和性能都有所不同。
MyProperty = @"hi there";
这被认为是直接分配。实际上没有内存或性能影响。当然,这并不是说这是最佳实践 - 这是一个不同的问题:)
@property(nonatomic, copy) NSString *MyProperty;
// ...
self.MyProperty = @"hi there";
此声明对内存和性能有重大影响。这基本上相当于:
-(void)setMyProperty(NSString *)newValue {
if (MyProperty != newValue) {
[MyProperty release];
MyProperty = [newValue copy];
}
}
释放旧值并将新值复制到MyProperty中。这是可以接受的,尤其是当你的分配字符串是可变的时候处理字符串时(例如,它可能会在以后更改)。
如果在你的例子中,你只是简单地指定一个静态字符串(@“hi there”),直接分配字符串值没有错;它的效率更高,但性能上的差异是微不足道的。
您可以将@property的属性声明为retain,copy或assign(默认为assign)。然后,您可以使用@synthesize生成“访问者”(getter / setter)方法。以下是执行此操作时生成的setter方法的外观:
// @property(nonatomic, assign)
-(void)setMyProperty(NSString *)newValue {
MyProperty = newValue;
}
// @property(nonatomic, retain)
-(void)setMyProperty(NSString *)newValue {
if (property != newValue) {
[property release];
property = [newValue retain];
}
// @property(nonatomic, copy)
-(void)setMyProperty(NSString *)newValue {
if (property != newValue) {
[property release];
property = [newValue copy];
}
}
有关ObjectiveC Declared Properties的更多信息。
“您可以在@implementation块中使用@synthesize和@dynamic指令来触发特定的编译器操作。请注意,任何给定的@property声明都不需要。
重要说明:如果没有为特定属性指定@synthesize或@dynamic,则必须为该属性提供getter和setter(或者只是readonly属性的getter)方法实现。“
换句话说,如果声明属性但不合成属性,除非定义“MyProperty”和“setMyProperty”方法,否则将无法使用[self MyProperty]或self.MyProperty。如果您没有声明属性,那么您只需要一个实例变量。
注意:@dynamic不会生成访问者。如果您通过加载代码或动态方法解析动态地(即,神奇地)解析访问器方法,它就真的被使用了。
答案 1 :(得分:7)
区别在于
self.MyProperty = @"hi there"
是点符号调用,它将调用生成的访问器,它将正确处理保留计数(相当于[self setMyProperty:@“hi there”]),而
MyProperty = @"hi there"
是对您的成员变量的直接赋值,它不会释放旧值,保留新值,或者执行您的访问者所做的任何其他操作(例如,如果您有自定义setter执行额外工作)。
所以,是的,内存管理和两者之间的行为存在很大差异。后一种形式几乎总是错误的,除非您明确知道为什么要这样做,并且您自己正确处理保留计数。
答案 2 :(得分:3)
如果你使用自动Key-Value Observing(或任何基于它构建的Cocoa技术 - 比如绑定,......),使用setter也很重要。如果您分配给ivar,观察员将不会收到任何通知。 如果将“MyProperty”绑定到NSTextfield并通过代码更改“MyProperty”ivar,则绑定的文本字段仍会显示旧值,因为它没有收到任何更改通知。
答案 3 :(得分:2)
要访问变量,通常不需要使用点表示法。因此,在XCode模板生成的代码中,您将看到如下内容:
[flipsideViewController viewWillAppear:YES];
这里没有必要编写self.flipsideViewController,因为除了处理变量外,访问器方法通常什么都不做。
所以一个好的经验法则是当你设置一个变量时使用点符号(除非你想要自己保留和释放,否则绝对必要),但是当你是访问:
self.aString = @"Text text text";
NSLog (aString); // No need for self.aString here
NSString* tmpString = aString; // Here neither
当你使用非对象类型时,比如int或float或许多其他类型,你可以不使用点符号/ setter方法。在这些情况下,没有什么可以保留,所以setter方法除了分配值之外几乎没有什么用。
然而,合成的getter和setter不仅仅是保留和释放。正如其他人所提到的,它们也是保持KVO系统运行的引擎。因此,即使在整数,浮点数和其余部分也应该使用适当的设定器。
那么访问者呢?在更高级的上下文中,即使变量不存在,类也可能响应对变量值的请求。为了引用高级的Objective-C手册,类可以直接或在运行时使用其他机制[而不是简单的访问器方法]提供“方法实现”,例如动态加载代码或动态方法解析。“
(实现这种对消息的即时响应的一种方法是重写NSObject方法,如methodSignatureForSelector:和forwardInvocation:。)
出于这个原因,使用正确声明的接口(无论是否合成)总是一个好主意,当你在做大事。但只要您使用适当的API 设置它们就可以直接访问ivars。
(注意:我不是可可大师,因此非常欢迎更正。)
答案 4 :(得分:1)
对于问题的第二部分,不需要属性定义,这对我们有帮助。属性上的@synthesize指令为属性生成访问器方法,因此我们不必手动执行,因为:
此代码指示编译器 生成或合成访问者 方法。编译器将生成 使用的访问方法 经过充分测试的快速算法 准备好多核和 多线程环境,包括 在setter方法中锁定变量。 使用属性不仅减少了 你需要的代码量 写,它用。替换该代码 今天最好的访问者 现代多核系统。以后,如果 你需要提供一个替代方案 财产的实施 访问者,你可以简单地添加 适合您班级的代码。
http://developer.apple.com/leopard/overview/objectivec2.html
nonatomic
将在访问变量时避免使用锁定,如果您未指定任何内容,则默认值为atomic
。锁定在多线程系统上很有用。副本指定应为访问者生成哪些代码,copy
将复制对象,retain
将保留新对象并释放旧对象,assign
对于简单变量(如int)只是普通的分配值。
因此,当您按照(nonatomic,copy)
上面的方式定义属性然后使用self.MyProperty = @"Hey"
时,您实际上正在调用生成的访问器,它将创建新变量的副本而不是仅仅分配它。您可以覆盖访问者并向其添加检查。
由于上述原因,我会说定义属性即使在类之外没有使用变量也有好处。
我相信您应该使用self.MyProperty
而非MyProperty
来访问属性,但我无法向您解释原因。
可能与编译器将从
self.MyProperty = @"Hey";
这样:
[self setMyProperty: @"Hey"];
但我只是在这里推测。
无论你是调用self.MyProperty还是MyProperty,它都不应该影响内存管理(我仍然更喜欢第一个 - self.MyProperty)。
有关Apple的一些高级别说明,请参阅Objective-C 2.0 Overview。
答案 5 :(得分:1)
作为其他答案的补充,尝试以这种方式思考:
self.MyProperty = @"hi there";
或
[self setMyProperty:@"hi there"];
(相当于)都调用方法,而
MyProperty = @"hi there";
只需设置一个变量。
答案 6 :(得分:1)
这是一个老问题,虽然它曾经是“我什么时候写[self setMyProperty:@"hi there"]
?” (请注意,self.MyProperty = @"hi there"
与此完全相同。)
我一直听到的答案(而且很有道理)总是使用访问者; 从不写MyProperty = @"hi there"
。有几个原因:
MyProperty
需要产生特定的副作用,你可以添加到setter方法,而不是每次都设置MyProperty
。MyProperty
问题,可以很容易地将记录代码添加到setter(甚至是getter),以便每次更改(甚至访问)时都能找到它。摘要:总是使用[self setMyProperty:@"hi there"]
或self.MyProperty = @"hi there"
,从不使用MyProperty = @"hi there"
,这是最安全和最灵活的。
答案 7 :(得分:0)
还不清楚何时使用访问器以及何时在ivars上进行直接分配?我见过许多直接访问ivars的Apple示例。所以使用所有ivars的属性似乎是迂腐的矫枉过正。
似乎只有重要的ivars需要更长时间并且在外部访问往往使用属性。
希望一些可可大师介入并澄清。