My iPhone app is a tab bar controller loading 3 navigation controllers: for the first the view is a UIViewController, and for the 2nd and 3rd the views are UITableViewController.
In all my app I access an object “Car” coming from Core Data, that I store in the app delegate. After changing the first navigation controller view of my tab bar, I get on EXC_BAD_ACCESS all the time when accessing the object in the 3 navigation controller (the settings). The debugger shows the error at @synthesize userCar=_userCar;.
The weird part, when I change in my app delegate the selected index of my tab bar, it works. So when it loads the default (index = 0), when I go in the settings view (index = 2) it crashes, but if I load the settings view at first, then my app all the time runs great.
Crash:
// Display the window with the tab bar.
[self.window addSubview:[self.tabBarController view]];
[self.window makeKeyAndVisible];
Does not crash if loads in MyAppDelegate class:
// Loads the 3 view (Settings) to avoid crash...
[self.tabBarController setSelectedIndex:2];
// Display the window with the tab bar.
[self.window addSubview:[self.tabBarController view]];
[self.window makeKeyAndVisible];
So I don’t understand, when I change back the NIB name and the Class name in my MainWindow.xib (where I have my tab bar controller, etc) to what it was before, it works again perfectly. I tried cleaning the project, restart Xcode and deleting the app from simulator and device, but nothing works.
Any idea?
Thanks!
UPDATE 1
So I declare my car object like this @property (nonatomic, retain) Car *userCar; in all my view controllers.
Then to get the current car, the one the user selected, I do this:
// Get the latest user car selected.
self.userCar = [EcoAppAppDelegate userCar];
Then I my app delegate I have 2 functions that let me play with the car, if the user create a new one it is auto-saved, if in the settings in select another car previsouly selected it saves it too. In the .m file:
+ (Car *)userCar;
+ (void)setUserCar:(Car *)newCar;
In the app delegate .m file:
// On top of the file.
static Car *_userCar;
#pragma mark - Static functions
+ (Car *)userCar
{
return _userCar;
}
+ (void)setUserCar:(Car *)newCar
{
if (_userCar != newCar) {
if (newCar != nil) {
[_userCar release];
_userCar = nil;
_userCar = [newCar retain];
}
else {
[_userCar release];
_userCar = nil;
}
}
}
Last piece of code, when I get the car from the Core Data, I do it this way (at start of the app for example in the app delegate didFinishLaunchingWithOptions):
// Load the car.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Car" inManagedObjectContext:[self managedObjectContext]];
[fetchRequest setEntity:entity];
// Set predicate and sort orderings...
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"selected = 1"];
[fetchRequest setPredicate:predicate];
// Execute the fetch -- create a mutable copy of the result.
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[self.managedObjectContext executeFetchRequest:fetchRequest error:&error] mutableCopy];
if (mutableFetchResults != nil && [mutableFetchResults count] > 0) {
// Get the car selected.
_userCar = (Car *)[mutableFetchResults objectAtIndex:0];
}
else {
// Handle error.
_userCar = nil;
}
// Memory management.
[fetchRequest release];
[mutableFetchResults release];
I believe the main issue is that the car object that you’re getting from core data isn’t being retained. It’s a valid object at the very beginning of the program, but once everything finishes loading the car object is autoreleased.
You can fix this by changing your coredata code to this:
Note the
retain. Also, there is no reason to make a mutable copy of the fetch results.