Objective-C,带属性的接口声明

时间:2011-06-23 01:39:10

标签: objective-c interface properties

在以下常见样本中,

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

@property (assign) NSString * myString;
@end

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

为什么要在界面中声明myString_

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

4 个答案:

答案 0 :(得分:5)

这是某些人的偏好/惯例问题。默认情况下,执行:

@property (assign) NSString * myString;

......接着是:

@synthesize myString;

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

如果您愿意,可以执行myString,然后您仍然可以像以前一样获得setter和getter,但不使用@synthesize myString = someOtherVarName实例变量,而是myString实例变量用于返回属性,并且没有创建someOtherVarName变量。

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

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

答案 1 :(得分:2)

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

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

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

虽然两者之间存在差异,但差距似乎正在缓慢缩小。

答案 2 :(得分:2)

这只是一个关于观点的问题。如果您直接访问ivar,那就是您在内部访问它。如果您正在使用属性,则不会访问ivar(语义上)。您正在使用对象的访问方法。因此,您将self视为内部未知的外部对象。

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

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

  1. ivar声明是可选的,不是必需的。编译器会自动生成它。
  2. 您应将ivar设置为@protected@private以正确封装。 (至少没有合理的理由)
  3. 如果您在访问该媒体资源时不需要线程锁,我建议您使用nonatomic。线程锁会大大降低性能,并可能导致并发执行代码中的奇怪行为。
  4. 您可以使用此代码执行相同的操作。

    @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

答案 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声明成为正式。