If I've to reinitialize a NSArray with others values, is it right to do this?
NSArray *array = [[NSArray alloc] initWithObjects:obj1, obj2, nil];
// ...
// some code
// ...
array = [[NSArray alloc] initWithObjects:obj3, obj4, nil];
thanks
Yes this is absolutely right. The new object is completely different than the previous. The object pointer now points to a new object and the old one will be released, since you are using ARC.
It is not exactly the same as reinitializing because you throw away the object and getting a new, but NSArray is immutable so this is the only way to "reinitialize" it.
Your code does not re-initialze an NSArray. It just assigns a new object to the variable array. That's fine.
I thinks this code may help you. At least, I thing this may be a suitable solution, especially if you are using ARC:
NSObject *obj1 = [NSNull null];
NSObject *obj2 = [NSNull null];
NSMutableArray *arrayObj = [NSMutableArray arrayWithObjects:obj1, obj2, nil];
[arrayObj removeAllObjects];
arrayObj = [NSMutableArray arrayWithObjects:obj1, obj2, nil];
I hope it helps you :)
you can reinitialize NSArray with same name ,you will not get any error or warning but the latest objects gets replaced with previous objects.The previous objects overwrites. For this you have to use ARC otherwise memory problem will occurs.
Related
I have a very strange behaviour with NSArray.
Firstly, i parsed an XML file and return a valid NSArray with NSDictionary inside:
NSArray *arrayOfDict = [parser parseWithXMLFile:filename];
In debugger it's fully valid. Then, i want to proccess all dictionaries in this array:
NSMutableArray* arrayOfProducts = [[NSMutableArray alloc] init];
for (NSDictionary* dict in arrayOfDict) {
Product* product = [[Product alloc] initWithName:dict[#"name"]
type:dict[#"type"]
imageName:dict[#"image"]
description:dict[#"description"]];
[arrayOfProducts addObject:product];
[product release];
}
And in this loop is a problem: a dict variable has value nil. And i don't know what to do with this. In debugger i evaluate value of arrayOfDict[someIndex] and get a right value, but in the programm itself it doesn't work.
May be it's the problem with MRR, i don't feel myself confidenly while using MRR and there is a mistake of using it.
P.S. I know that using MRR is stupid today, but in this project i must use it.
I am a little confused while using NSDictionary. I have a array (nameArray), I add that array to a Dictionary (nameDict) and finally I add this dictionary to another dictionary (requestDict).
NSMutableArray *nameArray = [[NSMutableArray alloc] initWithObjects:#"abcd",#"lmnop",#"xyz",#"pqr", nil];
NSMutableDictionary *nameDict = [NSMutableDictionary alloc] initWithObjectsAndKeys:nameArray,#"name", nil];
NSDictionary *requestDict = [NSDictionary dictionaryWithDictionary:nameDict];
When I remove objects from nameDict , requestDict is not affected.
[nameDict removeAllObjects]
So far so good. But my query is when I remove objects from nameArray why responseDict is affected.
[nameArray removeAllObjects];
Why nameArray still has objects. Shouldn't it have been deallocated as soon as I remove objects from nameDict. Please help me understand if I am missing something here.
What happens if I set nameArray to nil in this case?
Both nameDict and requestDict have a reference to the single array pointed to by nameArray. Changes made to nameArray are seen by both dictionaries.
When you did [nameArray removeAllObjects] you see the change to the array in both dictionaries because both dictionaries are referencing the one copy of the mutable array.
If you set nameArray to nil, nothing happens. Both dictionaries still have a reference to the mutable array.
I am using NSComparator to sort objects in NSArray. When the code is not ARC enabled then comparator gives different results to when code is ARC enabled.
Following is my Code snippet:
- (NSArray *)sortedToolsInfoArrayWithKey {
NSArray *aReturnVal = nil;
NSArray *aToolsInfoArray = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"ToolsData" ofType:#"plist"]];
aReturnVal = [aToolsInfoArray sortedArrayUsingComparator:(NSComparator)^(NSDictionary *a, NSDictionary *b) {
[[a valueForKey:#"selectionCount"] compare:[b valueForKey:#"selectionCount"]];
}];
[aToolsInfoArray release];
return aReturnVal;
}
This same method is written in Non-ARC code where I need the same kind of sorted array, Note that, my requirement is I need to sort the same array picked from same pList file in two different files, one of the file is ARC enabled while other file isnt ARC enabled.
But when I am doing that, I am getting exactly opposite sorting order and when I disable the ARC , the problem is solved.
I am not being able to understand the logic behind different behaviour of NSComparator to sort arrays in ARC and non-ARC enabled files.
Thanks..
You don't return a value from your comparator block:
aReturnVal = [aToolsInfoArray sortedArrayUsingComparator:^(id a, id b) {
NSDictionary *adict = (NSDictionary *)a;
NSDictionary *bdict = (NSDictionary *)b;
return [[adict objectForKey:#"selectionCount"] compare:[bdict objectForKey:#"selectionCount"]];
}];
(plus use objectForKey rather than valueForKey, which is the KVC accessor).
EDIT Missed the block syntax you were using is incorrect too (thanks to #Ivan Genchev).
As a follow-on to the answer by "trojanfoe", you have the wrong syntax for the block. You need:
aReturnVal = [aToolsInfoArray sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *a, NSDictionary *b) {
return [[a valueForKey:#"selectionCount"] compare:[b valueForKey:#"selectionCount"]];
}];
Let Xcode's code completion fill all of that in for you. It avoids the kind of mistakes you have.
You can also use NSSortDescriptor to sort your array.
NSArray *testArray = #[#{#"selectionCount":#"3"},
#{#"selectionCount":#"1"},
#{#"selectionCount":#"7"},
#{#"selectionCount":#"2"}];
NSLog(#"testArray: %#", testArray);
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"selectionCount" ascending:YES];
NSArray *sortedTestArray = [testArray sortedArrayUsingDescriptors:#[sortDescriptor]];
NSLog(#"sortedTestArray: %#", sortedTestArray);
I see a new kind of alloc&init NSMutableArray way in one project. It's like this A
NSMutableArray *array = [#[] mutableCopy]; and this works well, and i want to try whether its possible to use BNSMutableArray *array = [NSMutableArray mutableCopy]; it build succeeded, but got this error when used: +[NSMutableArray addObject:]: unrecognized selector sent to class 0x38bedc2c
Now i want to know how does A work? and why B is wrong? A is better than normal alloc&init?
Any help will be appreciated.
mutableCopy is an instance method declared in NSObject class. It is called on any instance to create a mutable copy of it.
In first case #[] will create an autoreleased NSArray instance on which calling mutableCopy will create NSMutableArray instance.
In second case calling mutableCopy on the class is incorrect because it is not meant to be called that way. This will get compiled but will cause exception at runtime.
Hope that helps!
In the first case, you're first initializing an empty NSArray instance; think of #[] as equivalent to [[NSArray alloc] init]. Therefore you're sending mutableCopy to a correct instance, so it works fine.
In the second case, you're sending the message to a class (as opposed to an instance of it), which doesn't make much sense, because the addObject message can only be sent to an instance, not the class itself.
#[] means an NSArray with no object. It returns an NSArray, and then its mutableCopy is copied to array.
+[NSMutableArray addObject:] is invalid as addObject is an instance method and you are trying to use it as class method.
Even NSMutableArray *array = [NSMutableArray mutableCopy]; is incorrect!!! As nothing is created, it is not been allocated and inited. If you log the array, it will only print the string NSMutableArray. Also you can't use array to addObject and other operations.
You should use NSMutableArray *array = [NSMutableArray array];
The first one is lazy typing.
You should avoid it.
It creates an empty NSArray from the array literal syntax and the creates a mutable copy.
That's saving a little typing by creating an unnecessary array.
You should just use
[NSMutableArray new]
Or
[[NSMutableArray alloc] init]
Or if possible because you know the initial capacity in advance
[[NSMutableArray alloc] initWithCapacity:someNSUIntegerValue]
Anything else above is laziness.
Only use mutableCopy when you are actually copying some content.
arrayOfElements = [NSMutableArray arrayWithArray:[someObj getArray]];
and
arrayOfElements = [[NSMutableArray alloc] init];
arrayOfElements = [someObj getArray];
What's the difference?
The first arrayOfElements does not seem to lose its objects when it returns count in numberOfRowsInSection:(NSInteger)section, but the second one does. I get EXC_BAD_ACCESS when I do it the second way.
EDIT:
Can I suppose now that this is the best way,
arrayOfElements = [[NSMutableArray alloc] initWithArray:[someObj getArray]];
because I am initializing an array with the contents of whatever will be autorelease'd, and I now have a fully independent array in the current class, that is viewDidLoad, oops sorry, ViewController.
This line creates an NSMutableArray from an existing array
arrayOfElements = [NSMutableArray arrayWithArray:[someObj getArray]];
This combination first creates an NSMutableArray and then instantly discards it replacing it with what is returned by [someObj getArray]
arrayOfElements = [[NSMutableArray alloc] init]; // Create new NSMutableArray
arrayOfElements = [someObj getArray]; // Throw away the newly created array and replace with the result of [someObj getArray]
If you are not using ARC then it is purely by luck that either would work.
In both cases arrayOfElements is being assigned an autorelease'd object - which will be cleared soon (most likely the next runloop). It is only by chance that nothing else has been written over this point of memory which allows one of your implementations to still work.
If you are not using ARC then really you should update your project to be using it will handle a lot of cases like this for you.
You should definitely be using properties (not bare ivars) as this will help reduce memory issues (for non-ARC) and give a more consistent interface to your code.
In your header (or class extension) declare the property like this
#property (nonatomic, strong) NSMutableArray *arrayOfElements;
Now for ARC you can simple do
[self setArrayOfElements:[[someObj getArray] mutableCopy];
for non-ARC you can do
NSMutableArray *array = [[someObj getArray] mutableCopy];
[self setArrayOfElements:array];
[array release]; array = nil;
Also note that getArray is a bad method name.
The use of “get” is unnecessary, unless one or more values are returned indirectly.
Coding Guidelines
When you are adding objects to mutable array from another array, try this:
[arrayOfElements addObjectsFromArray: [someObj getArray]];
If you're not using ARC, you need to make sure its retained.
if (arrayOfElements) {
[arrayOfElements release];
}
arrayOfElements = [[NSMutableArray alloc] initWithArray:[someObj getArray]];