I want to protect access to NSMutableArray in public interface
I am trying to do this by defining property as NSArray in public interface and as NSMutableArray in private interface like this:
@interface Order : NSObject
@property (readonly, strong, nonatomic) NSArray* comments;
@end
@interface Order()
@property (readwrite, strong, nonatomic) NSMutableArray* comments;
@end
But this doesn't work - so I have to define property in public interface NSMutableArray instead:
@interface Order
@property (strong, nonatomic) NSMutableArray* comments;
@end
The goal is to provide read-only access to comments for API clients and full access to methods like addObject:
in the implementation.
So defining goal more clearer:
So simply the question was if it's possible to make public definition of property more general (NSArray instead of NSMutableArray).
Is there any other clean way to reach the goal or I have to use NSMutableArray everywhere?
RESOLUTION
After reviewing my original question and answers I realized that I would like to use more generic class NSArray in the public interface and NSMutableArray in the implementation - but it's just not possible for one property. So the answer is not possible.
So I will just use single property with NSMutableArray without any extra desired protection.
But I will also pick the most appropriate answer it might help if you really prefer protection over simplicity and efficiency.
You don't need a public property if all you want is to allow clients to read the array.
Just create an accessor method that returns a copy of your private mutable array:
@interface Order : NSObject
- (NSArray *)allComments;
@end
@implementation Order ()
@property (nonatomic, strong) NSMutableArray * comments;
@end
@implementation Order
@synthesize comments;
- (NSArray *)allComments
{
return [[self comments] copy];
}
@end
This pattern can be seen in e.g., NSView
: constraints
and subviews
are internally mutable, but only exposed for reading via a single method returning a nonmutable array.
One solution would be to declare the property as readonly as an NSArray
. Then in your implementation, create a separate, writable property based on NSMutableArray
.
In the .h:
@interface Order : NSObject
@property (readonly, strong, nonatomic) NSArray* comments;
@end
In the .m:
@interface Order()
@property (strong, nonatomic) NSMutableArray* internalComments;
@end
Instead of synthesizing the readonly property, write:
- (NSArray *)comments {
return [self.internalComments copy];
}
In the .m you do everything with self.internalComments
.
A far cleaner solution, if it's acceptable for your use case, would be to declare the property as an NSArray
, while backing it with an NSMutableArray
. The client could technically modify the array by simply casting it to a mutable one, but you are making it clear that doing so would be a bad idea.
A @property
is simply a wrapper around two methods, a getter and a setter, which are typically backed by a storage variable. The simplest way to implement this solution would be:
@interface Order : NSObject
{
NSMutableArray *_comments;
}
@property (readonly, strong, nonatomic) NSArray *comments;
- (void)addComment:(Comment *)comment;
@end
@implementation Order
@synthesize comments=_comments; // Can be omitted if you use Xcode 4.4+
- (void)addComment:(Comment *)comment
{
[_comments addObject:comment];
}
@end
If you want the user to be able to replace the entire array (order.comments = ...
), remove the readonly
attribute on the property and override the -setComments:
method:
- (void)setComments:(NSArray *)array
{
[_comments release]; // Can be omitted if you are using ARC
_comments = [array mutableCopy];
}
It's worth noting that since Objective-C is a dynamic language, it's not possible to fully prevent someone from accessing a variable, as you can interface directly with the runtime or call methods by their selector if you really want to poke around in things you're not supposed to. All you can really do is make it clear that doing so is a bad idea.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With