NSError *error; vs NSError *error = nil; - ios

I developed an ios app that had a:
NSError *error;
instead of:
NSError *error = nil;
It worked fine in while I was debugging in the simulator and debugging on the device while connected. The moment I archived it and sent it into TestFlight to deploy for testing, I started getting Unknown Signal errors coming up in the crash log.
Why does this happen?

This happens because you have an uninitialized pointer. It does not crash as long as you get lucky, but using such pointers is undefined behavior.

To clarify on dasblinkenlights answer, this is declaring a variable:
NSError *error;
... and this is declaring AND assigning a variable
NSError *error = nil;
When you use it the first way and try to access it without ever setting it to something, the value it is pointing at is known as "garbage" It is a pointer to some other stack of memory, and accessing it will almost always make your app crash. Thus, it is always best practice to assign a value to your variable as above, or shortly after.

Related

How to catch NSError instance thrown in iOS simulator

I am developing an iOS application with Rubymotion which worked pretty fine until i added a new UIViewController. I have added the controller via xcode and have got just a UITextField as an element in it. On running the simulator and on displaying this particular scene, I get an instance of NSError. I also dont see the UITextField element in my screen.
Can any one please explain as to what it is and how do i handle the NSError and make sense out of it?
Any help at this point would be of great help.
UPDATE: I am getting the NSError instance every time my app is launched first, no matter what the controller is. I had upgraded to Xcode 5.1 yesterday. Wonder if that has something to do with the error.
UPDATE 2: This was result of a confusion on my part. I had assumed the NSError to have been raised after upgrading to Xcode 5.1 and thought it was some bug. The reason being was that I had had started using push notifications at the same time as I had upgraded to 5.1. As push notifications don't work in simulators, the NSError was being returned by the simulator. Messed it up big time and spent quite a few hours trying to debug this problem.
NSError is a class and it is used as the preferred way to handle errors in objective-c. Usually it works like this:
You declare a NSError pointer and sends the address to that one in as a parameter to a method that might fail. If something goes wrong in the method a NSError object is created and populated with info about the error and when the methods returns you can check the error object to se if anything went wrong.
NSError *error;
[someObject someFunctionWithParam:paramOne andError:&error];
if ( error ) {
// Here you can inspect the error and act accordingly
NSLog(#"%#", [error localizedDescription]);
}
If you are the one implementing a method it usually looks something like this.
- (void)someFunctionWithParameter:(NSString *)argOne andError:(NSError **)error {
// something goes wrong
*error = [NSError errorWithDomain:#"SomeDomain" code:500 userInfo:#{#"infoKey": #"some info"}];
}
So about the title of your question. There is no catching NSError's since they are not thrown. Only exceptions are thrown.

Getting "malloc: *** error: incorrect checksum for freed object" inconsistently

The full error is:
app(85540,0x38661a8) malloc: *** error for object 0x11214f84:
incorrect checksum for freed object - object was probably modified after being freed.
So I'm getting something that is quite hard to replicate and I suspect is has something to do with the way I have my block set up. What I'm trying to get is the current online status of gamers on Xbox Live, so I allocate 2 NSMutuableDictionaries in viewDidLoad. onlinePlayers is for holding the online status values of the gamers so it's not checked over and over again in cellForRowAtIndexPath when scrolling up and down. checkedPlayers is to prevent multiple calls going out trying to get the status of the same player. Anyway, if I keep launching the simulator over and over again, it will be fine 29/30 launches, but it always crashes at least once on launch with the above error when I'm trying to set the online status value for a gamer:
NSString* gamertag = cell.gamerTagLabel.text;
if (![_checkedPlayers containsObject:gamertag]) {
[_checkedPlayers addObject:gamertag];
[Utilities processJSONDataWithGamertag:gamertag andBlock:^(NSData *jsonData) {
id onlineStatus;
NSDictionary *allXboxAttributes = [Utilities returnJSONObject:jsonData];
// Get current Xbox Live Data
if ([allXboxAttributes objectForKey:#"data"]) {
NSDictionary *dataXboxAttributes = [allXboxAttributes objectForKey:#"data"];
onlineStatus = [dataXboxAttributes objectForKey:#"online"];
// Crashes on the line below
[_onlinePlayers setObject:onlineStatus forKey:gamertag];
// Return to main thread and update online status
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}];
}
If it helps for some reason, the value being returned from dataXboxAttributes is a BOOL. Any help would be much appreciated. Thanks!
You are getting the error in that method but the problem might be elsewhere.
To find the source of the problem, in XCode go to Product > Scheme > Edit Scheme, and under Diagnostics tab enable all the Malloc settings and Guard Malloc.
With that, run your application again, and XCode will stop at the line causing the problem.
from your code it looks like the completion block of processJSON isnt always on the main thread, synchronize access to onlinePlayers.
#synchronized will do I guess

Game Kit loadMatchDataWithCompletionHandler never loads match data

I'm building a turn based game kit application and I'm saving and retrieving data using:
saveCurrentTurnWithMatchData:jsonData completionHandler:^(NSError *error)
loadMatchDataWithCompletionHandler:^(NSData *matchData, NSError *error)
I Get all the matches using this:
[GKTurnBasedMatch loadMatchesWithCompletionHandler:^(NSArray *matches, NSError *error) {
and save each of the matches to an array and call the laodMatchData method when I need it. The problem is that the completion handler never returns anything. I guess it's stuck gettings the data and never gets back to me. It loads sometimes but more often than not, it just keeps loading.
Am I missing something?
The problem was with iOS7 beta 1. The problem is solved now.

iOS - Deal with Async task that point to a deallocated variable

I'm calling an asynchronous function from my controller and I pass to it a reference to an error variable, let's say:
NSError *err=nil;
[self myAsyncTask:&err];
if the controller get deallocated, the err variable does not exist anymore, so the app crash with a BAD_ACCESS error (because the function try to change the value of the err variable). How can I deal with that?
Notice that none of the built-in framework methods use pass by reference error reporting with asynchronous calls - they all use delegation or blocks to communicate error status. Using blocks, your API could be written to be used like:
[self doAsyncTaskWithErrorHandler: ^(NSError *error) {
//Handle error
}];
The method signature could look like
- (void)doAsyncTaskWithErrorHandler:(void (^)(NSError *error))errorHandler;
And in the implementation, where you used to do *error = someError; do something like:
NSError *error = ...;
if (errorHandler) {
errorHandler(error);
}
If I'm not mistaken this isn't really an issue with object lifetime though - if the stack frame is popped before the error is set then the pattern in the question would likely cause a crash as well.
How can I deal with that?
If you have an asynchronous function in process, you have to ensure that any variables that it uses remain valid until that function completes. Objective-C's memory management lends itself nicely to this -- a method like your -myAsyncTask can retain its arguments until it no longer needs them. That way, even if the controller (to use your word) is deallocated, the objects referred to by the variables will remain valid.
Another way to do it is to use a block for the async functionality. Blocks automatically retain the resources that they use, so they effectively solve this problem for you.

Core Data: Additional object inserted into Managed Object Context after restarting App

upon loading the Root View Controller a Managed Object called Target should be created using the convenience method:
- (void)viewDidLoad {
[super viewDidLoad];
if (context == nil) {
context = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
if ([fetchedResultsController.fetchedObjects count] < 1) {
Target *aTarget = (Target *)[NSEntityDescription insertNewObjectForEntityForName:#"Target" inManagedObjectContext:context];
}
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
}
if(![context save:&error]){
//Handle error.
} ...
If I run the App on my iPhone from Xcode it works all fine. However, if I stop the test run and restart the App on the iPhone a new Managed Object is created even though the condition
[fetchedResultsController.fetchedObjects count] < 1)
does not seem to be satisfied (in the end it is, I just don't know why). Once the App runs on the Phone independent of Xcode I can close and restart it without increasing the number of Managed Objects created. Only the first time after disconnecting it from Xcode.
Remark: The disconnection from Xcode causes the Segmentation fault: 11 error which also appears when I disconnect another Core Data App from Xcode. So I wouldn't attribute this error to my problem.
Any ideas how to prevent the App from creating this additional object? Would you need more code to figure out the issue? Thanks a lot.
Solely based on the code I can see, I would think that this piece of code will create a new object the first time the code runs each time the app is run.
Try switching your 2nd and 3rd if statements so that you're performing the fetch first. I'd give you code but the code formatting is turning out to be a real pain to use from my iPad.
Thuggish Nuggets & adonoho, thanks very much for your help. You guided me in the right direction. I switched the two statements as suggested and added the following condition when retrieving the object from the managed object context:
if ([fetchedResultsController.fetchedObjects count] > 0) {
id currObj = [fetchedResultsController.fetchedObjects objectAtIndex:0];
}
Without this condition I got an NSRangeExeption error ([__NSArrayI objectAtIndex:]: index 0 beyond bounds for empty array) when switching the two statements.
Following your advice, no new object is created when starting the app anew. Thanks very much!

Resources