iPhone: Code works in 3G but not 3GS - iphone

I've got a REALLY strange problem - my testers report problems (app is hanging, not crashing) on 3GS, but NOT on 3G... this is the code where I'm assuming the problem:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
[FlurryAPI startSession:#"myflurryapisessionkey"];
[FlurryAPI setSessionReportsOnCloseEnabled:NO];
// set managedObjectContext on TabBarController
tabBarController.managedObjectContext = self.managedObjectContext;
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
// check if we have to show a favorite immediately
Favorite *startseiteFavorite = [self getStartSeiteFavorite];
if (startseiteFavorite != nil) {
[FlurryAPI logEvent:#"favorite found"];
[self showStartseiteFavorite:startseiteFavorite];
} else {
[FlurryAPI logEvent:#"no favorite found"];
}
}
- (Favorite *) getStartSeiteFavorite {
// loading values
smart_infoAppDelegate *appDelegate = (smart_infoAppDelegate *)[[UIApplication sharedApplication] delegate];
managedObjectContext = [appDelegate managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Favorite" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate * predicate;
predicate = [NSPredicate predicateWithFormat:#"startseite == 1"];
[request setPredicate:predicate];
NSError *error;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
[request release];
Favorite *tempFavorite = [mutableFetchResults count] > 0 ? [mutableFetchResults objectAtIndex:0] : nil;
[mutableFetchResults release];
return tempFavorite;
}
I'd like to select a tab according to select the tab according to the existence of such a 'startseiteFavorite' - if there's one, I select tab 1, otherwise tab 0... does anyone of you find a problem or a reason why this works without problems in 3G but not in 3GS?
Thanks a lot,
Stefan

It's pretty tough to figure out a problem like this if you have not actually duplicated the problem yourself? Are you not able to duplicate the problem on the 3GS? You're saying that you are assuming where the problem occurs. That's not the best approach.
Do you not have a 3GS to test on? If not, I would go buy one to test it and get to the bottom of the issue directly in the debugger. You should never ship an app without having the hardware your app says it supports (not sure if you're doing that, but I'm thinking it's possible from the sound of your question).
Ask your testers exactly how they are causing the hang to occur.

Related

Saving Core Data From Multiple TableVIews [duplicate]

This question already has answers here:
Querying Core Data with Predicates - iPhone
(4 answers)
Closed 2 years ago.
I have an app that has multiple tableviews and I want to use Core Data to capture all the data. I have two entities - freezers and items. In the first tableview I add a freezer and it saves correctly. I quit the app, re-open, and it is there. I click on the freezer (opening another tableview) and add some items and I can see them in my new sectioned tableview. I quit my app, restart it, see the freezer, click on it and there are no items.
I have my managedObjectContext in my appDelegate and reference it from there using all views, so I am not creating multiple instances. Here is the code I use to save the items to a freezer, both the managedObjectContext and my itemsArray:
Item *item = (Item *)[NSEntityDescription insertNewObjectForEntityForName:#"Item" inManagedObjectContext:[delegate managedObjectContext]];
[item setFreezer:freezerName];
[item setName:name];
[item setQuantity:quantity];
[item setSection:section];
[item setAdded:added];
[item setNotes:notes];
NSError *error = nil;
if (![[delegate managedObjectContext] save:&error]) {
NSLog(#"Freezer info didn't save. Need to handle this.");
}
[items insertObject:item atIndex:0];
Here is the code I use in the ItemViewController to retrieve the items within viewDidLoad:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"freezer == '%#'", freezerName];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Item" inManagedObjectContext:[delegate managedObjectContext]];
NSSortDescriptor *sorts = [[NSSortDescriptor alloc] initWithKey:#"section" ascending:NO];
NSArray *sort = [[NSArray alloc] initWithObjects:sorts, nil];
[request setSortDescriptors:sort];
[request setEntity:entity];
[request setPredicate:predicate];
NSError *error = nil;
NSMutableArray *results = [[[delegate managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
if(results == nil) {
NSLog(#"Error fetching results... need to handle");
}
[self setItems:results];
NSLog(#"items count:%d", [items count]);
The item count returned is zero.
I am completely stumped and have spent several hours searching online, trying different things, and I can't figure it out. I know there are some much smarter coders out there and I hope one of you can see what the problem is.
I would try to change the predicate to
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"freezer like %#", freezerName];
Hope that helps!
Maybe the problem is that you load data in
- viewDidLoad:
method. It's called only once when your view is loaded, so when underlaying data get's changed, your view controller is not aware about it.
You can either move your loading code to
- viewWillAppear:
method or introduce notifications to spread the information that data store has changed its state and reload table views upon that event.
The best way is probably to use NSFetchedResultsController as your data source, as its always aware of its data store changes. Check docs for reference to that class.

Memory leak problem, could someone explain what this mean?

I am getting a memory leak on the following code line:
The code-line:
NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
I have been trying to read-up on this and have tried to find the cause of this for quite some time, without success.
Could someone give me a hint where to look? ...and do i understand the "100%" correctly that it indicate that this code line is 100% causing the leak?
UPDATE
Some more code:
//=========PREPARE CORE DATA DB===========//
if (managedObjectContext == nil) { managedObjectContext = [(FamQuiz_R0_1AppDelegate *)
[[UIApplication sharedApplication] delegate] managedObjectContext]; }
// Define qContext
NSManagedObjectContext *qContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"questions" inManagedObjectContext:qContext];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [qContext executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
if ([[info valueForKey:#"qDiff"] intValue] == 1) {
[allEasyArrayQ addObject:[info valueForKey:#"idQ"]];
} else if ([[info valueForKey:#"qDiff"] intValue] == 2) {
[allMediumArrayQ addObject:[info valueForKey:#"idQ"]];
} else if ([[info valueForKey:#"qDiff"] intValue] == 3) {
[allHardArrayQ addObject:[info valueForKey:#"idQ"]];
}
}
You are probably over-retaining the array or the objects inside it later in this method or even outside of this method. The line will only indicate where the objects are created, not where the actual extra retain is performed. For that you'd need to check using Instruments which call stacks retain and release the leaked objects.
No, the 100% means that this leak accounts for 100% of your leaked memory (ie, this is you only leak).
Note if you want to fix the leak you are looking in the wrong place. Leaks tells you which instance is leaking, it's Class and it's memory management history. Try a tutorial like this one http://www.cimgf.com/2008/04/02/cocoa-tutorial-fixing-memory-leaks-with-instruments/
Note, what Leaks can't tell you is the line where you are leaking, as the cause of your leak is something you haven't done, as opposed to something you have done (ie you didn't release your object).

MBProgressHUD altering data output?

I'm trying to use MBProgressHUD to show a loading animation while I'm accessing information to smooth out the process of going from a UITableView listing to a UIWebView that has detailed information of the item selected. If I call [self fetchPlayer]; without using MBProgressHUD I have no issues and everything works fine albeit without the animation. But if I call [self loadingAnimation]; it half works. The first time I select something from the UITableView it loads correctly every time, but if I go back and select the same or different item I will quite often get null values for playerDetails items. I'm not sure what the MBProgressHUD method could be doing to cause this but here is the code. The NSLog is displaying the correct information - but the main class that is calling the two methods does not output it correctly.
- (void)loadingAnimation {
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy)
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
// Add HUD to screen
[self.navigationController.view addSubview:HUD];
HUD.labelText = #"Loading";
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(fetchPlayer) onTarget:self withObject:nil animated:YES];
}
- (void)fetchPlayer {
NSManagedObjectContext *pcontext = [[AppController sharedAppController] managedObjectContext];
NSFetchRequest *pfetch = [[NSFetchRequest alloc] init];
NSEntityDescription *pentity = [NSEntityDescription entityForName:#"Players"
inManagedObjectContext:pcontext];
[pfetch setEntity:pentity];
NSPredicate *ppredicate = [NSPredicate predicateWithFormat:#"playerID=%#", [playerNews playerID]];
[pfetch setPredicate:ppredicate];
NSError *perror;
NSArray *plist = [pcontext executeFetchRequest:pfetch error:&perror];
playerDetails = [plist objectAtIndex:0];
NSLog(#"%# %# %# %# %#", [playerNews playerID],
[playerDetails valueForKey:#"playerFirstName"],
[playerDetails valueForKey:#"playerLastName"],
[playerDetails valueForKey:#"position"],
[playerDetails valueForKey:#"dateOfBirth"]);
[pfetch release];
NSManagedObjectContext *context = [[AppController sharedAppController] managedObjectContext];
NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Teams"
inManagedObjectContext:context];
[fetch setEntity:entity];
if (![playerDetails valueForKey:#"team"]) {
team = [playerDetail team];
} else {
team = [playerDetails valueForKey:#"team"];
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"team=%#", team];
[fetch setPredicate:predicate];
NSError *error;
NSArray *list = [context executeFetchRequest:fetch error:&error];
playerTeam = [list objectAtIndex:0];
[fetch release];
}
This seems to be at least a problem with threading. You are sharing your context across multiple threads as fetchPlayer is executed in a background thread by MBProgressHUD.
Create a new Context in the background thread and make sure NSManagedObjects are not shared across threads.

Core Data Memory Leak - iPhone iOS4

I desperately need help with a memory leak in my iPhone app. The app is ready to submit to the app store, is stable, has no memory leaks at all in iPhone simulator or Clang ... but seems riddled with them on my iPod Touch.
They all seem to stem from managedObjectModel when I'm trying to retrieve data from Core Data.
The Core Data code in my app was automatically created by Xcode a while back, I've noticed that the code has since changed when you get xcode to generate it ... I've tried with the old and new but it makes no difference.
If I comment out the following code, the problem goes away ... can anyway see what's wrong with it? I've spent 9 hours on this so far and just can't figure it out!
NSString *entityForName = [[NSString alloc] initWithString:#"OfflineSettings"];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityForName inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
[entityForName release];
NSSortDescriptor *sortById = [[NSSortDescriptor alloc] initWithKey:#"Id" ascending:YES];
[request setSortDescriptors:[NSArray arrayWithObject:sortById]];
[sortById release];
NSError *error;
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error.
NSLog(#"Error fetching");
}
int intId = -1;
if ([mutableFetchResults count] == 0) {
TTDERROR(#"No id has been saved to offline settings");
} else {
OfflineSettings *offlineSettings = (OfflineSettings *)[mutableFetchResults objectAtIndex:0];
intId = [offlineSettings.Id intValue];
}
[mutableFetchResults release];
[request release];
The leak specifically seems to be on this line:
NSMutableArray *mutableFetchResults = [[[self managedObjectContext] executeFetchRequest:request error:&error] mutableCopy];
.. and the code for [self managedObjectContext] is as follows in case it helps ..
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext_ != nil) {
return managedObjectContext_;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext_ = [[NSManagedObjectContext alloc] init];
[managedObjectContext_ setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext_;
}
I'm really at a loss, so I would be so grateful for some help!
Steven
You don't need the mutable copy. executeFetchRequest: returns an autoreleased static array and you're not mutating the array. (I keep seeing this. Must be in an example somewhere.) Likewise, creating the entityForName NSString is pointless. Just put the string literal in the entityForName: to eliminate another possible source of error.
Niether of these are the likely source of the leak but you should remove them anyway.
As a rule of thumb, if you have troubles on device but not simulator or on one hardware but not others, then the problem is in a library/framework that is not properly compiled for the hardware where the error occurs. There really isn't any type of coder error that leaks in one environment but not others. When we make a mistake, it's universal.
It's also possible for resources such as images and sounds to behave differently because different devices use different graphics and audio hardware. That, however, is rather rare.
If you run the code through Instruments it should tell you exactly what object is leaking.

iPhone How to modify the data contained on the Persistent store using Core Data

I'm stuck trying to figure out how to modify the data contained on the persistent store.
I'm writing an application with several views using a UITabBarController, my core data methods are located mainly on the main application delegate but I will only be using this data from the UItableViewController view.
In order to use the managedObjectContext created in the main application delegate from the UITableViewController I use the following on the viewDidLoad: method:
MessageAppDelegate *appDelegate = (MessageAppDelegate *)[[UIApplication sharedApplication] delegate];
managedObjectContext = [appDelegate managedObjectContext];
The application then displays some messages in the table and when a user selects a UITableViewCell (didSelectRowAtIndexPath) I get the ID of the message object and call the following method:
[self readMessage:pk];
-(void)readMessage:(NSInteger)pk {
// First I select the data
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// had to setReturnsObjectsAsFaults to NO so I could access the message data
[request setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Message" inManagedObjectContext:self.managedObjectContext];
[request setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"pk == %d", pk];
[request setPredicate:predicate];
NSError *error;
NSArray *items = [self.managedObjectContext executeFetchRequest:request error:&error];
[request release];
// Then I update the object
for (Message *thisMessage in items) {
//I display the message to the console before updating to check the value
DLog(#"before reading message %#", thisMessage);
// we set the message flat to YES
[thisMessage setRead:YES];
// we set some sample text here (just for testing)
[thisMessage setMessageText:#"New message text"];
// I then display the message to the console checking that the flag and text has been updated
DLog(#"read message %#", thisMessage);
}
// Finally I save the updated message calling the function posted below
[self saveMOC];
}
- (void)saveMOC {
NSError *error;
if (![managedObjectContext save:&error]) {
NSLog(#"there was an error saving the message!");
}
}
After that the data gets updated correctly and if I fetch the data from the managedObjectContext after saving it I get the correct values.
I verified this by adding the following code to at the end of readMessage method:
request = [[NSFetchRequest alloc] init];
//required to avoid presenting objects as faults!!
[request setReturnsObjectsAsFaults:NO];
entity = [NSEntityDescription entityForName:#"Message" inManagedObjectContext:[self managedObjectContext]];
[request setEntity:entity];
//Set the sort descriptor
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"pk" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
//Execute the request
NSMutableArray *mutableFetchResults = [[self.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil) {
// Handle the error later
DLog(#"ERROR: Unable to fetch the results");
}
[self setMessagesArray:mutableFetchResults];
NSLog(#"Data now is: %#", mutableFetchResults);
[mutableFetchResults release];
[request release];
The problem is that if I exit from the application and launch it again all my messages lose the read property (or any other changes I make) and the tableview loads the data as it was first saved onto the persistent store.
Try this and see if the object changes are actually being saved
- (void)saveMOC {
NSError *error;
if (![managedObjectContext save:&error]) {
NSLog(#"there was an error saving the message!");
} else {
NSLog(#"The message was saved!");
}
}
So for each call of saveMOC which is successful, you should see a console message. If it is being called and you're seeing the messages, then you must not be altering the 'read message' property. You could check this by inspecting the value of the 'read message' property before and after setting it either using a breakpoint or by using NSLog messages to print its value
Is -readMessage: method defined in your app delegate or in your view controller? My guess is that you're changing properties of an object in different managed object context than one where you try to save changes (MOC in your app delegate), which actually doesn't have an idea that something has changed. On the other hand, MOC which keeps your changes is never saved (changes are kept only in memory) and that for your changes are lost after you restart your app.
Can this be the situation?