Reputation: 1045
I am studying Objective-C. I asked a question about this code earlier but I came up with further questions. The below code is trying to make NSArray
externally but really makes NSMutableArray
internally so I can add pointers or remove in NSMutableArray
I face two questions.
1) What is the purpose of doing like this? Is there a specific reason you make NSArray
externally? Why can't I just declare a property of NSMutableArray
?
2)I learn that instance variable (_assets
) is made when I declare a property of NSArray *assets
. And I also declared NSMutableArray *_assets
under the interface. I think those two _assets
conflict each other even though they have different types. Am I thinking this in a wrong way?
@interface BNREmployee : BNRPerson
{
NSMutableArray *_assets;
}
@property (nonatomic) unsigned int employeeID;
@property (nonatomic) unsigned int officeAlarmCode;
@property (nonatomic) NSDate *hireDate;
@property (nonatomic, copy) NSArray *assets;
Upvotes: 1
Views: 101
Reputation: 9965
Another approach might be to make the property only writable to the implementation of you class.
To do that you declare your property as readonly
in the header:
//BNREmployee.h
@property (nonatomic, readonly) NSMutableArray *assets;
Than declare it as readwrite
inside an inner interface in your implementation:
//BNREmployee.m
@interface BNREmployee()
@property (nonatomic, readwrite) NSMutableArray *assets;
@end
@implementation
...
Upvotes: 0
Reputation: 1491
The reason you'd internally keep an NSMutableArray
, but expose an NSArray
externally is so that users of your API won't abuse it and mutate its data. Keeping it visible as immutable makes people less prone to mess with it.
Another approach you could take to this is to not use a property at all, but simply have a getter and a mutable property in a class extension. For example, in your .h:
@interface BNREmployee : BNRPerson
- (NSArray *)assets;
@end
In your .m
@interface BNREmployee ()
// Inside of the class manipulate this property
@property (nonatomic, strong) NSMutableArray *mutableAssets;
@end
@implementation BNREmployee
// Clients of your class rely on this
- (NSArray *)assets
{
// copy makes the result immutable
return [self.mutableAssets copy];
}
@end
Upvotes: 0
Reputation: 19884
Here's something you can do if you want _assets
to be a mutable array, but you don't want other classes to modify it, implement the setter and getter of the assets property so they look like this (implementing the getter and the setter will cause the property to not be synthesised, which means the NSArray *_assets
will not be created automatically):
-(NSArray *)assets{
return [_assets copy]; // Copy creates an immutable copy
}
-(void)setAssets:(NSArray *)assets{
_assets = [NSMutableArray arrayWithArray:assets];
}
Keep in mind that if you access the assets array a LOT, it might be slow since you're creating an immutable copy every time, so you can create an NSArray whenever your _assets
array is modified and return that in the -(NSArray *)assets
method
Upvotes: 1
Reputation: 2360
I'll try put your answers the way you have asked them. Let hope they clear your doubts. By now I guess you would be knowing that NSArray
once initialised with data you wont be able to add or delete the data inside it which is different from NSMutableArray
.
The benefit here no one else can change your externally visible data. Also when you try to sort or iterate the array you are sure that no other data would be removed or added. Also if you use NSMutableArray
for such cases the application would crash if you add data while you iterate the array.
Like @KirkSpaziani Explained
@synthesize assets = _assets;
would create an instance variable for your property. However you are actually supposed to use this _assets
only in getter and setter. Else places you should be using self.assets
.
You can also synthesize your other array NSMutableArray *_assets
as follows
@synthesize _assets = __assets;
Which would have double underscore, but frankly we shouldn't be using the underscore for a starting variable name. Plus would be great if you have different names altogether.
Also with advances in Objective C you dont require to synthesize these variables at all. Just use the self.variableName
and you can access it.
Hope it clears some of your queries.
Upvotes: 1
Reputation: 1972
Put { NSMutableArray *_assets; } in the @implementation block
@implementation {
NSMutableArray *_assets;
}
Putting the NSMutableArray in the implementation block hides the fact that it is mutable from consumers (it is no longer in the header file).
Follow it with:
@synthesize assets = _assets;
This might not be necessary actually, but makes things clearer. When you declare a property an ivar will be automatically created (unless you @dynamic the property). However an explicitly declared ivar of the same name will override the automatically created one - so long as the type is the same or a subclass.
The reason to make it an NSArray publicly visible is so that no one else can mutate your data structure. You will have control of it. If it is an NSMutableArray internally then you can add and remove items without exposing that functionality to consumers.
You can declare your property to be readonly or readwrite - a readwrite NSArray means you can replace the whole array with a property set, but you can't add or remove items. If internally you are adding and removing items, this can make things messy. Try to stick with readonly when having a mutable internal version.
Upvotes: 1