I am developing an iPhone app and I have a problem accessing to one NSArray defined on delegate.
My app has two tabs. These two tabs have an UITableView. I have the source of the data of these tables on one NSArray defined in the delegate.
When I load the application, the first tab loads correctly all the content. This is one part of code of the first tab controller:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
mainAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
return [delegate.dataArray count];
}
When the debugger is on return statement, I can see that dataArray has 9 elements. The code works fine.
When I click on the second tab, the same code is executed in the second's tab controller. But while debugger is on return statement, I can see that delegate is not null and dataArray shows
{(int)[$VAR count]} objects
On next step, program crashes giving EXC_BAD_ACCESS
I think in this point dataArray has been released, but I don't know when. I have deleted dataArray release calls on dealloc functions.
This is the property definition of dataArray:
#property (nonatomic, retain) NSArray *dataArray;
Anyone has any idea? I'm completely lost on it. Thanks for your help!
As per your comment, you initialize your array like this:
dataArray = [dict objectForKey:#"data"];
This does not retain the array since you are accessing the ivar directly, not the property. You should do this instead:
self.dataArray = [dict objectForKey:#"data"];
Some programmers prefer to synthesize their properties with a different ivar name to avoid such mistakes.
#synthesize dataArray = dataArray_;
In your comments you just said that dataArray is the response of a servlet and you're parsing it with json-framework.
This sounds like your dataArray object just stores a reference to an external array object being passed in.
You haven't posted much code. Could you show where your dict object is initialized?
Your external object might be getting released causing an EXC_BAD_ACCESS
Related
I have a UITableViewController which presents another UITableViewController when a cell is tapped. I have an NSMutableArray which I want to pass into the new UITableViewController when instantiated.
I would usually do something like :
- (void)loadStationList {
StationListView * listView = [[StationListView alloc] initWithNibName:#"StationListView" bundle:nil];
listView.dataList = newParser.stationData;
// ...
// Pass the selected object to the new view controller.
NSLog(#"New Parser is %d", [newParser.stationData count]); //This is fine - all objects in array here.
[self.navigationController pushViewController:listView animated:NO];
}
The odd thing is that dataList (the NSMutableArray pointer in the new class) is empty (I am in checking in the number of rows delegate method).
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
NSLog(#"Data List is %d", [dataList count]);
return [dataList count];
}
I have tried several different approaches (such as instantiating a new NSMutable array in the parent class) however nothing seems to work. This may be ARC related as I am still relatively new to ARC. Can anyone help ?
How did you declare dataList,newParser.stationData ?
Should be sth like this
#property (nonatomic, strong) NSMutableArray *dataList;
Anyway, to ensure that you do not loose any values, you may want to copy/assign each element from newParser.stationData to dataList.
Like here:
NSMutableArray * dataList = [[NSMutableArray alloc] init];
for (id arrayElement in newParser.stationData) {
[dataList addObject:arrayElement];
}
Try this instead of the simple assignment listView.dataList = newParser.stationData;. ps don't worry about efficieny this is so fast it will not matter.
Well I got round this by created an instance variable in the app delegate and then saving and reading the array from there. This does look like a bug in arc - it works with other variable types.
Currently developing my first Native iPhone application, the application is going to be integrating within an existing .net application and will be using webServices. However the problem i am facing i believe is nothing more than my understanding of xcode.
I hope i can explain this...
OK within my first view, within the viewDidLoad i go off to the webservice and return my list of items (these populate the tableview) this works completely fine:
--- snippet ---
- (void)viewDidLoad {
//GET ALL ITEMS
myArray = [[NSMutableArray alloc] init];
MyWebService *webService = [[MyWebService alloc] init];
myArray = [webService getAllNewsFunction];
[super viewDidLoad];
}
--- snippet ---
Ok so i now have my tableview populated and awaiting for you to select your item (in this case a news article) i need to determine the selectedItem in order to populate the next view with the details of the article. However it appears that within the didSelectRowAtIndexPath method my array list is no longer accessible. I am very confused at this point due to if i simply create a list of items within my viewDidLoad within the current view without using my webservice for example:
--- snippet ---
// listOfItems = [[NSMutableArray alloc] init];
// [myArray addObject:#"Iceland"];
// [listOfItems addObject:#"Greenland"];
// [listOfItems addObject:#"Switzerland"];
// [listOfItems addObject:#"Norway"];
// [listOfItems addObject:#"New Zealand"];
// [listOfItems addObject:#"Greece"];
// [listOfItems addObject:#"Italy"];
// [listOfItems addObject:#"Ireland"];
--- snippet ---
the above is accessible within didSelectRowAtIndexPath and i can populate the detailview.
Can you please help me pinpoint the problem i am facing and how this can be solved. I understand i have given you the very basics so if i need to provide more information i am happy to do so.
-- update --
ok based on your response i have update the following.
I have now declared myArray as a property
#property (nonatomic, retain) NSMutableArray *myArray;
and also updated the line to:
self.myArray = [webService getAllNewsFunction];
-- update --
however i now receive an error "program received signal: "SIGABRT"" on the self.myArray line.
any ideas?
Thanks Again
If you are following naming conventions then the method [webService getAllNewsFunction] will return an autoreleased array. Therefore when you come to access it again it will most likely have been released already.
If you have used a #property to declare myArray (which you should to save yourself from these problems) then you can resolve this by doing:
self.myArray = [webService getAllNewsFunction];
This line:
myArray = [[NSMutableArray alloc] init];
is also superflous and causing a memory leak as you are reassigning the value of myArray to [webService getAllNewsFunction] immediately after without releasing the new NSMutableArray you alloc/init'd
UPDATE
So from reading your update I think you need to firstly look at the warnings your project now has which will probably read something like:
Property 'myArray' requires method 'setMyArray' to be defined - use #synthesize, #dynamic or provide a method implementation in ...
The next clue to the problem appears in the console I get something like this
-[TestAppDelegate setMyArray:]: unrecognized selector sent to instance ...
So what it all boils down to is you either need to provide the methods
- (NSMutableArray *)myArray;
- (void)setMyArray:(NSMutableArray *)myArray;
or let the compiler do it for you by adding a #synthesize statement like this
.m
#implementation YourClass
#synthesize myArray;
// The rest of your class methods
- (void)dealloc
{
// release other ivars
[myArray release];
[super dealloc];
}
The synthesize is the easier, quicker options and the compiler will arrange for the coorect memory management depending on which options you use in your #property declaration.
I have a UITableView I'm populating with data from CoreData. I have a data access class I call a method on to get the array of data to populate the table with. In that method I have something like this:
NSArray *fetchedArray = [context executeFetchRequest:request error:&error];
I was just returning this array directly, but was getting an error in my view controller when I try to set its local property that holds the returned array
#property (nonatomic, retain) NSArray *listData;
and
#synthesize listData; // <-- error here -[CFNumber release]: message sent to deallocated instance...
respectively.
It seemed like the 'retain' in my #property was trying to release the previous listData array, which seemed to have already been released (or, more likely an object in the array or one of its properties had been released).
So in my data access class I added the following after the fetchedArray is produced by the context:
NSMutableArray *listArray = [[[NSMutableArray alloc] init] autorelease];
for (Response *item in fetchedArray) {
[listArray addObject:item];
}
return listArray;
But I still get the same error in the #synthesize listData back in the view controller. It doesn't happen the first time usually, but after tapping through to the detail controller and then going back to the list and then reloading the list with different data (e.g. filtering based on user input which calls the data access method to return an updated list - hence the error in the setter for listData).
I'm not entirely sure if my problem is memory management related or related to something I'm not understanding about what the context returns. It'd be nice if a fetch request returned data that didn't get released when I think I've retained it. :(
EDIT Note that given the answer, the title of the question may be a bit misleading.
Ah - just had to think it through a bit more. My problem was that I was assigning one of the objects in the array to a property on the detail controller, but calling release on that property in my detail controller's dealloc.
After changing #property (nonatomic, assign) to #property (nonatomic, retain) it doesn't crash. Yay. Sooo looking forward to ARC.
I have a class myClass and would like to access its properties, a NSArray *currentOptions (specifically to get the size of currentOptions and access the NSStrings which I've put in it.)
I have a method called generate options which assigns an filled array to *currentOptions. Generate options is called before I try to access *currentOptions. An instance of myClass has also been added to the ViewController via the App delegate. However when buttonOnePressed is called, I keep getting this error:
[myClass currentOptions]: unrecognized selector sent to instance 0x9b10490
Here is the parts of my code:
//TClass.h
#interface TClass : NSObject {
NSArray *currentOptions;
}
#property (nonatomic, retain) NSArray *currentOptions;
#end
//viewController
- (IBAction) buttonOnePressed:(id)sender {
NSLog(#"button1 pressed");
NSLog(#"int: %d",[myClass.currentOptions count]);
//myClass here is the instance of TClass
}
One thing that sometimes causes that error is failing to properly retain myClass. (Aside: "myClass" is a really bad name for a pointer because the thing being pointed to is almost certainly not a class but an object, i.e. an instance of a class.) If you don't retain the object that myClass points to, it will be deallocated. Sometimes, a different object happens to be created at that some location, and you end up sending a message meant for the original object to the new one, which is a different type and doesn't understand the message.
To all who have been following, the problem has been resolved by making the following changes:
1) Synthesized current options TClass.m
#implementation TClass
#synthesize currentOptions;
#end
2) I made currentOptions a NSMutableArray instead of a NSArray. This is because I need to reassign values to current options. Somehow it crashes with NSArray and everything goes smoothly with NSMutable array like such
#implementation TutorialClass
if ([currentOptions count] > 0) {
[currentOptions removeAllObjects];
}
[currentOptions addObject:[options objectAtIndex:0]];
[currentOptions addObject:[options objectAtIndex:1]];
[currentOptions addObject:[options objectAtIndex:2]];
[currentOptions addObject:[options objectAtIndex:3]];
3) And of course, I'll also have to do the following in the init method of TClass.m
currentOptions = [[NSMutableArray alloc] init];
Now its time to get some food. Thanks Caleb :D
I'm trying to share an NSArray object between several different view controllers and my first thought was to add a property on the app delegate as they all have access to this object.
But after some debugging it appears I can't actually share this array for some reason. When I set the object from the first view controller and NSLog the results all is well. But when I attempt to get that array value using another view controller object it always returns UITouchData (not the value previously shown in the logs after my first view controller set the value)
Here is the code that I'm using to set the value
NSArray* cookies = [NSHTTPCookie
cookiesWithResponseHeaderFields:[response allHeaderFields]
forURL:[NSURL URLWithString:#""]];
[appDelegate setAuthCookie:cookies];
Here is part of the .h for my app delegate
#interface SomeAppDelegate : NSObject <UIApplicationDelegate> {
NSArray* authCookie;
}
#property (retain) NSArray* authCookie;
- (void)setAuthCookie:(NSArray *)cookie;
- (NSArray *)getAuthCookie;
#end
Here is the .m for the methods in question
#synthesize authCookie;
- (void)setAuthCookie:(NSArray *)cookie
{
authCookie = cookie;
}
- (NSArray *)getAuthCookie
{
return authCookie;
}
Here is the attempt to grab this array in the second view controller that fails (technically it doesn't fail on this line but I don't get an NSArray back as expected so when I try to use this it fails)
NSArray* cookies = [appDelegate getAuthCookie];
Any way I can share state using the app delegate like this?
Your memory management is wrong, and you are getting a completely different object which has inherited the old array's address when you later use the getter.
Your #property is correct, but you've written your own setter and getter that do not retain the object. You don't need to use both #property/#synthesize and supply your own getter/setter. The former is a newer means of automating the latter.
If you remove your implementations of setAuthCookier: and getAuthCookie then your code should work.