NSUserDefaults:setObject crash - iphone

I trying to save app state on processing event applicationWillTerminate. But NSUserDefaults:setObject crashes in 30% cases if UIAlertView with UITextField present on screen. Call stack looks like
[NSUserDefaults setObject]
[NSNotificationCenter postNotificationName]
_CFXNotificationPostNotification
__CFXNotificationPost
_nsnote_callback
[UIKeyboardImpl defaultsDidChange]
[UIKeyboardImpl takeTextInputTraitsFrom]
[NSObjectCopy]
[UITextInputTraits copyWithZone]
[UITextInputTraits takeTraitsFrom]
[UITextInputTraits setInsertionPointColor]
objc_setProperty
objc_msgSend
Then CBR: Program received signal "EXC_BAD_ACCESS". How I can fix it? Thanks.

I am not as proficient in Objective-C but I'd think that you try to store an object that is actually null or an otherwise bad pointer. To investigate that more, you can either plaster the relevant parts with log messages or step through with the debugger.

Related

reload table view : indexPath isn't reset ios 6

I'm making an iOS 6 program which downloads JSON data from a website and displays it in a table view. I added a pull to refresh method witch works fine. I can go in the settings view controller (secondViewController) and change the address, everything works. Then, I use the pull to refresh method and my tableView is reloaded. But if I reload 3 times AFTER changing the address, my app crashes. I get this error :
*** Terminating app due to uncaught exception 'NSRangeException',
reason: '*** -[__NSArrayM objectAtIndex:]: index 10 beyond bounds for empty array'
*** First throw call stack:
(0x1ca1012 0x10dee7e 0x1c430b4 0x3084 0xdd8fb 0xdd9cf 0xc61bb 0xd6b4b 0x732dd 0x10f26b0 0x229dfc0 0x229233c 0x2292150 0x22100bc 0x2211227 0x22bb333 0x22bb75f 0x1c60376 0x1c5fe06 0x1c47a82 0x1c46f44 0x1c46e1b 0x1bfb7e3 0x1bfb668 0x22ffc 0x1fbd 0x1ee5)
libc++abi.dylib: terminate called throwing an exception
What am I doing wrong ? And how can I fix that problem ? Thanks for your help !
The key design consideration that leaps out is that your retreiveData method is clearly updating the model (the citiesArray) asynchronously, which means that any interaction with the tableview while this is taking place may fail. You should never asynchronously update the actual citiesArray itself. The update to that array should happen in the main queue.
You should change retrieveData to not touch the existing citiesArray, but rather create and return a new array, and then, in the code you dispatch back to the main queue, only then replace the existing citiesArray and call reloadData, something like:
- (void)refresh:(UIRefreshControl *)refreshControl {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *newCitiesArray = [self retreiveData];
dispatch_async(dispatch_get_main_queue(), ^{
if (newCitiesArray) {
// you presumably only want to reload the data if `retrieveData` was successful
citiesArray = newCitiesArray
[myTableView reloadData];
}
[refreshControl endRefreshing];
});
});
}
Clearly, this will involve some changes to retrieveData, too, but hopefully that's self explanatory. If not, update your question with that code, and we can make further suggestions. But we really shouldn't need to go there, as I suspect you understand the change that needs to take place there.
There are other, more subtle issues you might want to tackle, too, such as thinking about whether you really want to use a global queue, which is concurrent (e.g. if you hit refresh while the previous refresh going, do you really want two queries going on concurrently with your server ... because you dispatch the updates back to the main queue you won't crash, but it's inefficient, you're not guaranteed the order that they'll complete, etc.). You might also want to use NSOperationQueue in which you can write code to permit the cancellation of previous requests, etc.
But all of this is a little complicated and is of secondary concern to your main issue, the crashing. Refactoring the retrieveData code to ensure you don't touch citiesArray, itself, as outlined above, should address that.

Problem showing tableView updates while parsing xml with AQXMLParser StreamingParser

