开发者

Appropriate way to set property for NSMutableArray

开发者 https://www.devze.com 2023-02-20 13:33 出处:网络
I want a mutable array and set it by a property,which alternate is preferable and please explainthe reason. I have the 2 alternatives

I want a mutable array and set it by a property, which alternate is preferable and please explain the reason. I have the 2 alternatives

 NSMutab开发者_Go百科leArray *arrSubTitles_temp = [[NSMutableArray alloc] initWithObjects:    
 @"String 1",
 @"String 2",nil];
 self.arrSubTitles = arrSubTitles_temp;
 [arrSubTitles_temp release];

OR

 NSArray *arrSubTitles_temp = [[NSArray alloc] initWithObjects:    
 @"String 1",
 @"String 2",nil];
 self.arrSubTitles = [arrSubTitles_temp mutableCopy];
 [arrSubTitles_temp release];

I guess the 1st one is better, as self.arrSubTitles property is retained in .h, so (in 2nd) mutableCopy method will provide the mutable array, but also the retain count will be 2 in this case.

Which method is preferable, should I use retain in .h while setting the property or just assign. Please suggest.

Many thanks in advance :)


  1. Use retain as your property attribute, unless you have a good reason not to (ex: retain would cause a retain cycle, it's a primitive, you need to guarantee the object is immutable, etc)
  2. Use the first example you posted, since the second one would leak memory.

If you use assign as your property attribute, then the first option would probably crash:

  1. Allocate an array (owned by you)
  2. Assigned to a property (still owned by you)
  3. Release (no owners, promptly deallocated)
  4. Attempt to access property value: crash (because the pointer is stale)

The second one, however, would work:

  1. Allocate an array (+1 owners)
  2. Copy the array (original: +1 owners, copy: +1 owners)
  3. Assign the copy into the property (both still have +1 owners)
  4. Release the original array (it gets deallocated, the copy continues to exist)

Regardless, it is rather unconventional to have an assign property and then manage the retention of the value yourself. It is extremely error-prone, and much simpler to declare the property as retain and let the generated setter take care of the release/retain dance for you.


Either way is problematic because the caller must provide a mutable array. If the caller ever passes an immutable array (as anything that uses KVC to set the property would be able to do without a compiler warning), you will find yourself holding an immutable array in a mutable-array property, and will shortly thereafter try to mutate it, causing an exception.

What I do is hold a mutable array, which I create in init and release in dealloc, as the value of the property, declare the property as @property(nonatomic, copy) NSArray *myArray, and implement setMyArray: to send a setArray: message to my mutable array. At no point do I ever switch out the array; I exclusively and privately own the same mutable array for the entire lifetime of my object.

An equivalent implementation of setMyArray: would release the array and set the myArray variable to a mutableCopy of the input array. The only difference is that this would create and throw away more arrays over the duration of the process.

With either of these solutions, the caller does not need to worry about whether it passes a mutable or immutable array; the property will always do the right thing. And the caller would, as usual, not need to retain it on my behalf.

Note that a setter implementation generated by @synthesize will not do the right thing. It sends copy to the input array, which will return an immutable copy. This would be even worse, as then it would not work even if the caller does pass in a mutable array. You must implement a custom setMyArray: accessor to correctly handle both immutable and mutable arrays.


What about the setting it as autorelease NSMutableArray *arrSubTitles_temp = [[[NSMutableArray alloc] initWithObjects:
@"String 1", @"String 2",nil] autorelease]; self.arrSubTitles = arrSubTitles_temp; [arrSubTitles_temp release];

0

精彩评论

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