I have a class, say the class Person. In than class I have several NSMutableArrays.
#property NSMutableArray *arrayOne;
#property NSMutableArray *arrayTwo;
...
Now I want to copy that Class so I can return it from a function and use the copy and change it's data. I want to have a new copy of the object in memory not another reference to the same address.
To do that I have implemented this in my Person.m:
-(id)copyWithZone:(NSZone *)zone
{
Person *copy = [[Person allocWithZone:zone] init;
copy.arrayOne = [NSMutableArray arrayWithArray:self.arrayOne];
copy.arrayTwo = [NSMutableArray arrayWithArray:self.arrayTwo];
...
return copy;
}
So far this works just like I want it to, but when I try to sort the arrays of the copy, I get an error:
-[__NSArrayI sortUsingSelector:]: unrecognized selector sent to instance 0x100108a30
I have noticed that the original arrays are of the type '_NSArrayM' but the copy is '_NSArrayI'...
So what did I wrong? I have heard of deep copying using NSArchiver and NSUnarchiver... Do I have to use that? Sorry, I am quite new to C and Objective-C... :D
I hope you can help me out of this. =)
Sorry about my 'school-english'....
Cheers,
Nick
EDIT: The arrays consist of NSString objects, so I can use
sortUsingSelector:#selector(caseInsensitiveCompare:)
to sort the array.
How are your mutable array properties being declared in your header file?
// Wrong
#property (copy) NSMutableArray *array;
#property (assign) NSMutableArray *array;
// Right
#property (strong) NSMutableArray *array;
NB If you're just doing
#property NSMutableArray *array;
then I'm amazed your code has got this far :) The default property memory semantics is assign - which won't tell ARC to retain your arrays in any way at all :) You need to specify strong.
Related
In Objective-C, it's common to declare NSString/NSArray/NSDictionary as copy, is it necessary to do that for a readonly property or there is no difference? If an NSString is readonly, it will never be set, so declaring it strong or copy will have the same effect right?
//use strong rather copy here and it will work the same since it will
never be copied?
#property (nonatomic, readonly) NSString *string;
If it really is read-only then you don't need to specify it. If you're going to redeclare it privately to be readwrite then you do want to specify it. For readonly properties it has no effect as no setter will be created.
You're right, but there're some things to consider. That's okay as long, as your property is immutable object. However, it is not always true.
First example, which I run into frequently, is when you have actually mutable object inside of your implementation. Like property declared NSArray in implementation can actually be NSMutableArray. Strong reference property getter for it will return pointer to that NSMutableArray. And, at some point, you'll run into situation when you request NSArray from object, work with it some time and than - boom!!! - your NSArray have different elements of number of it? What the hell? In that case, it's better idea to copy your inner implementation used NSMutableArray in getter.
Another example is some model object
#interface Person : NSObject <NSCopying>
#property NSString *name;
#property NSDate *birthdate;
#end
And you have some other interface with property
#property (strong, readonly) Person *person;
Yeah, you will not assign different object to this property. However, you'll be able to modify its fields, so it will represent some completely different Person. If you don't want such behaviour - make it copy property. Or make it private with access methods to get its fields
- (id) getHiddenPersonPropertyValueForKey:(NSString *)personPropertyKey;
Or any other way
If property represents really immutable value (NSArray, NSIndexSet, etc), then just readonly is fine, as it will be returned immutable as-is.
But in case of your private ivar being mutable (NSMutableArray ivar vs property's NSArray type), you should return a copy to prevent leaks of future internal changes into caller's state.
#interface MyObject : NSObject {
NSMutableArray *_array;
}
#property(nonatomic, readonly) NSArray *array;
// -or-
- (NSArray *)array;
#end
and
#implementation
#dynamic array; // only if #property was declared in interface
- (NSArray *)array
{
return [_array copy];
}
#end
The caller is safe then to store property's value and expect that it will not change even without making explicit copy itself:
self.array = [myObject array]; // e.g. 1 element
[myObject addElementToArray:#(42)];
NSLog(#"%#", self.array); // still 1 element
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;
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.
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.
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
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
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
...
Suppose I have
#interface A : NSObject
#property (nonatomic, strong) NSMutableArray *array;
#end
Later on in another class B, I want to access that array, to check how many items are in it. I can do one of two things in B (a is an instance of A):
Option 1
[a.array count]
Option 2
[[a array] count];
Which option is the best way to do this? Is option 2 the right way to access the array when using [a array] as the getter method?
both are the same if you have synthesized the array. in first one you just call the property and in 2nd one you are calling the getter method which was generated by #synthesize action.
and sure the 2nd option is the right way as #synthesize makes two methods
1- getter that is same as the property name
2- setter that is add set with property name at start with first letter captial like setArray.
There is no difference between the two if you have synthesized the array, as The Saad said. However, I recommend bracket syntax as to remain consistent in all your method calling as all other Objective-C methods (aside from functions from C) use bracket syntax to be called.
There's no difference until you decide to rename the generated getter/setter methods and the message is likely to become invalid.
For the public instance variables you can skip the accessor methods (both property and method styles) and use the structure dereference operator:
#interface A : NSObject
{
NSMutableArray *array;
}
#property (nonatomic, strong) NSMutableArray *array;
#end
classA.m
[self->array count];
classB.m
[a->array count];
Doing this, you waive the convenience of both operation and memory management optimizations which you have using properties (in both access styles) with the different attributes, see more.
As example for the NSString property
#property (readwrite, copy) NSString *sVar;
the generated setter looks like this:
-(void)setSVar:(NSString*)inSVar
{
if (self->sVar != inSVar)
{
[self->sVar release];
self->sVar = [inSVar copy];
}
}
This is for an app that allows users to tag things. Tags are just strings.
An array of TagHolder objects holds a list of all tags in use in the app, with a boolean telling if the tag is selected, but this is an implementation detail.
The external interface calls for two methods, selectedTags, and setSelectedTags: which return and accept an arrays of strings.
I would like these two methods to work as accessors for a declared property selectedTags.
Now, my question is:
What would be the correct memory management semantics to declare for that property?
The code pattern that I have in mind is this (code not tested, so please bear with typos):
#interface TagInfo : NSObject
#property (strong, nonatomic) NSString *tag;
#property (nonatomic) BOOL selected;
#end
#interface SomeClass : NSObject
#property (memorytype, nonatomic) NSArray *selectedTags;
#end
#implementation TagHolder
- (NSArray *)selectedTags
{
// tagInfoArray is an array of all TagInfo objects
NSPredicate *selPred = [NSPredicate predicateWithFormat: #"selected == YES"];
NSArray *selectedTagInfoObjects = [[self tagInfoArray] filteredArrayUsingPredicate: selPred];
NSArray *selectedTags = [selectedTagInfoObjects valueForKey: #"tag"];
return selectedTags;
}
- (void)setSelectedTags: (NSArray *)selectedTags
{
for (TagInfo *tagInfo in [self tagInfoArray]) {
tagInfo.selected = [selectedTags containsObject: tagInfo.tag];
}
}
#end
What should memorytype be? Obviously not strong or weak, but I think it could be any one of assign, copy or even unsafe_unretained, but which one is the most correct for a computed property with an object value?
I normally use ARC, but I guess the question is the same in an environment with manual retain count.
memorytype is significant only when you #synthesize your property accessors. Since you are providing your own implementation for both the getter and the setter, the things you put in parentheses after #property are ignored; I usually put readonly or readwrite there, just to remind myself of what kind of access is available on these properties.
Your code is correct, it will work without creating memory issues with or without ARC.
I have the following controller class which will do different tasks based on combination of the flag and param property. The value of these two properties will be set by many other classes having a reference to this controller. The question is how does each of the calling class assign value and when should they release it so that there will be no memory leak ?
#interface SampleController {
NSMutableArray *param;
NSString *flag;
}
#property (nonatomic, retain) NSMutableArray *param;
#property (nonatomic, retain) NSString *flag;
#end
#implementation SampleController
#synthesize param;
#synthesize flag;
- (id)init
{
param = [[NSMutableArray alloc] initWithCapacity:0];
flag = #"nothing";
}
#end
Well it depends on how you call your controller :
in an instance variable of an other object : you have to release it in this object's deallocate methode
in a function : you should release it when you do not need it anymore (retained by another object for example or it finished the job in this function), if you want to return it, just sent the message "autorelease" to it and the NSAutoReleasePool will do the job for you.
To assign value, you can
set the mutable array with the setParam:(*NSMutableArray)theArrayYouWantToReplaceYourArrayWith
access it directly with [[yourSampleController param]addObject:(id)objectYouWantToAdd]...
or more convenient : [yourSampleController.param addObject:(id)objectYouWantToAdd]
The addObject: message here is an example, you can see the methods for modifying an array (remove, sort,...) in the NSMutableArray class reference.
You will not be able to modify your string since it is a NSString and not a NSMutableString, but you can accessit by
[yourSampleController getParam]
[yourSampleController param]
yourSampleController.param
If you want to avoid leaks in general, build your project with the Instrument tool in leak mode and look at the objects that are leaked if you found some that are declared in your functions.
You can also check the Clang Static Analyzer (free static debugger) which is quite good if you have a lot of files.
I hope i helped you
Julien