【问题标题】:Is there a difference between an "instance variable" and a "property" in Objective-c?Objective-c 中的“实例变量”和“属性”有区别吗?
【发布时间】:2010-10-25 00:35:31
【问题描述】:

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

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

【问题讨论】:

    标签: objective-c


    【解决方案1】:

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

    @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
    

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

    【讨论】:

    • 我一直在查看属性的方式是提供/限制对外部对象的实例变量的访问。有点像其他语言中的公共/私人概念?
    • “通常其他对象不应该直接访问它们”你是什么意思?你的答案也用现代的objective-c更新了吗?
    • @Honey 我认为他指的是封装的概念并遵循最佳实践。其他对象不应该能够直接访问或修改 ivar。通过通过属性控制 ivar 访问,我们可以在这些调用可能影响 ivar 之前拦截它们。请参阅此处了解更多信息:en.wikipedia.org/wiki/Encapsulation_(computer_programming)
    【解决方案2】:

    属性是为某个值实现 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 或从myObject.propertyName 读取时,您实际上是在调用对象的setter/getter 方法。

    @synthesize 行告诉编译器为您生成这些 getter/setter,使用与属性同名的成员变量来存储值(或 otherVarName,如果您使用 cmets 中的语法)。

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

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

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

    第二个是copy,它将复制传入的任何值,而不是保留它们。对 NSString 使用 copy 是一种很好的做法,因为调用者可以传入 NSMutableString 并将其从您的下方更改。 copy 将制作一个只有您可以访问的输入的新副本。

    第三个是assign,它直接分配指针而不对旧对象或新对象调用retain/release。

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

    【讨论】:

    • 声明实例变量和属性(例如propertyName)有什么好处吗?如果为同一个变量声明属性,则不需要接口内的声明,对吗?这确实节省了代码行,除非我缺少某些东西..
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

        • 我的猜测是,Apple 使用 @implementation 中的属性是想显示与 Swift 的相似之处。我仍然更喜欢支持变量而不是浪费虚拟函数调用,以便查找我自己的类的简单字段(访问属性时会发生这种情况)。
        【解决方案6】:

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

        [Swift variable, property...]

        实例变量

        @interface SomeClass: NSObject
        NSString *someVariable;
        @end
        

        房产

        @interface SomeClass: NSObject
        @property (nonatomic, strong) NSString *someVariable;
        @end
        

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

        • @property 生成 gettersetter methods(访问器方法),它们使用 backing ivar(又名支持字段),您可以通过下划线使用 _<var_name> (_someVariable) .

        • 因为它调用一个方法 - 使用了method dispatch 机制,这就是为什么可以应用KVO[About]

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

        #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
        

        [property attributes]

        【讨论】:

          猜你喜欢
          • 2012-02-02
          • 2010-12-05
          • 2010-10-23
          • 1970-01-01
          • 1970-01-01
          • 2011-05-07
          • 2020-05-09
          • 2013-05-19
          相关资源
          最近更新 更多