Incrementing `static int` causes SIGSEGV SEGV_ACCERR
I'm debugging a crash reported as:
Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR
The crash is happening on the line that does numberOfFails++
.
The app uses ASIHTTP
. I personally much prefer using NSURLConnection
. I'd never automatically repeat a request for NSURLConnection
if it failed because I've never seen it fail when it shouldn't. I'd rather just give the UI a refresh button or show a UIAlertView
with a button to try again or something like that.
Anyway, to cooperate with other team members, I'm looking to fix this issue without replacing ASIHTTP
with NSURLConnection
for now.
The request is being started with something like:
- (void)getResources:(CLLocation *)location withQuery:(NSString *)query {
NSURL *url = [NSURL URLWithString:[NSString stringWithString:@"https://example.com/"]];
self.resourcesAPIRequest = [ASIFormDataRequest requestWithURL:url];
[resourcesAPIRequest setPostValue:[Model instance].oauth_token forKey:@"oauth_token"];
[resourcesAPIRequest setPostValue:[[NSNumber numberWithDouble:location.coordinate.latitude] stringValue] forKey:@"latitude"];
[resourcesAPIRequest setPostValue:[[NSNumber numberWithDouble:locatio开发者_开发百科n.coordinate.longitude] stringValue] forKey:@"longitude"];
[resourcesAPIRequest setPostValue:query forKey:@"query"];
[resourcesAPIRequest setDelegate:self];
[resourcesAPIRequest setDidFinishSelector:@selector(resourcesAPIReturned:)];
resourcesAPIRequest.userInfo = [NSDictionary dictionaryWithObjectsAndKeys:NSStringFromSelector(@selector(getResources:withQuery:)), @"repeatSelector", location, @"argument1", query, @"argument2", nil];
[resourcesAPIRequest startAsynchronous];
}
One thing I noticed is : <ASIHTTPRequestDelegate>
is not in the header file, but this callback method is still being called OK:
#define maximumNumberOfFails 50
- (void)requestFailed:(ASIFormDataRequest *)request {
static int numberOfFails = 0;
if (numberOfFails < maximumNumberOfFails) {
[NSThread sleepForTimeInterval:sleepTimeInSeconds];
if ([request.userInfo objectForKey:@"argument2"]) {
[self performSelector:NSSelectorFromString([request.userInfo objectForKey:@"repeatSelector"]) withObject:[request.userInfo objectForKey:@"argument1"] withObject:[request.userInfo objectForKey:@"argument2"]];
} else if ([request.userInfo objectForKey:@"argument1"]) {
[self performSelector:NSSelectorFromString([request.userInfo objectForKey:@"repeatSelector"]) withObject:[request.userInfo objectForKey:@"argument1"]];
} else {
[self performSelector:NSSelectorFromString([request.userInfo objectForKey:@"repeatSelector"])];
}
numberOfFails++;
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Problem" message:@"There was a problem connecting to the servers. Please make sure you have an Internet connection." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
[alert show];
[alert release];
numberOfFails = 0;
}
}
Also, I think that static int numberOfFails
should be static NSUInteger numberOfFails
. And, I noticed that the request is started with startAsynchronous
. Is static int numberOfFails
atomic? That may be why we're getting the error SEGV_ACCERR
(Invalid permissions for mapped object).
Thoughts?
The problem likely has nothing to do with your static variable.
Does requestFailed:
execute on the main thread, or in a background thread?
If it's on a background thread, you'll need to use performSelectorOnMainThread:withObject:
.
If it's on the main thread, you may need to take a pass through the runloop before executing a new HTTP request. To do that, use performSelector:withObject:afterDelay:
, and pass '0.0' as the delay.
You'll notice that both those methods allow only a single method parameter. Typically, you pass your parameters in a NSDictionary
rather than try to parse out the number of parameters beforehand, like you're doing.
精彩评论