如何写一个正确的readonly属性?

时间:2011-02-08 05:50:51

标签: iphone objective-c properties

我有两个关于如何在Objective-C 2.0 +中创建正确的只读属性的问题。

这是我原来的方法,我们称之为解决方案1 ​​

@interface ClassA{
 @private
  NSMutableArray *a_;
}

// NOTE: no retain
@property (nonatomic, readonly) NSMutableArray *a;

@end


///////////////////////////////////////
@implementation ClassA

@synthesize a = a_;

- (NSMutableArray *)a{
  if(nil == a_){
    a_ = [[NSMutableArray alloc] array];
  }
  // Potential leak warning on the following line.
  return a_;
}

- (void)dealloc{
  // I released the object here, I think this should be safe.
  [a_ release];
  [super dealloc];
@end

当我编译和分析它时,系统会发出如下警告:“'返回_'时可能发生泄漏。”

然后我再次阅读Objective-C的文档,并找到另一种方法如下。我们称之为解决方案2

@interface ClassB{
 @private
  NSMutableArray *a_;
}

// NOTE: make it retain+readonly
@property (nonatomic, readonly, retain) NSMutableArray *a;

@end


///////////////////////////////////////
// Add a private category
@interface ClassB ()

// reset the property to readwrite
@property (nonatomic, readwrite, retain) NSMutableArray *a;

@end

//////
@implementation ClassB

@synthesize a = a_;

- (id)init{
  if(self = [super init]){
    // NOTE: set the value as we use property normally.
    self.a = [NSMutableArray array];
  }
  return self;
}

- (void)dealloc{
  self.a = nil;
  [super dealloc];
@end

现在,我的问题是:

  • 是否可以使用解决方案1并摆脱“潜在泄漏”?
  • 解决方案2是否为常见解决方案?

谢谢你们!

- Tonny

3 个答案:

答案 0 :(得分:3)

根据要求,我正在复制我的评论作为答案:

[[NSMutableArray alloc] array]应该给你一个编译器警告,它肯定会崩溃。你想要[[NSMutableArray alloc] init]

答案 1 :(得分:2)

通常,如果您现在只读属性的值将提前,则最好在init方法中进行设置。

我不确定这是否会导致泄漏警告,但我会做类似的事情:

@interface ClassA{
 @private
  NSMutableArray a_;
}

// NOTE: no retain
@property (nonatomic, readonly) NSMutableArray a;

@end

@implementation ClassB

@synthesize a = a_;

- (id)init{
  if(self = [super init]){
    // NOTE: set the value as we use property normally.
    a_ = [[NSMutableArray alloc] init];
  }
  return self;
}

- (NSMutableArray *)a
{
 return a_;
}

- (void)dealloc{
    [a_ release];
    [super dealloc];
   }
@end

编辑:

修正了a_ assignment。

答案 2 :(得分:2)

老实说,我发现使用“私人”读写属性更容易,而不是对ivars大惊小怪:

MyClass.h

@interface MyClass : NSObject

@property (nonatomic, copy, readonly) NSArray * someArray;    // Public

@end

MyClass.m

@interface MyClass ()     // Class extension

@property (nonatomic, copy, readwrite) NSArray * someArray;   // "Private"

@end

@implementation MyClass

@synthesize someArray = someArray_;

- (id)init
{
    self = [super init];

    if (self != nil)
    {
        self.someArray = ...; // Array initialization
    }

    return self;
}

- (void)dealloc
{
    [someArray_ release];

    [super dealloc];
}

@end

不需要ivars!现代运行时将自动合成它们。您的属性是从外部(即其他类)只读,但在内部,您已将该属性重新声明为读写,因此您可以利用合成属性访问器的便利性。

(当然,我仍然声明明确的ivar合成 - 在此示例中为someArray_ - 用于-dealloc,因为有充分的理由不使用-dealloc中的属性并且可能在-init中。)