Trashed properties in Application Delegate - iphone

I'm in deep trouble. Something in my app causes a lot of properties in my app delegate to become trashed (changing contents and even object type, say an NSArray becomes an NSString...), and I can't debug it out. I can find no memory leaks or errors on my part. The only thing I've found is that all the way to ViewDidAppear for the view of the first tab, everything is okay. The view displays a table. When one of the cells are clicked, the app delegate properties are already trashed.
What after a view has been loaded and before didSelectCellForRow could cause this? No other code of mine is being executed between those two, certainly no code in the app delegate.
Any tips for hunting this down in an sleuthy manner would be appreciated, or just some thoughts on narrowing it down to what could cause it.

It sounds like either something is getting released prematurely or things are not properly connected with respect to one of your XIBs. If you haven't already, you might want to familiarize yourself with NSZombieEnabled, NSDeallocateZombies, NSEnableAutoreleasePool and NSAutoreleaseFreedObjectCheckEnabled. These are environment variables that can be set in the Executable "Get Info" window's Arguments panel.
For sanity's sake, I have added this to my AppDelegate's -applicationDidFinishLaunching:
#ifdef DEBUG
// account for environment value's actual value if set.
NSString *NSZombieEnabled = (getenv("NSZombieEnabled"))
? [NSString stringWithCString:getenv("NSZombieEnabled") encoding:NSASCIIStringEncoding]
: #"NO";
DLog(#"NSZombieEnabled = %#", NSZombieEnabled );
NSString *NSDeallocateZombies = (getenv("NSDeallocateZombies"))
? [NSString stringWithCString:getenv("NSDeallocateZombies") encoding:NSASCIIStringEncoding]
: #"NO";
DLog(#"NSDeallocateZombies = %#", NSDeallocateZombies );
NSString *NSEnableAutoreleasePool = (getenv("NSEnableAutoreleasePool"))
? [NSString stringWithCString:getenv("NSEnableAutoreleasePool") encoding:NSASCIIStringEncoding]
: #"YES";
DLog(#"NSEnableAutoreleasePool = %#", NSEnableAutoreleasePool );
NSString *NSAutoreleaseFreedObjectCheckEnabled = (getenv("NSAutoreleaseFreedObjectCheckEnabled"))
? [NSString stringWithCString:getenv("NSAutoreleaseFreedObjectCheckEnabled") encoding:NSASCIIStringEncoding]
: #"NO";
DLog(#"NSAutoreleaseFreedObjectCheckEnabled = %#", NSAutoreleaseFreedObjectCheckEnabled );
#endif
It sometimes saves me from having to check these variables through Xcode UI.

The only way out was to wade through every alloc in the app delegate and a few viewcontrollers and also made sure I knew what'd happen using the NSCopying protocol. There were 2 errors due to synthesized but nil (and then reassigned!) objects, and 1 copy-error, one or more of them caused the trashing when there was an early "autorelease" by Objective-C.

Related

Object is deallocated - why? where?

Ok, I spent the last 8 hours fighting with it - it just seems beyond me. Here's my complete (relevant) code:
- (void)updateUserDefaults
{
NSMutableDictionary *viewControllerDetails = [[NSMutableDictionary alloc] initWithCapacity:4];
[viewControllerDetails setObject:[NSNumber numberWithInt:OOVenueClassControllerType] forKey:#"classType"];
[viewControllerDetails setObject:self.searchTerm forKey:#"searchTerm"];
[viewControllerDetails setObject:self.searchLocation forKey:#"searchLocation"];
//----- the next two lines cause the problem
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
[viewControllerDetails setObject:res forKey:#"searchresults"];
//-----
NSMutableArray *viewControllersList = [NSMutableArray array] ;
[viewControllersList addObject:viewControllerDetails];
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
//the following line causes the error
[defs setObject:viewControllersList forKey:kViewControllersKey];
[defs synchronize];
[res release];
}
Note the block with the next two lines cause the problem. At first I didn't create another string, but added it later while trying to solve the problem.
If I comment out those two lines, everything works fine. If I put them back in, I get
- [CFString class]: message sent to deallocated instance 0xa1a9000
Is something is wrong with the string that I'm trying to put into the userdefaults? That string is rather large (about 200,000 characters), but I had stored even longer strings in user defaults in the past.
It's also worth noting that if I uninstall the app, then everything works fine. But on subsequent runs the problem exhibits itself.
So, how and why and where is the string getting deallocated? I have explicitly added retain - but that still doesn't help. What am I missing?
Edit: just realised I forgot to say that the error is thrown on line
[defs setObject:viewControllersList forKey:kViewControllersKey];
Also, for general information, method - (NSString *)xmlString on searchResults does exactly what the name means: creates an XML string with the information from that object.
Edit 2: I tried doing something else with that string - convert it to NSData, compress using zlib - but regardless of data type, that particular object gets deallocated. Does it have to do something with the size of the string?
NSString *res = [[NSString stringWithFormat:#"%#",[searchResults xmlString]] retain];
Is auto released. You don't need to release it at the end of your method. You are over-releasing it.
Further, you don't need to retain the [searchResults xmlString]. The stringWithFormat method already does it for you.
Good Luck!
Ok, not sure what exactly the problem was, but it was somewhere in the searchResults and/or xmlString method. searchResults object is originally created from XML received from the server (XML is parsed into the object structure). When xmlString was called, for some reason the string I was getting back was different from the original XML (I'm not talking about formatting, of course) - of 200,000 char-long string, within the first 500 chars or so there were some differences. I haven't been able to figure out why. So, instead of recreating the xml from object structure, I instead stored the original XML in a field in that object and, when xmlString was called, simply returned the original string. Now everything worked fine.
Thank you all for your support through this painful process.

Strange Error:-CoreAnimation: ignoring exception:

I am developing an iPhone application and everything seems to work fine.
But when I use the app for some amount of time suddenly on view load
CoreAnimation: ignoring exception: *** -[NSArray objectAtIndex:]: index 1 beyond bounds [0 .. 0]
comes and after that the view life cycle methods are not called (basically the app stop responding).
Please suggest me if anyone knows the significance of this error or how do I resolve it.
Did you check if you get any memory issues just before this error message pops up? Implement the didReceiveMemoryWarning method in all your viewcontrollers (put in NSLog statements for now) and see if any of these are printed before you get this error.
Finally I got solution to my problem , it really very strange but would like to share with all of you so that if you guys face the same error, can check for this:-
On debugging my whole project I came to know on a when I click on a certain button and then click on any where else so that that page viewWillDisappear Method gets called.
-(void)viewDidDisappear:(BOOL)animated
{
NSString *finalTimeString=self.timeLabel.text;
if (![finalTimeString isEqualToString:#""] || finalTimeString!=nil) {
NSArray *aRR =[finalTimeString componentsSeparatedByString:#"-"];
NSString *startTimeString = [[aRR objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *endTimeString = [[aRR objectAtIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[appDelegate.searchDataDictionary setObject:startTimeString forKey:#"time_str"];
[appDelegate.searchDataDictionary setObject:endTimeString forKey:#"time_end"];
}
}
I came to know that when I got finalTimeString empty then that error came and if finalTimeString contain some data then it works fine.So I put condition according to my self and got rid from this error.
Happy Coding:)

bad UIViewController

I have ONE viewController that is giving me a problem...
UIViewController *nextController = [[NextView alloc] initWithNibName:#"NextView" bundle:nil];
[currentPageController.view removeFromSuperview];
[self.view addSubview:nextController.view];
My app crashes here with an EXC_BAD_ACCESS.
Does anybody have ANY idea what could cause this?
Thanks in advance!
UPDATE
After using Breakpoints and stepping through the code, the problem seems to be with this bit of code in the viewDidLoad of my viewController:
NSString *noteToSet;
if ([Settings isData]) {
noteToSet = [NSString stringWithFormat:#"Data, "];
}
if ([Settings isGeom]) {
if ([noteToSet isEqualToString:#""]) {
noteToSet = [NSString stringWithFormat:#"Geom, "];
} else {
noteToSet = [noteToSet stringByAppendingFormat:#"Geom, "];
}
}
Anybody see a problem there?
Thanks so much!
FIXED
Fixed it by initializing the string with the blank value #""
noteToSet = [NSString stringWithFormat:#""];
So the first part of the answer is - if your viewController won't load and you have no idea why - check the code in viewDidLoad, that's where my issue was and it drove me crazy trying to figure out what was wrong with the viewController itself when it was really an NSString issue in the viewDidLoad all along.
The second part is that you can't compare an NSString to a blank value using [stringName isEqualToString:#""] unless you got that string from NSUSerDefaults or unless you first set the string to be equal to #"".
I don't see anything in the posted code that'd cause the exception. However, both pieces of code that you posted contain the lines:
currentPageController = nextController;
[currentPageController retain];
[nextController release];
Since the first line makes currentPageController point to the same object as nextController, the second and third lines cancel each other out. You might as well write:
currentPageController = nextController;
and leave it at that. A similar misunderstanding at some other point in the code could easily cause you to miss a retain or release once too often and cause the sort of bad pointer that you seem to be seeing.
EXC_BAD_ACCESS is often caused by poor memory management. Go to the Build Menu in Xcode and Profile it (in the simulator) using Allocations. Then go in and make sure you have Zombies Enabled. Run the app in the simulator and point it to where you get the error. Instruments should then tell you where the bad memory management is. If you still can't get it, then tell us what you're getting.
Here's a guide: http://www.markj.net/iphone-memory-debug-nszombie/

Passing Variables Error

Im getting this annoying error and tried every i know but in this case it hasnt helped.
I have in my delegate....
vid_name = [push objectForKey:#"vid"];
(in the console .... vid = "video" )
now in my normal page i have
NSString *videoName = [(MissileAppDelegate *)[[UIApplication sharedApplication] delegate] vid_name];
NSString *path = [[NSBundle mainBundle] pathForResource:videoName ofType:#"mp4"];
when i run this and it comes to play the video, i get an error that doesnt even relate to the video, it happens with all variables i try and pass over using the [push objectForKey:#"vid"];. if i just vid_name =#"video" it works fine.
Any Ideas?
Alex
First of all do not name your variables like vid_name! You should always use vidName in Objective-C.
You should share more information, I'm not really getting what you're doing and the error message you get would be niche.
But It sounds like a memory management problem. Because when you use the #"video" this is a static string that is always there. But when you use objectForKey: you get an object that is autoreleased and get's eventually deallocated at some point. So make sure your vid_name still exists when accessing it from your 'normal page'.
Cocoa Memory Management Programming Guide

"Invalid" iphone string

I'm converting data (from a web page) to a string). The basic code works (but there's been some subtle change somewhere - maybe on server).
NSLog shows the expected string (maybe 1000 chars long). However, when I float over responseString, it shows "Invalid". Worse, parsing with componentsSeparatedByCharactersInSet does not work.
Ideas?
NSString *responseString;
responseString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSLog([NSString stringWithFormat:#"responsestring ='%#'",responseString]);
if ([responseString compare:#""] != NSOrderedSame) {
lines = [responseString componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:#";"]];
This may happen when the configuration is set to "Release" rather than "Debug" I think.
Do not trust what the debugger says, it is not accurate, this has happened to me and took me a while to realise that the xcode debugger is not always right and should not be trusted, so i no longer trust the debugger and i use nslog statements whenever it tries to tell me something is invalid. So dont worry about it it happens, and when it happened to me I was also parsing responses from some webservice.
Just to be clear -- my experience with seeing "Invalid" in the debugger means that the reference is to an already-released object.
Your question and the comments below seem to suggest that you are thinking "Invalid" is an actual string value -- but are you sure you don't just have a memory management probably?