在以下常见样本中,
////
@interface MyObject : NSObject
{
@public
NSString * myString_;
}
@property (assign) NSString * myString;
@end
@implementation MyObject
@synthesize myString = myString_;
@end
////
为什么要在界面中声明myString_
?
我问,因为我们仍然可以使用myString
,self.myString
,[self myString]
和self.myString = ...
在实施中设置[self setMyString:...]
,事实上我们必须相反,它被保留。
答案 0 :(得分:5)
这是某些人的偏好/惯例问题。默认情况下,执行:
@property (assign) NSString * myString;
......接着是:
@synthesize myString;
......会给你三件事。您将获得一个可以作为self.myString = @"newValue"
或[self setMyString:@"newValue"]
访问的setter方法,一个可以作为NSString* temp = self.myString
或NSString* temp = [self myString]
访问的getter方法,以及一个名为{{1的实例变量可以直接在类内部访问(即不通过getter和setter)并用于设置和获取属性值,并在内部用于支持属性。
如果您愿意,可以执行myString
,然后您仍然可以像以前一样获得setter和getter,但不使用@synthesize myString = someOtherVarName
实例变量,而是myString
实例变量用于返回属性,并且没有创建someOtherVarName
变量。
那么为什么要使用更详细的语法呢?从来没有任何情况需要您这样做,但有些人更愿意在处理声明为myString
或retain
的属性时执行此操作。这样做的原因是通过其生成的setter方法设置声明为copy
或retain
的属性将影响正在设置/取消设置的对象的保留计数。通过直接访问实例变量来做同样的事情不会。
因此,通过将实例变量别名化为其他内容,您可以在代码中区分“copy
正在修改保留计数的任何内容,而执行xxx.myString = Y
的任何内容都是不”。同样,没有必要这样做,但有些人更喜欢这样做。
答案 1 :(得分:2)
你应该可以跳过它。现代编译器允许这样做。
定义属性时,实际上是在声明如何为特定实例变量构造getter和setter方法。之前它需要定义实例变量,因此您声明了它。它还允许属性名称通过@synthesize myProperty = myIVar;
与实例变量名称不同。现在你不需要这样做,因为现代编译器会为你生成实例变量。
点语法实际上是一个方便的事情,你会注意到。它不直接引用实例变量,而是引用方法myProperty
和setMyProperty:
。您甚至可以致电myArray.count
,其中count
不属于某个属性(即使很多人似乎都喜欢它,我也不会推荐它)。
虽然两者之间存在差异,但差距似乎正在缓慢缩小。
答案 2 :(得分:2)
这只是一个关于观点的问题。如果您直接访问ivar,那就是您在内部访问它。如果您正在使用属性,则不会访问ivar(语义上)。您正在使用对象的访问方法。因此,您将self
视为内部未知的外部对象。
这是面向对象范式的封装问题。
使用属性时我会推荐一些技巧。
@protected
或@private
以正确封装。 (至少没有合理的理由)nonatomic
。线程锁会大大降低性能,并可能导致并发执行代码中的奇怪行为。您可以使用此代码执行相同的操作。
@interface MyObject : NSObject
@property (assign,nonatomic) NSString * myString;
@end
@implementation MyObject
@synthesize myString;
@end
这将大致改变。
@interface MyObject : NSObject
{
@private
NSString* myString; // Ivar generated automatically by compiler
}
@end
@implementation MyObject
// Methods with thread synchronization locking generated automatically by compiler.
- (NSString*)myString { @synchronized(self) { return myString; } }
- (void)setMyString:(NSString*)newMyString { @synchronized(self){ myString = newMyString; } }
@end
事实上,我不确定使用assign
行为指令进行同步锁定,但总是更明确地将其设置为nonatomic
。编译器可以使用原子操作指令而不是锁定来优化它。
答案 3 :(得分:1)
使用现代的Obj-C运行时,声明ivar比其他任何东西都更具形式。但是,要记住一些内存管理事项。
首先,对象类型的属性声明通常是retain
,或者对于字符串,它可能是copy
。在任何一种情况下,都会保留新对象。
给出以下代码:
NSString *string = [[NSString alloc] init];
myString_ = string;
self.myString = string; // If the property was retain or copy
第二项任务将泄漏;第一个不会。这是因为该属性将保留已保留计数为1的内容 - 现在为2.当您在dealloc
中释放该属性时,计数将变为1,而不是0,因此它不会释放。但是,使用第一个选项时,保留计数保持为1,因此dealloc
将其降至0。
在您的示例中,将该属性保留为assign
将使ivar声明成为正式。