iPhone - accessing an NSArray in a ViewController from the AppDelegate? - iphone

I want to be able to access an array of objects in my iPhone application. The array of objects is populated in the appDelegate of my application and I want to be able to access the array in one of my View Controllers.
I currently set up the array in my appDelegate.h file as follows:
NSArray *listObjArray;
#property (nonatomic, retain) NSArray *listObjArray;
I then populate it with some Strings like this in the AppDelegate:
listObjArray = [NSArray arrayWithObjects:#"Hello", #"How", #"are", nil];
NSLog(#"Array size = %i", [listObjArray count]);
It is synthesized and also released in dealloc. The NSLog returns the correct count here.
In my ViewController class I import the appDelegate like this:
#import "MyaAppDelegate.h"
I then access my appDelegate and the NSArray like this and try to Log the count in my View Controller:
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication]
delegate];
NSLog(#"Before array set");
NSArray *newArray = [appDelegate listObjArray];
NSLog(#"After array set");
NSLog(#"array count = %i", [newArray count]);
NSLog(#"After array count");
The logging here gets to "After array set" and then I get "EXC_BAD_ACCESS" on the line where I try to print the count from the array in the View Controller.
The printing of the count works fine from the appDelegate and setting the newArray as the array from the delegate appears to work yet I cant do anything with it then.
Can anyone see what I am doing wrong?

I think your array declaration should be:
NSArray *newArray = [[NSArray alloc] initWithArray:appDelegate.listObjArray]
Be sure to release it after you are done! Though I'm not sure why you want to declare the new array, you could just do:
NSLog(#"array count = %i", [appDelegate.lstObjArray count]);
Hope this helps!
-Karoly

You have a memory issue: listObjArray = [NSArray arrayWithObjects:#"Hello", #"How", #"are", nil]; sets the instance variable directly. Shortly after this line the array gets released again, which results in you accessing a bad memory location in NSArray *newArray = [appDelegate listObjArray];, since it has been freed.
Use self.listObjArray = ... instead when populating the array. This will properly retain the object for you.

Please use the getter if it is sythesized. Since you are not using the getter, it is giving you bad memory access.
Also you should use retain or copy if you want to retain it or copy it. Else both newArray and listObjectArray will point to same memory location causing bad behavior.
NSArray *newArray = [[appDelegate getListObjArray] retain];

Try this
self.listObjArray = [NSArray arrayWithObjects:#"Hello", #"How", #"are", nil];
Allocation should be made on the getter.

Related

How to copy the contents of NSMutableArray to another NStArray in iphone app?

I have two array one is NSMutableArray and one is NSArray i want to store the contents of NSMutableArray in NSArray but it is not working for me gives exception unrecognised selector sent.
myArray=[[NSArray alloc] initWithArray:appDelegate.surveyAnswersScreenOne];
Note, SurveyAnswerScreenOne is an NSMutableArray
You can do that in many ways -
NSArray * myArray = [appDelegate.surveyAnswersScreenOne copy];
NSArray * myArray = [NSArray arrayWithArray:appDelegate.surveyAnswersScreenOne];
NSArray * myArray = [[NSArray alloc]initWithArray:appDelegate.surveyAnswersScreenOne];
But first of all your appDelegate.surveyAnswersScreenOne should have objects in it.
Have you made object for your appDelegate ?
appDelegate = (yourDelegateClass *)[[UIApplication sharedApplication]delegate];
If yes, then other answers should work!
myArray = [NSArray arrayWithArray:appDelegate.surveyAnswersScreenOne];
From what we see here, it is most likely that your mutable array is nil. Look into the creation of that in you app delegate. If it is created properly, check that it is retained. Is it a strong reference?
#propery(nonatomic, strong) NSMutableArray *surveyAnswersScreenOne;
for one, I would use the convenience method:
myArray = [NSArray arrayWithArray:appDelegate.surveyAnswersScreenOne];
If surveyAnswersScreenOne is a valid array, mutable or otherwise, this should work. Try printing it to the console to be sure. This will return empty array if surveyAnswersScreenOne is nil, where alloc initWithArray will fail.
Check you mutable array like this.
NSLog(#"Mutable array is %#", appDelegate.surveyAnswersScreenOne);

how to preserve array outside of method in objective c

After a ASIFormDataRequest , i create a temporary NSMutableArray *resultArray from the JSON then add it to a defined NSMutablearray *myData
-(void)viewDidLoad{
myData = [[NSMutableArray alloc] init];
//request that calls gotInfo method
}
-(void)gotInfo:(ASIFormDataRequest *)request{
NSString *responseString = [request responseString];
NSMutableArray *resultArray = [responseString yajl_JSON];
[myData addObject:resultArray];
}
-(IBAction)doSomethingWithData:(id)sender{
//something with myData
}
but when i try to call myData from outside of the gotInfo: method, i get bad access errors and when i inspect myData outside of the method, it shows a kern_protection_failure. So i'm guessing that outside of the method, the resultArray is obviously released, but it's also released from myData since the object inside myData is sharing the same memory location?
I also tried
-(void)gotInfo:(ASIFormDataRequest *)request{
NSString *responseString = [request responseString];
[myData addObject:[responseString yajl_JSON]];
}
How do I preserve myData??
in my header file:
#import <UIKit/UIKit.h>
#class ASIFormDataRequest;
#interface EventsTableController : UITableViewController <UITableViewDataSource>{
NSMutableArray *myData;
}
-(void)gotInfo:(ASIFormDataRequest *)request;
UPDATE:
so in the gbd, the myData is allocated as 0x5e96560 so i did
po 0x5e96560
and then i get the EXC_BAD_ACCESS with the reason being KERN_PROTECTION_FAILURE at address: 0x00000009
but if i do
po [[0x5e96560 objectAtIndex:0] objectForKey:#"key"]
then i get the value! whyyyyyy?
#property(nonatomic,retain) NSMutableArray *myData
and create the object
self.myData = [[NSMutableArray alloc] init];
and
// and i assume your resultArray is a mature NSMutableArray object
[self.myData addObject:resultArray];
The best way of using copy I can think of, is to always set NSString properties to "copy" instead of retain. That way you get more accurate readings from the Leaks instrument if you mess up and forget to release a string an object is holding onto. Other uses of copy need to be more carefully thought out.
NOTE : You are responsible to release myData after no use of that variable.
You dont really have any way to correctly access myData as you declare it as a member inside of EventsTableController, but you dont set the #property for it, and do not synthesize it either. By synthesizing it in your EventsTableController.m file you are telling xcode to generate the getter/setters you need to correctly touch myData, which is where your program seems to be failing. If you do this, this should solve your problem.
-Karoly
Except for the different name of your ivar (mienVar vs. myVar), I don't see a problem. Some other code must be releasing your ivar, or you are accessing it before viewDidLoad has the opportunity to actually create the array (I bet it is the latter).
I think you should put the code in viewDidLoad in your initialization method instead. Don't forget to release the array in dealloc.
You could, of course, also write your own myData getter method, doing lazy initialization, instead of creating it in the init method:
- (NSMutableArray *) myData
{
if (!myData)
myData = [[NSMutableArray alloc] init];
return myData;
}
Note that now, you should access self.myData if you want to use it.
I think the NSString yajl_JSON category can return an array or a dictionary - you might need to inspect the type of the result array on the line below as it may be an NSDictionary:
NSMutableArray *resultArray = [responseString yajl_JSON];
IF you are treating it as an array when its a dictionary that might be causing your problems.
(relevant code from the NSObject+YAJL category below)
YAJLDocument *document = [[YAJLDocument alloc] initWithData:data parserOptions:options error:error];
id root = [document.root retain];
[document release];
return [root autorelease];
(and in YAJLDocument object)
#interface YAJLDocument : NSObject <YAJLParserDelegate> {
(id root_; // NSArray or NSDictionary

Memory leak when refreshing table view with retain iOS

Most of the memoryleaks I solved myself, but this one is quite tough imo. The following happens. I need to load information from facebook in a table view, this table view has an refresh function. All the rows in this tablview are loaded from an array, this arrays consists of data objects as they need to be sorted. My code looks like this (I have cut out the irrelevant parts).
This parts runs through the results from facebook and places it in an array
- (void)request:(FBRequest*)request didLoad:(id)result
{
if ([result isKindOfClass:[NSDictionary class]]) {
//Setting single result into result dictionary
NSArray *resultArray = [result allObjects];
result = [resultArray objectAtIndex:0];
for(int i=0; i<13; i++){
//Set all retrieved data in containerArray
Post *newPost = [[[Post alloc] init] autorelease];
newPost.created_time = created_time1;
newPost.message = message1;
newPost.picture = picture1;
newPost.fbSource = fbSource1;
[containerArray insertObject:newPost atIndex:i];
//Reload the table in the tableView
[self.tableView reloadData];
}
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:#"created_time"
ascending:NO] autorelease ];
sortedArray = [containerArray sortedArrayUsingDescriptors:[NSMutableArray arrayWithObject:sortDescriptor]];
[sortedArray retain];
}
}
So far this works and gives no memory leaks. But as soon as the refresh function gets called. This function will run again. And then creates the memory leak, I think probably due the [sortedArray retain] function. But without this function the array doesn't load and I get a EXC_BAD_ACCESS. If I release sortedArray, I also get the EXC_BAD_ACCESS since the sortedArray is gone and can't be called.
Someone knows how to fix this? Thnx!
Your diagnosis is right. If you assign a value to sortedArray a second time the way you are doing, the previous object is leaked.
The solution is calling release before doing the assignment:
[sortedArray release];
sortedArray = [containerArray sortedArrayUsingDescriptors:[NSMutableArray arrayWithObject:sortDescriptor]];
[sortedArray retain];
A more elegant solution would be declaring sortedArray as a retain property:
#property (nonatomic, retain) NSArray* sortedArray;
so that you can replace the three lines above by:
self.sortedArray = [containerArray sortedArrayUsingDescriptors:[NSMutableArray arrayWithObject:sortDescriptor]];
and this will handle both releasing and retaining properly.
sortedArray = [containerArray sortedArrayUsingDescriptors:[NSMutableArray arrayWithObject:sortDescriptor]];
This line runs for first time and this is OK. But run 2nd time and you are pointing to a new array, leaking the previous one. So there is two solution.
First, release it before this line like this:
[sortedArray release];
sortedArray = [containerArray sortedArrayUsingDescriptors:[NSMutableArray arrayWithObject:sortDescriptor]];
[sortedArray retain];
Or make sortedArray a retained property in your class.
#property (nonatomic, retain) NSArray *sortedArray;
self.sortedArray = [containerArray sortedArrayUsingDescriptors:[NSMutableArray arrayWithObject:sortDescriptor]];

iphone: unable to copy instance of an array to other array

Dont why this is happening I have a method getOutage which returns an array of managed objects
NSArray *fetchedOutages = [context executeFetchRequest:fetchRequest error:&error];
if (error) {
NSLog(#"Error in Core Data: %#", [error description]);
}
return fetchedOutages;
when I try to copy this array to listOutage (this is a property)
#property (nonatomic, retain) NSArray *listOutage
I tried to copy this array like this in didRowSelectMethod like this
if (listOutage) {
NSLog(#"Its there");
[listOutage release];
}
listOutage=[[NSArray alloc] initWithArray:[self getOutage]];
I tried various other methods but all of then are failing.
This getoutage method returns 5 objects five objects got copied in listOutage but when I try to access the listOutage elements they are displayed as 'out of scope'
Please help me to overcome this I have to pass this to next ViewController.
Thanks in advance
when there is a property, use 'self.property' instead of 'property' that way, when somebody else reads your code it is more obvious if you mean an ivar or a property.
if you use self.property, you do not need to write
if (listOutage) {
NSLog(#"Its there");
[listOutage release];
}
listOutage=[[NSArray alloc] initWithArray:[self getOutage]];
instead, just write
NSArray newListOutage=[[NSArray alloc] initWithArray:[self getOutage]];
self.listOutage = newListOutage;
[newListOutage release];
the release and retain will be handled by the get/set method generated by the #synthesize property.

Objective C two-dimensional array memory issues

I'm trying to declare a two-dimensional array as an instance variable in Objective C. I've got the NSMutableArray in the header (data), along with the #property (nonatomic, retain). In viewDidLoad: I have:
data = [[NSMutableArray alloc] init];
[data addObject:[[NSArray alloc] initWithObjects:#"Cheese", #"Meat", #"Veggie", nil]];
[data addObject:[[NSArray alloc] initWithObjects:#"Sandwich", #"Soup", #"Stew", nil]];
I can NSLog the array within the method and it is correct, however when I try to Log it from a separate method I get nothing (just "#"), and if I try to access with
NSInteger num = [[data objectAtIndex:component] count];
it crashes with no error in the log. I'm sure this is something to do with not allocating memory properly, however I am new to Obj C and haven't worked with a C-style language in many years. FWIW, I have tried many variants of this that all fail, including using NSArray instead of mutable, [NSArray arrayWithObjects] instead of [[NSArray alloc] initWithObjects], and every combination in between.
try creating the outer array like this:
self.data = [NSMutableArray arrayWithCapacity:2]; // assuming you're only adding 2 inner arrays.
The following may be a right way.
self.data = [NSMutableArray array];
[data addObject:[NSArray arrayWithObjects:#"Cheese", #"Meat", #"Veggie", nil];
[data addObject:[NSArray arrayWithObjects:#"Sandwich", #"Soup", #"Stew", nil];
Note that, as #jamihash commented above, you need self.data to properly retain the array. And, there is no need to alloc the NSArray which you are adding to data.
As a side issue, you're retaining the child arrays twice. They get retained when you add them to your NSMutableArray, so you should probably autorelease them on creation or create them with one of the NSArray methods that returns an autoreleased array.
Your code by itself shouldn't crash. You should look into where and when you release and retain the NSMutableArray. You could post more of the code and I'm sure somebody will spot the problem.