NSArray unwanted deallocation - objective-c

I am new to collection programming , so i faced this problem . Any help will be thanked ...
I Initialized a NSArray instance in a class initialize ( i already define that as a property of that class in header file so i a must can access it any where in that class implementation ) and assign some object to it with
+(NSArray*) arrayWithObjects: ; . every thing in init method is fine but ,...
When i want to work with that array in update method app crashs , because that array DEALLOCATED .
Why that array became deallocated ? How can i prevent it ?
Thanks .

If you are not using ARC, then you should init it with initWithObjects, then retain it.
If you are using ARC, probably it's just a weak reference.Make it be a strong reference when you declare the property.

if you are initializing array like this,
objects = [NSArray arrayWithObjects: buttonOne, buttonTwo,
textField, nil];
its a conventional method, It just auto-release the object after one time the object access. Rather you can retain the object or you can allocate and initialize it like
objects = [NSArray alloc] initWithObjects: buttonOne, buttonTwo,
textField, nil];

You should alloc NSArray and use -initWithObjects method instead.
NSArray* tempArray = [[NSArray alloc] initWithObjects:(id), ..., nil]

Related

NSDictionary of uninitialized objects?

How can I store an uninitialized object in an NSDictionary?
I think I would do it like this, but I’m not certain that it’s a good approach:
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:
[MyObject1 alloc], #"myObject1",
[MyObject2 alloc], #"myObject2"
, nil];
MyObject1 *object = [dict objectForKey:#"myObject1"];
[object init];
Any help would be appreciated.
What you need is to store mutable objects inside the dictionary. Doing this you will be able to modify them after the insertion, because an immutable dictionary doesn't allow to insert a new object.
If for "uninitialized" you mean that the object has only been created with alloc, without init, that's deprecable because init may return a different object from the one returned with alloc. So just store them like you're doing it, and when you need to modify them call the accessors:
NSDictionary *dict = #{ #"myObject1" : [MyObject1 new] , #"myObject2" : [MyObject2 new] };
dict[#"myObject1"].someProperty= someValue;
If your MyObject1 class is immutable, then you have to use a mutable dictionary.

unable to store an image in an NSMutableArray

I am trying to save an image in an NSMutable array and it is not working
here is what I am doing
[imagesList addObject:[UIImage imageNamed:#"b.png"]];
after executing this line I noticed that the number of objects remains 0
any reason ?
Thanks
I repeate this code in several areas :
Globally I declare :
NSMutableArray *imagesList;
NSUserDefaults *imagesHistory;
in my viewdidload method I write:
imagesHistory=[NSUserDefaults standardUserDefaults]; //imagesHistory is created globallt as NSUserDefault imagesHistory
[imagesHistory setObject:imagesList forKey:#"images history"];
UIImage *image;
image=[UIImage imageNamed:#"b.png"];
[imagesList addObject:image];
imagesHistory=[NSUserDefaults standardUserDefaults];
[imagesHistory setObject:imagesList forKey:#"images history"];
and in the didFinishLaunchingWithOptions I write : (even though I don t need to do it when I am adding strings ...)
imagesList = [[NSMutableArray alloc] init];
Regardless of whether it is a global variable or not, you still need to call alloc and init SOMEWHERE for the object. If you intend to use it throughout your app, then appDidFinishLaunchingWithOptions is a decent place to add this call:
imagesList = [[NSMutableArray alloc] init];
Is your empty array being retained? If you're not using Automatic Reference Counting, there's a good chance you're initializing the array with the following
imagesList = [[NSMutableArray alloc] init];
but it's not being retained. You'll want to retain the empty array so it gets appended to further on in your code.
imagesList = [[[NSMutableArray alloc] init] retain];
Just don't forget to release the array when you're all done with it, in viewDidUnload or wherever is appropriate.
You're allocating/initing imagesList AFTER you try to add an object. You need to alloc/init imageList before you add anything to it.
To make sure it's there, try something like this:
if (!imagelist) imageList = [[NSMutableArray alloc] init];
If it exists, and you're still having this problem, it's possible that you're allocating/initing a new NSMutableArray and assigning it to imageList after you've added the object. This means the old array would be discarded and you'd be left with a new array with zero items.
try UIImageView *image;
image=[UIImage imageNamed:#"b.png"];
also, in #property(nonatomic,retain) use 'strong' instead of 'retain'

NSCFArray not acting as NSArray

I'm trying to save data to and XML file on Iphone. For that, I load the wholeXML, add new data and the save it again. The problem arises when i try to store the new data, my
[mArray addObject:newData];
methods crashes, as mArray is not a NSMutableArray, instead, it is a NSCFArray even if I applied a mutableCopy method to it.
As I understand, a NSCFArray is a toll-free bridging to an NSArray, so I can't understand why the mutablyCopy method is not working.
Any idea??
NSMutableDictionary *wholeXML = [[NSMutableDictionary alloc] init];
wholeXML = xmlData;
NSArray *array = [[NSArray alloc] init];
NSMutableArray *mArray = [[NSMutableArray alloc] init];
array = [wholeXML objectForKey:#"Key"];
mArray = [a mutableCopy];
NSCFArray is a private subclass that gets instantiated when you do things with NSArray factory methods or initializers. You're doing too many initializations. Try this simplified version:
NSMutableDictionary *wholeXML = [[NSMutableDictionary alloc] initWithDictionary:xmlData];
NSMutableArray *mArray = [[NSMutableArray alloc] initWithArray:[wholeXML valueForKey:#"Key"]];
NSCFArray is the concrete class for both NSMutableArray and NSArray. It sounds like you are simply mistaken about what kind of array you have. Since the code you posted is obviously not your real code (it won't even compile, and wouldn't exhibit the problem even if it did), it's impossible to tell at what point your program is assigning an immutable array to the variable. But that's what it sounds like is happening.
I will say (and please don't take this as a personal criticism — it's just an observation) that the code you posted suggests you don't have a strong grasp on how classes and object identity work. That's probably the root cause here.
All three of your variables you initialize with [[Something alloc] init], but then you immediately throw away the object and replace it with something else. This means the original object (NSMutableArray in this case) just gets leaked and the variable now contains the new object you have assigned. If that new object isn't an NSMutableArray, it won't magically be turned into one just because that's what the variable held before.

Why Do I Have to Create An Object and Assign It to A Property in Objective C?

So I had this code, and it did not work:
for (NSDictionary *item in data){
[self.resultsArray addObject:item];
}
self.resultsArray is nil. But then I changed it to this:
NSMutableArray *myDataArray = [[NSMutableArray alloc] init];
for (NSDictionary *item in data){
[myDataArray addObject:item];
}
self.resultsArray = myDataArray;
[myDataArray release];
and now it worked. self.resultsArray is now populated
So I'm a beginner in Objective C and I was wondering why can I not just directly use it in the property's addObject. Why did I have to create another mutable array, populate it, assign it to the resultsArray property and release the mutable array I made?
Thanks in advance!
EDIT: Also, in a lot of books I've been working on, this is done a lot.
simple answer
You didn't initialize self.resultArray before adding objects to it. It is just a pointer to the value which is nil until you alloc it.
self.resultArray = [[NSMutableArray alloc] init]; before adding objects to it will solve the issue.
However, this way of alloc'ing will create a memory leak, therefore it is not shown in books and examples. Memory leak can happen if the self.resultArray property is marked as retain and by calling alloc it will be retained 2 times.
If self.resultsArray is nil, then [self.resultsArray addObject:item] will NOT add an object to the array, it will just do nothing (because the array will be nil by default, and sending messages to nil is a no-op in Objective-C). When you create a mutable array as a local variable, you can add things to it — then if you assign it to the property, well, everything works as you expect and self.resultsArray will no longer be nil.
Typically when you have properties like this, you'd set them up in your init method:
- (id)init {
// ...
self.resultsArray = [NSMutableArray array];
// or access the ivar directly:
// _resultsArray = [[NSMutableArray alloc] init];
// ...
}
Then as soon as your object is initialized you'll be able to add things to the array. Again, if you don't do this, it will be nil by default, and [self.resultsArray addObject:item] will have no effect.
Chances are you are not initializing the array (I'm going to assume myDataArray is an NSMutableArray).
In your init method, call myDataArray = [NSMutableArray array]; and it'll work
The important thing to note is that you're not creating another mutable array as you didn't have an array to start with. Merely declaring a property or variable does not create an object to go along with it. That's why self.resultsArray starts out as nil.
The working code you have is designed to allow you to explicitly release the array as you are retaining it twice: once when you alloc it and once when you assign it to your property. You only want one of those retains, so you release once.
You could just do:
self.resultsArray = [[NSMutableArray alloc] init];
[self.resultsArray release];
for (NSDictionary *item in data){
[self.resultsArray addObject:item];
}
This is less code, but it's not as clear. Clarity is important.

Warning "Potential leak of an object allocated on line ..." when declaring a 2D array

Initially i declared a 2D array in this way:
subUrb = [[NSArray alloc] initWithObjects:
[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, #"East",#"South", #"West", #"North", nil] ,
[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, #"Kuala Lumpur SubUrb1", #"Kuala Lumpur SubUrb2", nil],
[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, #"Jakarta SubUrb1",nil],
nil];
But when i try to 'analyze' the warnings of the project, i got three same type of issues in this chunk of code - "potential leak of an object allocated on line xxx"
I noticed that to get rid of it, i have to write sth like this:
subUrb =
[[NSArray alloc] initWithObjects:
[[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, #"East",#"South", #"West", #"North", nil] autorelease],
[[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, #"Kuala Lumpur SubUrb1", #"Kuala Lumpur SubUrb2", nil] autorelease],
[[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, #"Jakarta SubUrb1",nil] autorelease],
nil];
Then i will not get any analyze warnings. But i dun like this...it is not logical. This 2D array should never be released in my controller actually, the entire 2D array should be retained for the entire life time of the controller for a PickerView.
How should I declare the 2D array more elegantly?
1: NARC
If you send +alloc, you own that object and it is your responsibility to release it. Hence
[[NSArray alloc] initWithObjects:ALL_SUBURBS_LABEL, #"East",#"South", #"West", #"North", nil]
creates an array that’s owned by you, hence you should release it.
2: Cocoa collections own their elements
When you add an object to a Cocoa collection such as NSArray, the collection owns that object. It will also release all elements in the collection when they’re not used any longer.
3: Conclusion
Your code without -autorelease gives you ownership of both the outermost array and each inner array that’s an element of the outermost array. This means that you’re responsible for releasing those four arrays (one outermost, three innermost). However, since the outermost array already owns the innermost arrays, you probably don’t need to own them as well, hence -autorelease.
You get the ownership if you allocate an array with alloc init and so you have to release it as you do in your second code.
You can also use:
[[NSArray alloc] initWithObjects:
[NSArray arayWithObjects:first,second, nil], nil];
Your second method is correct. The point is that the enclosing array will take ownership of the nested objects, while the additional ownership lien you gain via alloc is left dangling. A marginally neater approach is to use the class method arrayWithObjects instead of alloc/initWithObjects/autorelease but it amounts to the same thing.
Even if the array is needed through the entire life of the controller, you should release it on the controller's dealloc method, otherwise the objects will leak.
If it is never released then both ways won't leak, but the second is more "correct". The NSArrays won't be autoreleased till the parent array is (never), so it is fine.
When you add a child array to the parent array, the parent array retains the child array. Thus increasing the retain count to 2. Since you're aren't keeping a reference to the child array(s) anywhere else the retain count should only be 1, hence you should use autorelease. So your second version is correct.