I have a tableview which gets filled by a StreamingXMLParser (https://github.com/AlanQuatermain/aqtoolkit).
When I run my app, the tableView appears empty.
First I thought that my tableView didn't show anything until the async xml parser was ready, but if I start to scroll during the parsing the view is suddenly filled.
My code is based on ParserExample (https://github.com/AlanQuatermain/ParserExample) and the parser is called using the same method as the example:
[parser parseAsynchronouslyUsingRunLoop: [NSRunLoop currentRunLoop]
mode: NSDefaultRunLoopMode
notifyingDelegate: self
selector: #selector(parser:completedOK:)
context: NULL]
I think my problem is that my async task is taking up too much processing power.
Who has experience with the StreamingXMLParser and can help me out?
How can I fix my app so the tableView has more priority than the xml parsing ?
The problem can be simulated by downloading the example project and inserting
[NSThread sleepForTimeInterval:0.2];
After the [self.managedObjectContext save: NULL]; statement in the endPost method of the parserDelegate.
I've been able to circumvent the problem by calling the synchronous method [parser parse] via a small utility called MBProgressHUD Created by Matej Bukovinski.
The MBProgressHUD now calls the parsing method async & fixes my problem. (And gives a nice indicator).
I think the problem is in your parsing. Because when you parse some tags they have some empty or \n string so the first few have empty rows. One more thing that can happen is that the response from the server is coming too late. That's why it takes so much time.
You should place some break points and then check each data.

SIGKill Without warning or stack trace with NSLogv

I know this is a somewhat vague question, but during debug execution, the app I'm working on dies without any stacktrace or warning and with simply this message in the debug console:
Program received signal: “SIGKILL”.
I have NSZombieEnabled, NSDebugEnabled, MallocStackLoggingNotCompact and MallocStackLogging all set within XCode.
I've run Instruments to check for memory leaks with none reported.
The last place I can step into with the debugger after it reports that the "GDB: Interrupted" is this piece of code where NSLogv is invoked:
+ (void)print:(NSString *)format, ...
{
va_list args;
va_start(args, format);
// Doesn't seem to go past this line
NSLogv(format, args);
va_end(args);
}
But this method is invoked many a times throughout the app and no problem in any where until at some point after I've used the app long enough.
The stack shown through the debugger thereafter is:
#0 0x02592e07 in ___forwarding___
#1 0x02592cd2 in __forwarding_prep_0___
#2 0x000ce57f in _NSDescriptionWithLocaleFunc
#3 0x0260b00d in __CFStringAppendFormatCore
#4 0x02552f87 in _CFStringCreateWithFormatAndArgumentsAux
#5 0x025da36e in _CFLogvEx
#6 0x0014beb5 in NSLogv
Upon re-testing over and over again, the SIGKILL consistently happens with the call to NSLogv and no where else.
What else can I turn or set to figure out why the debugger is terminating the instance of the app?
Check the format string and the arguments supplied are the correct type, for instance with a format string of #"%f" and argument of #"hello", this would crash....

A NSMutableArray is destroying my life!

IET ANOTHER EDIT (to increase strangeness)
EDITED to show the relevant part of the code
Hi. There's a strange problem with an NSMutableArray which I'm just not understanding...
Explaining:
I have a NSMutableArray, defined as a property (nonatomic, retain), synthesized, and initialized with 29 elements.
realSectionNames = [[NSMutableArray alloc] initWithCapacity:29];
After the initialization, I can insert elements as I wish and everything seems to be working fine.
While I'm running the application, however, if I insert a new element in the array, I can print the array in the function where I inserted the element, and everything seems ok.
However, when I select a row in the table, and I need to read that array, my application crashes. In fact, it cannot even print the array anymore.
Is there any "magical and logical trick" everybody should know when using a NSMutableArray that a beginner like myself can be missing?
Thanks a lot.
I declare my array as
realSectionNames = [[NSMutableArray alloc] initWithCapacity:29];
I insert objects in my array with
[realSectionNames addObject:[category categoryFirstLetter]];
although I know i can also insert it with
[realSectionNames insertObject:[category categoryFirstLetter] atIndex:i];
where the "i" is the first non-occupied position.
After the insertion, I reload the data of my tableView. Printing the array before or after reloading the data shows it has the desired information.
After that, selecting a row at the table makes the application crash. This realSectionNames is used in several UITableViewDelegate functions, but for the case it doesn't matter. What truly matters is that printing the array in the beginning of the didSelectRowAtIndexPath function crashes everything (and of course, doesn't print anything). I'm pretty sure it's in that line, for printing anything he line before works (example):
NSLog(#"Anything");
NSLog(#"%#", realSectionNames);
gives the output:
2010-03-24 15:16:04.146 myApplicationExperience[3527:207] Anything
[Session started at 2010-03-24 15:16:04 +0000.]
GNU gdb 6.3.50-20050815 (Apple version gdb-967) (Tue Jul 14 02:11:58 UTC 2009)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin".sharedlibrary apply-load-rules all
Attaching to process 3527.
Still not understanding what kind of stupidity I've done this time... maybe it's not too late to follow the career of brain surgeon?
following an answer, i printed
NSLog(#"self=%x", self);
NSLog(#"self=%#", self);
NSLog(#"realSectionNames=%x", realSectionNames);
gives the exact same results in every function (from delegate or not).
NSLog(#"realSections = %#", realSectionNames);
prints well in my viewWillAppear, in the didSelectRowAtIndexPath, and crashes in viewForHeaderInSection. No threading, by the way...
So, without knowing what to do, I'm trying "things"... I changed all references of realSectionNames to self.realSectionNames
printing in the viewForHeaderInSection gives the following problem:
2010-03-24 16:01:44.067 myApplication[4104:207] numberOfSectionsInTableView result -> 1
2010-03-24 16:01:44.068 myApplication[4104:207] viewForHeaderAtSection
2010-03-24 16:01:44.068 myApplication[4104:207] self=3d13470
2010-03-24 16:01:44.068 myApplication[4104:207] self=<RootViewController: 0x3d13470>
2010-03-24 16:01:44.069 myApplication[4104:207] self.realSectionNames=3b12830
2010-03-24 16:01:44.070 myApplication[4104:207] realSections = (
<__NSArrayReverseEnumerator: 0x3b50500>
)
2010-03-24 16:01:44.070 myApplication[4104:207] *** -[__NSArrayReverseEnumerator length]: unrecognized selector sent to instance 0x3b50500
2010-03-24 16:01:44.071 myApplication[4104:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayReverseEnumerator length]: unrecognized selector sent to instance 0x3b50500'
2010-03-24 16:01:44.072 myApplication[4104:207] Stack: (
31073371,
2572170505,
31455291,
31024758,
30877378,
276908,
26404,
3227182,
4544033,
4551926,
4550923,
3267462,
3207973,
3249408,
25927,
3222086,
3205252,
459178,
30857920,
30854216,
39163413,
39163610,
2949039
)
What is a NSArrayReverseEnumerator??? And why is it being mean to me???
Note to everybody (and specially to self)...
I'm a dumb, dumb boy.
I was releasing an element which I inserted in the array.
Sorry for the questions, thanks for the answers...
When an application crashes, the Xcode Console will report the error that caused the application to crash. You will want to edit your question to include this error message, along with relevant source code, as this will help others answer your question.
I suspect your selected table row is trying to point to an index in the array, which does not exist. If so, you're trying to reference a part of the array that does not exist. This causes your application to throw an exception and quit.
Remember that an NSMutableArray can be initialized to a certain capacity, but until items are inserted, it does not actually hold any objects. The -initWithCapacity: method only sets aside a certain amount of memory, but there are no placeholders or nil entries for 1 through n indices.
1) Could we know the error message ? and the relevant part of the code ?
2) Here is the proper way to declare your array :
self.realSectionNames = [[NSMutableArray arrayWithCapacity:29];
I suspect your TableView's delegate isn't hooked up correctly, or is connected to an invalid object. Are any of your other delegate methods working? Try putting these at the top of didSelectRowAtIndexPath to check the pointer values:
NSLog(#"self=%x", self);
NSLog(#"self=%#", self);
NSLog(#"realSectionNames=%x", realSectionNames);

Multiple UITableViews displaying the same data

I am working on an app that has several views selected using a tab bar. One tab displays a list of data using a table view. Another tab uses a table view (and a navigation controller) so the user can add items to/delete items from the list.
If the user switches to the first tab after adding or deleting items on the other tab, the app crashes. (I'm still working on trying to glean anything useful from the debugger output).
New (as of 22 Aug) info:
In light of some of the comments below, I've been doing some exploring and I think I must not be allocating objects correctly. Below is a stack trace, but note I am not always getting the same error. Eg, sometimes I get an uncaught exception, sometimes just the debugger steps in; when it is an uncaught exception, it's not always the same one.
2009-08-22 15:20:34.254 Mexico[29531:20b] * -[_NSIndexPathUniqueTreeNode isEqualToString:]: unrecognized selector sent to instance 0x562ff0
2009-08-22 15:20:34.255 Mexico[29531:20b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[_NSIndexPathUniqueTreeNode isEqualToString:]: unrecognized selector sent to instance 0x562ff0'
2009-08-22 15:20:34.257 Mexico[29531:20b] Stack: (
2504683691,
2423127611,
2504712874,
2504706220,
2504706418,
817812590,
19892,
816386359,
816387412,
816468754,
816411067,
836579268,
836579060,
836577406,
836576671,
2504177986,
2504184740,
2504187000,
827745792,
827745989,
816114848,
816160924
)
[Session started at 2009-08-22 15:20:34 -0400.]
Loading program into debugger…
GNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:14:40 UTC 2008)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin".warning: Unable to read symbols for "/System/Library/Frameworks/UIKit.framework/UIKit" (file not found).
warning: Unable to read symbols from "UIKit" (not yet mapped into memory).
warning: Unable to read symbols for "/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics" (file not found).
warning: Unable to read symbols from "CoreGraphics" (not yet mapped into memory).
Program loaded.
sharedlibrary apply-load-rules all
Attaching to program: `/Users/matt/Library/Application Support/iPhone Simulator/User/Applications/0F9033CE-39BB-4589-B791-5E473D991789/Mexico.app/Mexico', process 29531.
(gdb) bt
#0 0x954a6f54 in ___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___ ()
#1 0x906dfe3b in objc_exception_throw ()
#2 0x9542da53 in CFRunLoopRunSpecific ()
#3 0x9542dc78 in CFRunLoopRunInMode ()
#4 0x31566600 in GSEventRunModal ()
#5 0x315666c5 in GSEventRun ()
#6 0x30a4eca0 in -[UIApplication _run] ()
#7 0x30a5a09c in UIApplicationMain ()
#8 0x00001ffc in main (argc=1, argv=0xbfffe108) at /Users/matt/Coding/iPhone/Mexico/main.m:13
(gdb)
Here is some (I think) relevent code. First, the function that invokes a view to add a new entry:
- (IBAction)addButtonWasPressed {
AddPlayerViewController *apvController;
apvController = [[AddPlayerViewController alloc]
initWithNibName:#"AddPlayerView" bundle:nil];
apvController.rvController = self;
[self.navigationController pushViewController:apvController animated:YES];
[apvController release];
}
Then in the add player view:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[rvController addPlayerNamed:textField.text];
[textField resignFirstResponder];
[self.navigationController popViewControllerAnimated:YES];
return YES;
}
Finally RosterViewController is a subclass of UITableViewController and has the following method:
- (void)addPlayerNamed:(NSString *)name {
Player *player = [[Player alloc] initWithName:name];
[players addObject:player];
// insert NSLogS
NSIndexPath *indexPath;
indexPath = [NSIndexPath indexPathForRow:[players indexOfObject:player] inSection:0];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:NO];
}
If I iterate over players and print out the names using NSLog statements (see commented spot above), then the app crashes after I add a second entry. If I take the NSLog statements out, then it won't crash until later.
If i had to guess, i would say you are probably sharing the data objects (data sources) in your two table views and deleting from one is affecting the other, and you try to do something with the released object in the other view which is causing the app to crash, or something along those lines.
Here's how I'd do it:
Create a class that implements the UITableViewDataStore delegate methods. Assign it to something accessible from both viewcontrollers. A good place is up at the UIApplication level so you can get to it via something like:
MyDataStore* store = ((MyApplication *)[UIApplication sharedApplication]).{myDataStore}
For backing store this class would keep the actual values in an array, a dictionary, a SQLite database, or something like that.
Assign this class to each table's dataSource property. Since it's owned by the app it shouldn't be released until the app is finished. So you'll want to make sure the object is accessible via a property with a "retain" attribute.
Each time the user adds something you'll want to add it to this object then call reloadData on the table to refresh the table.
For each of those views implement the viewWillAppear method. This gets called whenever that view comes into view. Inside it make a call to the table reloadData as well. This way when the user switches from one view to another, before the new view is shown, it will have refreshed itself with the new data.
If you assign the datastore object to the application then it owns it for the lifetime of the app so you probably don't want to set it to autorelease. If memory becomes an issue then you'll want to save the backing stuff to SQLite or CoreData.
You're probably already doing all this but this is the general pattern for creating shared data between views. Maybe it'll help jog something.