问题
I have hunted around a lot on posts to do with NSURLConnection and more generally SIGABRT debugging but have had no joy on this. Any help is greatly appreciated.
So, at the start of my app the user is presented with a login view and on supplying user name and password I start an NSURLConnection by doing the following in a LoginService class:
-(void)loginWithURLRequest:(NSString*)requestString
{
if(self.mConnection == nil)
{
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:120.0];
self.mConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
}
}
-(void)discardLoginDataAndPrepareToReceiveMore
{
// Releases old mLoginData and assigns a new empty one.
self.mLoginData = [[NSMutableData alloc] init];
}
-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
[self discardLoginDataAndPrepareToReceiveMore];
}
-(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
[mLoginData appendData:data];
}
-(void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
{
[self discardLoginDataAndPrepareToReceiveMore];
[mDelegate onLoginFailure:error];
self.mConnection = nil;
}
-(void)connectionDidFinishLoading:(NSURLConnection*)connection
{
[mDataReader performSelector:mDataReaderSelector withObject:mLoginData];
[mDelegate onLoggedInSuccessfully];
self.mConnection = nil;
}
So this all works just fine. Problem is later I try to POST a request (from within a different class) and shortly afterwards the app crashes with a SIGABRT in a load of assembly on a separate thread which I cannot trace back to my code. I realise the NSURLConnection is run on another thread etc.
So I thought maybe it's something wrong with my post code and replaced it with the exact same login connection code below :
NSString* requestString = @"identical URL as before in login";
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestString]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:120.0];
self.mConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease];
Same problem, so my last try was to see if somehow the 1st login was messing things up. i.e. maybe I didn't know something about connections and was not cleaning up properly etc. So I disabled the 1st login and left my 2nd one in and then it works fine and I get my callbacks in the delegate methods etc.
Any tips on what I could be doing wrong. There seems to be something I am not doing during/after the 1st connection is made that causes the second to crash.
I can step over the 2nd NSURConnection in the app when the 1st login is still present. The actual crash occurs shortly after telling the app to continue after this connection is made.
In both cases the mConnection is a (nonatomic, retained) property of each class respectively.
I realise that there are better ways of handling multiple connections (after my searching around) which I will need to employ soon anyway, but I need to get this working for a demo for a client and am also curious as to what is going wrong in case it implies a more fundamental misunderstanding of connections etc on my part.
Hmm, I guess also I also lacking knowledge about how I should go about debugging this. Any instruments tips for this would be appreciated. I avoided using allocations in the performance tool since SIGABRT is not an issue caused by leaks if my understanding is correct?
Additionally here's the call stack:
-#0 0x90d7e132 in kill
-#1 0x90d7e124 in kill$UNIX2003
-#2 0x90e108e5 in raise
-#3 0x90e2699c in abort
-#4 0x90d23d35 in free
-#5 0x026fc081 in __CFStringDeallocate
-#6 0x026fbccb in _CFRelease
-#7 0x02720c9d in _CFAutoreleasePoolPop
-#8 0x0004fe67 in -[NSAutoreleasePool release]
-#9 0x00300e7f in _UIApplicationHandleEvent
-#10 0x030c4822 in PurpleEventCallback
-#11 0x027c5ff4 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION
-#12 0x02726807 in __CFRunLoopDoSource1
-#13 0x02723a93 in __CFRunLoopRun
-#14 0x02723350 in CFRunLoopRunSpecific
-#15 0x02723271 in CFRunLoopRunInMode
-#16 0x030c300c in GSEventRunModal
-#17 0x030c30d1 in GSEventRun
-#18 0x00304af2 in UIApplicationMain
-#19 0x0000242c in main at main.m:14
I assume that this means (when I look at my comment below also) that I am not calling alloc on something (maybe a string) before I release it?
回答1:
It's a tough one to pinpoint without the whole source, but it seems like you're calling a second (and invalid) release on an NSString object. Take a look at how you're treating strings throughout your project. Be sure that they have the 'copy' attribute in your property declarations and you're not unnecessarily releasing the ones that are already autoreleased. (i.e. the ones with created [NSString stringWithFormat:])
回答2:
Have you run your app with zombies enabled? It is possibly an over-release, which zombies will pick up.
Another way to track this down would be to enable malloc history, and check out where the bad pointer (0x818c0b0 in your comment) is coming from.
This may be useful to you: iPhone - debugging "pointer being freed was not allocated" errors
It looks as though memory is being corrupted inside an CFString
/NSString
object, which means that it could be occurring somewhere that looks completely unrelated. You could be passing a bad pointer into an NSString
, so you might want to check for that too.
Also, what's the value of mDataReaderSelector
? If you do a performSelector:
and the method returns a struct (e.g. NSRect) that can possibly corrupt memory. It's a long shot, but I thought I'd check anyway.
回答3:
fixed after enabling Zombie (which I thought only tracked leaks and not also double frees/autoreleases). I was autoreleasing a string that didn't need it.
Thanks to TomDalling and drowntoge, you were both on the right tracks. I just got there then saw your answers (as I was posting this)which for sure would have got me there soon anyway. I was not aware that stringWithFormat autoreleased and was autoreleasing one anyway. Only really just started using auto release and used to assign to locals and release them after assigning said local to my retained properties. Which is also fine just not so tidy in code. I guess i had a lot of leaks before that I was unaware of. I had read the docs on memory stuff a while back but just never used the autorelease so I think I need to go back over them again :-)
Still have no idea how the initial connection manifested the problem when enabled since the 2nd connection is a good while later. Completely threw me as I thought it was all about my understanding of connections. The string in question was in and around this code though. hmm anyway, cheers guys.
来源:https://stackoverflow.com/questions/4244263/2nd-use-of-nsurlconnection-causes-sigabrt-iphone