Can't access an NSMutableArray created with Json in another object - objective-c

I create an NSMutableArray:
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSMutableArray *components = [parser objectWithString:#"[\"Item1\",\"Item2\"]"];
then I access it from the same method: no problem!
Then I try to access it from another object: crash!!??
It doesn't happen if i create the NSMutableArray with other means (e.g. initWithObjects:)
Any clue?
It's been all day I can't find a solution to this.

The array returned from [parser objectWithString:] is autoreleased; you need to retain it yourself if you want to keep it around.
(You're also probably leaking parser unless you're releasing it later in your method.)

Related

potential leak value stored never read in NSMutableArray

NOTE: i want to alloc my NSMutableArray and then assign data in it.
i got leak in below code
NSMutableArray *responseArr=[[NSMutableArray alloc]init];
responseArr =[response valueForKey:#"result"];
Also in here value stored never read
NSString *name=_txt_name.text;
if ([name length]==0) {
name=#"";
}
Also leak in below
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/yyyy HH:mm:ss"];
//below here i get leak
NSDate *dateStart = [[NSDate alloc] init];
dateStart = [dateFormatter dateFromString:startDate];
EDIT :
I have disable ARC using -fno-objc-arc in reachability Class even i get below leaks
This line
NSMutableArray *responseArr=[[NSMutableArray alloc]init];
Allocates a new NSMutableArray and assigns a reference to it to responseArr
This line
responseArr = [response valueForKey:#"result"];
Takes a value from a dictionary (that presumably is a reference to an NSMutableArray) and assigns that to responseArr. At this point there are no more references to the original NSMutableArray that you allocated, so it will be deallocated.
You can just say:
NSMutableArray *responseArr = (NSMutableArray *)response[#"result"];
Similarly with your date code, you could just say:
NSDate *dateStart = [dateFormatter dateFromString:startDate];
There is no need to assign an initial value, only to throw it away.
None of the code you have shown will cause leaks, assuming you are using ARC.
If you aren't using ARC, then start using ARC!
A. First snippet
Using MRC (MRR) you have to balance allocations with +alloc your own:
NSMutableArray *responseArr = [[NSMutableArray alloc]init];
responseArr = [response valueForKey:#"result"];
In the first line you allocate an instance of NSArray. You have to (auto-)release it later, otherwise it is a memory leak. I think you misunderstood that you create a new instance of NSArray using -valueForKey and assign the value of this new reference to responseArr. (Therefore you do not need a mutable array.) After that you created two objects having only one reference to the new one, you can never release the old one.
Do something like this:
NSArray *responseArr = [[NSArray alloc]init];
NSArray *resultArr =[response valueForKey:#"result"];
[responseArr release];
You do not have to do that with the object referred by resultArr, because it isn't created with +alloc-init. Here you get an introduction to ownership.
B. Third snippet
It is the same with the last example:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
You +alloc-init that instance object, but there is no release in your code. Therefore it cannot be released anymore, when the reference dateFormatter loses its extent (lifetime), i. e. returning from the method.
Add this code at the end of the method:
[dateFormatter release];
C. Second snippet
The second example has a different problem: You assign a value to the var name without using the variable in the code below. So assigning the value is meaningless.

How to copy NSArray to another NSArray?

I have many different NSArrays, and according to the users choice I want one of them to be copied to a new NSArray. How do I copy one NSArray to another?
There can be several ways for this-
array1 = [array2 copy];
Use initWithArray method.
You can also use initWithArray:copyItems: method. (This if for NSMutableArray)
you can use the
NSArray *_newArray = [NSArray arrayWithArray:_oldArray];
or if you prefer better, you can use:
NSArray *_newArray = [[NSArray alloc] initWithArray:_oldArray];
(in that case the object of the first array won't be copied, that get only a retain front he second NSArray, you can remove the object from any array it won't affect the other array, but if you change any object in any NSArray it will be changed in the other one as well because there is both of the old and the new array is working with the same instance of the objects.)
if your plan is to make another instance of the old objects in the new array:
NSArray *_newArray = [[NSArray alloc] initWithArray:_oldArray copyItems:true];
if you are using the ARC, you won't need to do anything else, if you are not, in the case of both -initWithArray: or -initWithArray:copyItems: you should use the [_newArray release]; to release the array after you don't want to use anymore.
As well as
NSArray *newArray = [oldArray copy];
if you need to add/remove from the new array, the simplest way to make a mutable copy is:
NSMutableArray *editableArray = [oldArray mutableCopy];
The above functions both make shallow copies, for deep copy it's as #holex and #rishi mentioned
NSArray *newArray = [[NSArray alloc] initWithArray:oldArray copyItems:true];
NSMutableArray *editableArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:true];

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.

Assigning values to Instance variables in Objective C

The function I'm looking at:
-(void)viewDidLoad {
NSBundle *bundle = [NSBundle mainBundle];
NSString *plistPath = [bundle pathForResource:#"statedictionary" ofType:#"plist"];
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.statesZips = dictionary;
[dictionary release];
NSArray *components = [self.stateZips allKeys];
NSArray *sorted = [components sortedArrayUsingSelector:#selector(compare:)];
self.States = sorted;
NSString *selectedState = [self.states objectAtIndex:0];
NSArray *array = [stateZips objectForKey: selectedState];
self.zips = array;
}
Why is an NSDictionary allocated, then assigned to a pointer called *dictionary, and then assigned to the instance variable stateZips? Why not allocate it and assign it directly to the instance variable and save memory of creating and releasing another NSDictionary? The same methodology is always followed, including later in this function with the NSArray...
NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
self.statesZips = dictionary;
[dictionary release];
Also, this sorting puts the keys from a hash table (dictionary) in alphabetical order. I'm not sure I understand this line:
NSArray *sorted = [components sortedArrayUsingSelector:#selector(compare:)];
No one seems to have addressed the fact that the line
self.statesZips = dictionary;
is not directly an instance variable assignment. stateZips is a property, and so that line of code calls the setStateZips: method. That method retains or copies the dictionary, so unless the viewDidLoad method intends to use it again for some purpose, it's not needed any longer. That makes it OK to release it.
The previous line:
[[NSDictionary alloc] initWithContentsOfFile:plistPath];
allocates an object. That makes it your responsibility to release it once you don't need it any more. After assigning it to the statesZips property, it's no longer needed, so it's released and you shouldn't use dictionary any more. You'll notice that later code only refers to self.stateZips, not dictionary.
In the case of the NSArray later in the method, viewDidLoad does not allocate the object, so that method is not responsible for calling release on it. The rule of thumb is that if you alloc it, you're responsible for making sure it gets released. Otherwise, it's not your problem.
Sorting the array uses the sortedArrayUsingSelector: method. A selector identifies a method in Objective-C. And the #selector is the literal syntax for selectors (kind of like how #"" is the literal syntax for NSString objects). So, what that code says, is "give me an array where the objects in components are sorted, and use the compare: method to compare each object when you do the sort. When it sorts the array, it will call compare: on the objects in the array to determine how to put them in order.
The statesZips property is probably retained, that's the reasoning.
When the NSDictionary is first allocated, its retain count is 1. When it's assigned to statesZips, the retain count becomes 2. When it's released, the retain count drops to 1, which is usually the desired outcome.
Note that the code below would have produced (almost) the same result:
self.statesZips = [NSDictionary dictionaryWithContentsOfFile:plistPath];
because dictionaryWithContentsOfFile returns an autoreleased object.
As a convention, class methods like [NSDictionary dictionary] return autoreleased objects (which automatically get released after some time), while the usual alloc-init method (as in [[NSDictionary alloc] init]) return retained objects.
I suggest you read the Memory Management Programming Guide for Cocoa for further information.
EDIT: I must have missed the last part of your question when I first read it, but Barry has already answered that part.
This code uses reference-counted memory management (not the automatic garbage collection memory management available in Objective-C 2.0 on OS X). When any object (in this case, the NSDictionary and the NSArray) are alloc'd, the caller is responsible for calling -release on that instance. Failing to call release causes a memory leak. The code could have been written as
self.statesZips = [[[NSDictionary alloc] initWithContentsOfFile:plistPath] autorelease];
but at the expense of less explicit memory management (relying on NSAutoreleasePool to release the alloc'd instance at the end of the event loop iteration.
the call
[components sortedArrayUsingSelector:#selector(compare:)];
returns an array of whose elements come from components but according to the return value of calling [elem1 compare:elem2] to compare two array elements.