【问题标题】:How to write a correct readonly property?如何编写正确的只读属性?
【发布时间】:2011-06-23 05:39:26
【问题描述】:

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

这是我原来的方法,我们称之为solution 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

当我编译和分析它时,系统会报告如下警告:“'return a_' 处可能存在泄漏”。

然后我再次阅读了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 是常用解决方案吗?

谢谢你们!

-- 托尼

【问题讨论】:

  • [[NSMutableArray alloc] array] 应该给你一个编译器警告,它肯定会崩溃。你想要[[NSMutableArray alloc] init]
  • 你错过了*NSMutableArray a_;
  • @Simon,谢谢,我是手动输入的,没有用编译器编译。我已经修好了。
  • @Kevin Ballard,你是对的。这是我的愚蠢错误。将[[NSMutableArray alloc] array] 更改为[[NSMutableArray alloc] init] 后。一切顺利。 能否请您将其回复为答案,以便我将您的回复标记为正确答案并关闭此问题。
  • 我知道这是一篇旧帖子,但我只是注意到一个小错误(我最近才学到的东西)。在您的代码中,您有注释// Add a private category,而后面的内容实际上是类扩展,而不是类别。非常相似的符号,但有区别。使用类别您只能添加新方法,使用扩展您可以添加方法和属性。

标签: iphone objective-c properties


【解决方案1】:

一般如果你现在只读属性的值会提前,最好在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

已编辑:

修正了一个_分配。

【讨论】:

  • 谢谢 criscokid。我认为一般来说,您的解决方案比我的要好。是的,我应该将 ivar 初始化放在 -init 方法中。但是我仍然在线收到潜在的泄漏警告:a_=[[NSMutableArray alloc] array];。也许这是因为 clang 太笨了,无法识别这种模式,还是其他原因?
【解决方案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 中的属性。)

【讨论】:

  • 我觉得这和我的解决方案2一模一样
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 2010-12-14
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 2010-12-02
    • 1970-01-01
    • 1970-01-01
    • 2018-03-22
    • 1970-01-01
    相关资源
    最近更新 更多