2011-06-23 27 views
4

在下面的共同的样品,Objective-C中,接口声明具有属性

//// 
@interface MyObject : NSObject 
{ 
@public 
    NSString * myString_; 
} 

@property (assign) NSString * myString; 
@end 

@implementation MyObject 
@synthesize myString = myString_; 
@end 
//// 

为什么声明在界面在所有myString_

我问,因为我们仍然可以获取和使用self.myString[self myString]self.myString = ...[self setMyString:...]实施设置myString。事实上,我们必须相反,如果它被保留。

回答

1

随着现代的Obj-C运行时间,声明伊娃比其他任何形式更具形式性。但是,有一些内存管理事项需要记住。

首先,对象类型的属性声明通常是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将使伊娃声明成为正式。

5

这是一些偏好/约定的问题。默认情况下,这样做的:

@property (assign) NSString * myString; 

...依次为:

@synthesize myString; 

...会给你三件事情。你会得到一个setter方法,它可以被访问为self.myString = @"newValue"[self setMyString:@"newValue"],一个可以作为NSString* temp = self.myStringNSString* temp = [self myString]访问的getter方法,以及一个名为myString的实例变量,它们可以直接在你的类的内部访问(即不经过getter和setter )并用于设置和获取属性值,并在内部用于支持该属性。

如果你喜欢,你可以做@synthesize myString = someOtherVarName,然后你还是像以前一样得到getter和setter方法,但不是在myString实例变量someOtherVarName实例变量是用来备份的财产,并没有创建myString变量。

那么为什么要使用更冗长的语法呢?从来没有任何情况要求您这样做,但有些人在处理声明为retaincopy的属性时更愿意这样做。原因是设置一个通过其生成的setter方法声明为retaincopy的属性将影响被设置/取消设置的对象的保留计数。通过直接访问实例变量来做同样的事情不会。

因此,通过将实例变量别名为别的,您可以在代码中沿着“xxx.myString = Y修改保留计数的任何内容进行区分,而someOtherVarName = Y的任何内容都不是”。再次,没有必要这样做,但有些人更喜欢。

+1

+1;我想补充一点,'@ synthesize'只会使用ivar,getter和setter完成这个类:如果你自己定义了它们,它们将优先于自动实现。 – zneak

2

你应该可以跳过它。现代编译器允许这样做。

当你定义一个属性时,你实际上是在声明如何为特定的实例变量构造getter和setter方法。之前它需要定义实例变量,以便您声明它。它还允许属性名称通过@synthesize myProperty = myIVar;与实例变量名称不同。现在你不需要这样做,因为现代编译器会为你生成实例变量。

点语法实际上是一个方便的东西,因为你会注意到。它不直接引用实例变量,而是直接引用方法myPropertysetMyProperty:。你甚至可以打电话myArray.count,其中count不是一个属性(我不会推荐它,即使很多人似乎喜欢它)。

虽然两者之间存在差异,但差距似乎在缓慢收尾。

2

这只是一个关于观点的问题。如果您直接访问伊娃,那么您就是在内部访问它。如果你使用财产,你没有访问伊娃(语义)。您正在使用对象的访问方法。所以你正在处理self就像内部未知的外部对象。

这是封装面向对象范例的问题。

我在使用属性时推荐一些技巧。

  1. ivar声明是可选的,不是必需的。编译器会自动生成它。
  2. 您应该将伊娃设置为@protected@private以正确地封装它。 (至少没有合理的理由)
  3. 如果您在访问属性时不需要线程锁定,我建议使用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明确。编译器可以使用原子操作指令而不是锁定来优化它。

以下是有关属性的参考文件:http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17