UIAlertView clickedButtonAtIndex EXC_BAD_ACCESS - iphone

I currently have a UIAlertView being shown with two option buttons. When the user presses one of the buttons, I would like a method (in the same object) to be called that would then retrieve a file from the web.
I can call the method fine and can call NSLog(), but as soon as I come to use any object variables, I get an EXC_BAD_ACCESS error.
My first thought was it could be a threading issue, so thought calling NSNotificationCenter might solve it, but that too ends in the same error.
Below is the code I've got at the moment. I have tried a few different things (some are commented out) to no avail. The 'dbURL' object is a property of the class. (Edit: below code is not complete)
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
//If database update
[[NSNotificationCenter defaultCenter] postNotificationName:#"newdb" object:self]; //EXC_BAD_ACCESS happens here
if ([alertView.title isEqualToString: #"Database Update"]){
switch (buttonIndex) {
case 0:
//[self getNewDatabase];
//[self performSelectorOnMainThread:#selector(getNewDatabase) withObject:nil waitUntilDone:NO];
//[NSThread detachNewThreadSelector:#selector(getNewDatabase) toTarget:self withObject:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"newdb" object:self];
break;
// Get a new database file from the server
- (void)getNewDatabase{
NSLog(#"in database: %#", dbURL);
}
Thanks in advance!

The problem was an object I was calling as not being retained properly and therefore the reference was lost, resulting in an EXC_BAD_ACCESS error
Thanks to Nick Weaver. Using the NSZombieEnabled argument in the build options helped to identify the rogue reference.

You can't compare NSString with == . You need to use isEqualToString:
[alertView.title isEqualToString:#"Database Update"]

Related

Implement game center, and "missed method" error [duplicate]

Apologies ahead of time if this is a completely off-the-mark question, or if I'm not including enough information - I'm very new to iOS development (and Objective-C), and have a habit of jumping into the deep end...
I'm having trouble understanding the "callDelegate" code in GameCenterManager.m that's in the GKTapper Sample Code and also provided in this tuts+ tutorial: http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-game-center-achievements-and-leaderboards-part-2/
This is the code:
- (void) callDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
assert([NSThread isMainThread]);
if([delegate respondsToSelector: selector])
{
if(arg != NULL)
{
[delegate performSelector: selector withObject: arg withObject: err];
}
else
{
[delegate performSelector: selector withObject: err];
}
}
else
{
NSLog(#"Missed Method");
}
}
My app always logs that "Missed Method" line, but I'm not sure what this callDelegate code is actually doing (so I can't fix it). I figure the best way forward is to learn what this is actually doing, and get better output than 'Missed Method'...
One caveat is that my app is currently using Game Center in sandbox mode, since I'm still developing it. This 'Missed Method' line might be expected in this situation - I'm not sure of that, either.
Would anybody be able to translate this code into paragraph form? I'm particularly unsure about the '[delegate respondsToSelector: selector]' piece.
Alternatively, would anybody be able to rewrite the NSLog line so that it outputs more/relevant detail about the problem? I tried this in the hopes of seeing which selector is not going through 'respondsToSelector' properly, but it didn't seem to work:
NSLog(#"Missed Method, %#", selector);
T'he best way to see exactly what is happening is putting a breakpoint at the beginning of callDelegate and then debugging your program, instead of simply running it. You can debug by pressing cmd-y.
Doing like this, each time your program enters the callDelegate function, it stops and the debugger window pops up. There you will be able to inspect where the call came from and what the parameters are.
As to a plain description of this function I would say that it is an helper function that wraps a call to a selector by preceding it with a check of existence of that selector. Instead of checking each time and the performing the selector, you call the helper function that will do both things for you.
So, the reason you always see the log line is that the function you would like to call is not there. By using the debugger you will be able to see which function it is, which class is missing it, and who attempted the operation.
Some comments requested further details about what I commented out to resolve this issue. I didn't think this was good to add as an edit to the question, since it specifically goes over the resolution. It's been a while since I've worked on this project, so it's not all at the top of my head & I'm not sure I've done everything correctly ... I'll do my best to explain it, though.
In the file GameCenterManager.h, it looks like authenticateLocalUser is being initialized:
- (void) authenticateLocalUser;
In the file App_NameViewController.m, viewDidLoad is checking to see if Game Center is available:
self.currentLeaderBoard = kLeaderboardID;
if ([GameCenterManager isGameCenterAvailable]) {
self.gameCenterManager = [[[GameCenterManager alloc] init] autorelease];
[self.gameCenterManager setDelegate:self];
[self.gameCenterManager authenticateLocalUser];
} else {
// The current device does not support Game Center.
}
In the file GameCenterManager.m
- (void) authenticateLocalUser
{
if([GKLocalPlayer localPlayer].authenticated == NO)
{
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error)
{
// report any unreported scores or achievements
[self retrieveScoresFromDevice];
[self retrieveAchievementsFromDevice];
//[self callDelegateOnMainThread: #selector(processGameCenterAuth:) withArg: NULL error: error];
}];
}
}
The line that I commented out, which moved me past the Missed Method error, was:
[self callDelegateOnMainThread: #selector(processGameCenterAuth:) withArg: NULL error: error];
I hope this helps!
Add this code to Game_CenterViewController.m you will see the error
- (void)processGameCenterAuth:(NSError *)error{
NSLog(#"error %#", error);
}

What causes "Missed Method" in this code?

Apologies ahead of time if this is a completely off-the-mark question, or if I'm not including enough information - I'm very new to iOS development (and Objective-C), and have a habit of jumping into the deep end...
I'm having trouble understanding the "callDelegate" code in GameCenterManager.m that's in the GKTapper Sample Code and also provided in this tuts+ tutorial: http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-game-center-achievements-and-leaderboards-part-2/
This is the code:
- (void) callDelegate: (SEL) selector withArg: (id) arg error: (NSError*) err
{
assert([NSThread isMainThread]);
if([delegate respondsToSelector: selector])
{
if(arg != NULL)
{
[delegate performSelector: selector withObject: arg withObject: err];
}
else
{
[delegate performSelector: selector withObject: err];
}
}
else
{
NSLog(#"Missed Method");
}
}
My app always logs that "Missed Method" line, but I'm not sure what this callDelegate code is actually doing (so I can't fix it). I figure the best way forward is to learn what this is actually doing, and get better output than 'Missed Method'...
One caveat is that my app is currently using Game Center in sandbox mode, since I'm still developing it. This 'Missed Method' line might be expected in this situation - I'm not sure of that, either.
Would anybody be able to translate this code into paragraph form? I'm particularly unsure about the '[delegate respondsToSelector: selector]' piece.
Alternatively, would anybody be able to rewrite the NSLog line so that it outputs more/relevant detail about the problem? I tried this in the hopes of seeing which selector is not going through 'respondsToSelector' properly, but it didn't seem to work:
NSLog(#"Missed Method, %#", selector);
T'he best way to see exactly what is happening is putting a breakpoint at the beginning of callDelegate and then debugging your program, instead of simply running it. You can debug by pressing cmd-y.
Doing like this, each time your program enters the callDelegate function, it stops and the debugger window pops up. There you will be able to inspect where the call came from and what the parameters are.
As to a plain description of this function I would say that it is an helper function that wraps a call to a selector by preceding it with a check of existence of that selector. Instead of checking each time and the performing the selector, you call the helper function that will do both things for you.
So, the reason you always see the log line is that the function you would like to call is not there. By using the debugger you will be able to see which function it is, which class is missing it, and who attempted the operation.
Some comments requested further details about what I commented out to resolve this issue. I didn't think this was good to add as an edit to the question, since it specifically goes over the resolution. It's been a while since I've worked on this project, so it's not all at the top of my head & I'm not sure I've done everything correctly ... I'll do my best to explain it, though.
In the file GameCenterManager.h, it looks like authenticateLocalUser is being initialized:
- (void) authenticateLocalUser;
In the file App_NameViewController.m, viewDidLoad is checking to see if Game Center is available:
self.currentLeaderBoard = kLeaderboardID;
if ([GameCenterManager isGameCenterAvailable]) {
self.gameCenterManager = [[[GameCenterManager alloc] init] autorelease];
[self.gameCenterManager setDelegate:self];
[self.gameCenterManager authenticateLocalUser];
} else {
// The current device does not support Game Center.
}
In the file GameCenterManager.m
- (void) authenticateLocalUser
{
if([GKLocalPlayer localPlayer].authenticated == NO)
{
[[GKLocalPlayer localPlayer] authenticateWithCompletionHandler:^(NSError *error)
{
// report any unreported scores or achievements
[self retrieveScoresFromDevice];
[self retrieveAchievementsFromDevice];
//[self callDelegateOnMainThread: #selector(processGameCenterAuth:) withArg: NULL error: error];
}];
}
}
The line that I commented out, which moved me past the Missed Method error, was:
[self callDelegateOnMainThread: #selector(processGameCenterAuth:) withArg: NULL error: error];
I hope this helps!
Add this code to Game_CenterViewController.m you will see the error
- (void)processGameCenterAuth:(NSError *)error{
NSLog(#"error %#", error);
}

need Database writing to happen in NSNotification call-back method

I make a call to a web service, passing a parameter and then register an observer in a viewcontroller class (to notify completion of download) :
[self callWebservice:parameter1];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dataDownloadComplete:) name:OP_DataComplete object:nil];
and then post a notification in my parser class:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection method of the parser class. [[NSNotificationCenter defaultCenter] postNotificationName:OP_DataComplete object:nil];
In the callback method dataDownloadComplete: i would like to call the same web service again several times.
-(void)dataDownloadComplete
{
if([anArray objectAtindex:N]<10)
{
[self callWebservice:parameterN];
NSLog(#"This is getting called everytime (9 times)");
[self writeintoDatabase];
N++;
}
}
But the problem is that i want to write into a database what data i download from the service. The DB writing happens for 'parameter1' call strangely, and goes on for the others but not for parameter9(which i need as well). Note the Log is called all 9 times though. The writeintoDatabase code is perfect. Please help. Thanks in advance.

UIProgressView update fail with UINotification

I try to solve this problem for several days now I have to ask you...
I've got a View (and a ViewController) with a UITableview. There is a TableViewController for that table which is generated in the ViewController. The TableViewController calls a DataSyncManager sharedInstant object (which is obviously in a separate class) which starts to sync data with the server.
I do it this way (first the refresh method):
-(void) refresh{
[serverQueueProgressView setProgress:0.0];
[syncingLabel setAlpha:0.5];
[serverQueueProgressView setAlpha:1];
[self performSelector:#selector(reloadTableViewDataSource) withObject:nil afterDelay:1.0];
}
Then the method reloadTableViewDataSource (of TableViewController) is called:
- (void)reloadTableViewDataSource
{
[dataSyncManager getEntriesFromServer];
}
dataSyncManager is my sharedInstance.
In the getEntriesFromServer method of dataSyncManager I do the loop with different sync items and call everytime
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ServerQueueProgress"
object:progress];
with the proper progress as NSNumber (that part works well). The message is now sent and catched by my ViewController (it works, I checked with a breakpoint, it also gets the right progress-NSNumber and converts it to float):
- (void)serverQueueProgress:(NSNotification *)notification {
if(![NSThread isMainThread])
{
[self performSelectorOnMainThread:_cmd withObject:notification waitUntilDone:NO];
return;
}
[queueProgressView setProgress:[[notification object] floatValue]];
}
This is one solution which I found here on stackoverflow. But the if is always skipped because obviously I'm on main thread.
Unfortunately the UIProgressview doesn't get updated, it just hangs around, but I connected it well in Interface Builder (I checked that by setting the progress in another method of ViewController.
I also tried to catch the Notification with my TableViewController and put in some other solutions, but no chance, the UIProgressView doesn't get updated live. Only after the sync is done.
Here is the mentioned code in TableViewController which also gets executed without errors (I also stepped it to make sure every line gehts executed well):
This is the method called when received a the notification:
- (void)serverQueueProgress:(NSNotification *)notification {
[self performSelectorOnMainThread:#selector(updateProgress:) withObject:[notification object] waitUntilDone:NO];
[serverQueueProgressView setProgress:[[notification object] floatValue]];
}
Which also calls updateProgress: of the same class:
- (void)updateProgress:(NSNumber *)newProgressValue {
[serverQueueProgressView setProgress:[newProgressValue floatValue]];
}
No chance. I tried many ways and implemented some in parallel as you see, but the ProgressView won't get updated live. Only at the end of syncing. What am I doing wrong??
EDIT: Here is my getEntriesFromServer and some other stuff in DataSyncManager:
- (void)getEntriesFromServer
{
[[NSNotificationCenter defaultCenter]
postNotificationName:#"SynchingStarted"
object:nil];
[self completeServerQueue];
...
}
and completeServerQueue is the function which sends messages to my ViewController with the proper progress float value (it's only a dummy for loop, which gets executed properly... I've checked it):
- (void)completeServerQueue {
NSNumber *progress = [[NSNumber alloc] init];
for (int i=0; i<15; i++) {
progress = [[NSNumber alloc] initWithFloat:(100/15*i) ];
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ServerQueueProgress"
object:progress];
sleep(1);
}
}
also, when you're having trouble, break the problem down a bit. Instead of:
[serverQueueProgressView setProgress:[[notification object] floatValue]];
do this;
float prog = [notification object] floatValue];
[serverQueueProgressView setProgress:prog];
then debugging would give a clue that this isn't working.
my guess is the problem isn't the code you've shown here, but other code in getEntriesFromServer. Are you using NSURLConnection? Something like:
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
then you will get callbacks asynchronously that you can use to update your progress view.

Timed selector never performed

I've added an observer for my method:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(closeViewAfterUpdating)
name:#"labelUpdatedShouldReturn"
object:nil];
Then my relevant methods:
-(void)closeViewAfterUpdating; {
NSLog(#"Part 1 called");
[self performSelector:#selector(closeViewAfterUpdating2) withObject:nil afterDelay:2.0];
}
-(void)closeViewAfterUpdating2; {
NSLog(#"Part 2 called");
[self dismissModalViewControllerAnimated:YES];
}
The only reason why I've split this method into two parts is so that I can have a delay before the method is fired.
The problem is, the second method is never called. My NSLog output shows Part 1 called, but it never fires part 2. Any ideas?
EDIT: I'm calling the notification from a background thread, does that make a difference by any chance?
Here's how I'm creating my background thread:
[NSThread detachNewThreadSelector:#selector(getWeather) toTarget:self withObject:nil];
and in getWeather I have:
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateZipLabel" object:textfield.text];
Also, calling:
[self performSelector:#selector(closeViewAfterUpdating2) withObject:nil];
does work.
EDITx2: I fixed it. Just needed to post the notification in my main thread and it worked just fine.
The background thread is the problem. It has a non running run loop, thus the selector is never called. Just let the NSRunLoop or CFRunLoopRef object of the thread run while the selector isn't fired.
I tried your code and it works fine on my side. You might be doing something funky in the background that is interrupting your selector.
You have a semi-colon in the method definition:
-(void)closeViewAfterUpdating2; {
Is this present in the code or a copy/paste issue? That would be the problem on why you never see it called.