开发者

How to write a correct readonly property?

I have 2 questions about how to make a correct readonly property in Objective-C 2.0+.

Here is my or开发者_运维技巧iginal approach, let's call it 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

When I compile and analyze it, the system report a warning like this: "a potential leak at 'return a_'".

Then I read the document of Objective-C again and find another approach as below. Let's call it solution 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

Now, here are my questions:

  • Is it possible to use solution 1 and get rid of 'potential leak'?
  • Does solution 2 the common solution?

Thank you guys!

-- Tonny


As requested, I'm reproducing my comment as an answer:

[[NSMutableArray alloc] array] should give you a compiler warning, and it will definitely crash. You want [[NSMutableArray alloc] init].


Honestly, I find it easier to just use "private" read-write properties and not fuss with the ivars at all:

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

No ivars needed! The modern runtime will automatically synthesize them. Your property is read-only from the outside (i.e., other classes), but internally, you've redeclared the property as read-write, so you can leverage the convenience of synthesized property accessors.

(Of course, I still declare an explicit ivar synthesis—in this example, someArray_— for use in -dealloc as there are good reasons not to use properties in -dealloc and possibly in -init.)


Generally if you now the value of a read only property will be ahead of time, it's good to set it up in the init method.

I'm not sure if this would cause a leak warning but I would do something like:

@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

EDITED:

Fixed a_ assignment.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