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


82

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

我对此不太确定。我认为“属性”是具有访问器方法的实例变量,但我可能会认为错误。

Answers:


84

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

@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

(注意:上面的代码有很多错误,因为它假定名称已经存在并且至少有两个组成部分(例如,“比尔·盖茨”,而不只是“门”)。不太清楚,所以我只是在这里指出,所以没有人会无辜地重复这些错误。)


4
我一直在查看属性的方式是一种提供/限制对外部对象的实例变量的访问的方法。有点像其他语言中的公共/私人概念吗?
典型的

“通常,其他对象永远都不应该直接访问它们”这是什么意思?您的答案还会更新为最新的Objective-C吗?
亲爱的

1
@Honey我认为他指的是封装的概念并遵循最佳实践。其他对象不应直接访问或修改ivar。通过通过属性控制ivar访问,我们可以在潜在影响ivar之前拦截这些调用。有关更多信息,请参见此处:en.wikipedia.org/wiki/Encapsulation_
computer_programming

33

属性是实现一些值的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行定义了一个名为propertyNametype的属性NSString *。可以使用以下语法获取/设置:

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

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

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

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

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

有3个属性值可控制任何@synthesized设置程序的内存管理。第一个是retain自动发送release到属性的旧值以及retain新值的。这非常有用。

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

第三个是assign在不调用旧对象或新对象的情况下直接分配指针的方法。

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


1
声明实例变量和属性(例如propertyName)有什么好处?如果为同一变量声明属性,则不需要在接口内进行声明,对吗?这确实节省了行代码,除非有我丢失的东西..
whyoz

6

我在接口部分使用属性-对象与其他对象的接口以及实例变量是类内部所需的东西-除了您应该看到并操纵这些对象之外,没有其他人可以使用。


3

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

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

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


2

以前,人们公开使用属性,而ivars供私人使用,但是自几年前以来,您还可以在@implementation其中定义属性以私下使用它们。但是我仍会尽可能使用ivars,因为键入的字母更少,并且根据本文,它的运行速度更快。这是有道理的,因为属性是“繁重的”:应该从生成的getter / setter或手动编写的getter / setter中访问它们。

但是,在Apple最近的代码中,不再使用ivars。我猜是因为它更像objc而不是C/C++,再加上它更容易使用与性能assignnullable等等。


我的猜测是,Apples中对属性的使用@implementation希望与Swift表现出相似之处。我仍然更喜欢支持变量而不浪费虚函数调用,以查找我自己类的简单字段(这种情况在访问属性时发生)。
狮子座
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.