Objective-c中的“实例变量”和“属性”之间有区别吗?

时间:2009-05-09 16:53:08

标签: objective-c

Objective-c中的“实例变量”和“属性”之间是否存在差异?

我对此并不十分肯定。我认为“属性”是一个具有存取方法的实例变量,但我可能认为错了。

6 个答案:

答案 0 :(得分:81)

属性是一个更抽象的概念。实例变量实际上只是一个存储槽,就像结构中的槽。通常,其他对象永远不应该直接访问它们。另一方面,属性是您可以访问的对象的属性(听起来很模糊,应该是这样)。通常,属性将返回或设置实例变量,但它可以使用多个数据或根本不使用数据。例如:

@interface Person : NSObject {
    NSString *name;
}

    @property(copy) NSString *name;
    @property(copy) NSString *firstName;
    @property(copy) NSString *lastName;
@end

@implementation Person
    @synthesize name;

    - (NSString *)firstName {
        [[name componentsSeparatedByString:@" "] objectAtIndex:0];
    }
    - (NSString *)lastName {
        [[name componentsSeparatedByString:@" "] lastObject];
    }
    - (NSString *)setFirstName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
    - (NSString *)setLastName:(NSString *)newName {
        NSArray *nameArray = [name componentsSeparatedByString:@" "];
        NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
        self.name = [newNameArray componentsJoinedByString:@" "];
    }
@end

(注意:上面的代码是错误的,因为它假定名称已经存在并且至少有两个组件(例如“比尔盖茨”而不仅仅是“盖茨”)。我觉得修复这些假设会使实际点代码不太清楚,所以我只是在这里指出,所以没有人无辜地重复那些错误。)

答案 1 :(得分:31)

属性是一种为某些值实现getter / setter的友好方式,具有其他有用的功能和语法。属性可以由实例变量支持,但您也可以定义getter / setter以执行更具动态性的操作,例如您可以在字符串上定义lowerCase属性,该属性动态创建结果而不是返回某个成员变量的值。

以下是一个例子:

// === In your .h ===

@interface MyObject {
    NSString *propertyName;

}

// ...

@property (nonatomic, retain) NSString *propertyName;

// === In your .m @implementation ===

@synthesize propertyName /* = otherVarName */;

@property行定义了propertyName类型NSString *的属性。可以使用以下语法来获取/设置:

myObject.propertyName = @"Hello World!";
NSLog("Value: %@", myObject.propertyName);

当您分配或读取myObject.propertyName时,您实际上是在对象上调用setter / getter方法。

@synthesize行告诉编译器为您生成这些getter / setter,使用具有相同属性名称的成员变量来存储值(如果使用语法,则为otherVarName注释)。

@synthesize一起,你仍然可以通过定义自己的getter / setter来覆盖其中一个。这些方法的命名约定对于setter而言是setPropertyName:,对于getter而言是propertyName(或getPropertyName,而不是标准)。另一个仍将为您生成。

@property行中,您可以在属性的parens中定义许多属性,这些属性可以自动执行线程安全和内存管理等操作。默认情况下,属性是原子的,这意味着编译器将使用适当的锁包装@synthesiz ed get / set调用以防止并发问题。您可以指定nonatomic属性来禁用此功能(例如,在iPhone上,您希望将大多数属性默认为nonatomic)。

有3个属性值可以控制任何@synthesized setter的内存管理。第一个是retain,它会自动将release发送到属性的旧值,并retain发送给新值。这非常有用。

第二个是copy,它将复制传入的任何值,而不是保留它们。优良作法是将copy用于NSString,因为调用者可以传入NSMutableString并将其从您的下方更改。 copy将创建只有您有权访问的输入的新副本。

第三个是assign,它在没有调用旧对象或新对象的保留/释放的情况下进行直指针分配。

最后,您还可以使用readonly属性禁用该属性的setter。

答案 2 :(得分:6)

我使用接口部分的属性 - 对象与其他对象接口 实例变量是你在课堂上需要的东西 - 除了你之外,没有人应该看到并操纵它们。

答案 3 :(得分:3)

默认情况下,readwrite属性将由实例变量支持,该实例变量将再次由编译器自动合成。

实例变量是一个存在的变量,它保存对象生命周期的值。用于实例变量的内存在首次创建对象时(通过alloc)分配,并在释放对象时释放。

除非另行指定,否则合成的实例变量与属性具有相同的名称,但带有下划线前缀。例如,对于名为firstName的属性,合成的实例变量将被称为_firstName。

答案 4 :(得分:1)

以前人们公开使用属性而ivars用于私人使用,但几年前,您还可以在@implementation中定义属性以私下使用它们。但是我仍然会尽可能使用ivars,因为输入的字母较少,而且根据this article它运行得更快。这是有道理的,因为属性意味着“沉重”:它们应该从生成的getter / setter或手动编写的那些访问。

然而,在Apple最近的代码中,不再使用ivars了。我想因为它更像objc而不是C/C++,而且使用assignnullable等属性更容易。

答案 5 :(得分:0)

Objective-C 属性与实例变量 (iVar)

[Swift variable, property...]

实例变量

Property

财产

Instance variable

property = variable + bounded getter/setter 在内部使用 @propertygetter。它是一个具有可变语法和访问权限的方法调用

  • setter 生成 backing ivar_<var_name> 方法(访问器方法),它们使用 _someVariable(又名支持字段),您可以通过下划线 method dispatch (KVO) 使用。

  • 由于它调用了一个方法 - 使用了 @synthesize 机制,这就是为什么可以应用 #import "SomeClass.h" @interface SomeClass() @property (nonatomic, strong) NSString *someVariable; @end @implementation SomeClass - (void) foo { //property getter method NSString *a1 = self.someVariable; //NSString *a1 = [self someVariable]; //property setter method self.someVariable = @"set someVariable"; //[self setSomeVariable:@"set someVariable"]; //iVar read NSString *a2 = _someVariable; //iVar write _someVariable = @"set iVar"; } //if you overriding someVariable getter and setter the iVar(_someVariable) is not generated, that is why you can: //1. create some variable explicitly NSString *_someVariable; //or //2. use @synthesize @synthesize someVariable = _someVariable; //overriding - (NSString*) someVariable { return _someVariable; } - (void)setSomeVariable: (NSString*) updatedSomeVariable { _someVariable = updatedSomeVariable; } @end [About]

  • 当您覆盖不生成支持 iVar 的访问器方法时,这就是为什么您可以显式声明一个新属性或使用 {{1}}[About] 生成一个新属性或与现有的链接

{{1}}

[property attributes]