12

I have an Obj-C 2.0 class that has an NSMutableArray property. If I use the following code, then the synthesised setter will give me an immutable copy, not a mutable one:

@property (readwrite, copy) NSMutableArray *myArray;

Is there any reason that Apple didn't implement the following syntax?

@property (readwrite, mutablecopy) NSMutableArray *myArray;

Since we don't have mutablecopy, what's the best way to handle this (seemingly common) situation? Should I just write my own setter that does a -mutableCopy?

Nick Forge
  • 21,344
  • 7
  • 55
  • 78

6 Answers6

14

I ran into the same problem some time ago and found a document on the Apple Developer Connection recommending to provide your own implementation of the setter. Code sample form the linked document:

@interface MyClass : NSObject {
    NSMutableArray *myArray;
}
@property (nonatomic, copy) NSMutableArray *myArray;
@end

@implementation MyClass

@synthesize myArray;

- (void)setMyArray:(NSMutableArray *)newArray {
    if (myArray != newArray) {
        [myArray release];
        myArray = [newArray mutableCopy];
    }
}
Markus Müller-Simhofer
  • 3,391
  • 1
  • 28
  • 32
5

It's not common to pass around NSMutableArrays in Cocoa. Standard Cocoa practice would be to implement the key-value coding compliant methods for an indexed to-many property. This has two benefits:

  1. Key-value observing works as expected (there are several cases where observing an NSMutableArray leads to not-what-you-want behavior)
  2. The implementation of your data structure is hidden because you expose mutating methods (e.g. -[MyObject insertObjectInMyProperty:(id)newObject atIndex:(NSUInteger)i] , not the data structure itself.
Barry Wark
  • 107,306
  • 24
  • 181
  • 206
4

As said before, the right way to do it is not to make the mutable array a property. There's a great explanation of what you should implement to be KVC compliant here.

wbyoung
  • 22,383
  • 2
  • 34
  • 40
  • In this answer http://stackoverflow.com/a/14814973/104790 I present a solution that exposes mutable collections without breaking encapsulation. The answer is not suited for this question here because it's for `readonly` properties only. – Nikolai Ruhe Feb 11 '13 at 16:18
  • Here is a working link to Nikolai's answer: http://stackoverflow.com/a/14814973/1687195 – user1687195 Dec 29 '15 at 19:28
3

Keep in mind that passing around a mutable array isn't really a common practice in Cocoa. You might use a private mutable array as internal storage, but create methods using plain NSArray objects to add or get objects out of it. This may be why there's no mutablecopy property declaration.

Marc Charbonneau
  • 40,399
  • 3
  • 75
  • 82
1

You'll have to write your own setter.

Becca Royal-Gordon
  • 17,541
  • 7
  • 56
  • 91
0

The right way to hold on to a NSMutableArray is with a retain property:

@property (nonatomic, retain) NSMutableArray *myArray;

You do not need to write your own setter or use copy. The copy property should be used with a NSArray that actually does need to be copied when the property is captured into another object. For example, if you assign a NSMutableArray object to a property that is of type NSArray with the copy property, then you do want to make a copy of the mutable array to "capture" it as an immutable property from that point forward.

And Marc has the right approach, one would not normally make NSMutableArray a part of the public API of your objects. If you do have a public property, it can be a NSArray with the copy property.

MoDJ
  • 4,309
  • 2
  • 30
  • 65