I am having problem releasing NSMutableURLRequest object.
Application crashes during the deallocation of request object.
The object is created via [[NSMutableURLRequest alloc] initWithURL:my_http_url];
As mainstream flow of control, I try to release the connection object in response to connectionDidFinishLoading handler being invoked.
At first I tried autoreleasing NSMutableURLRequest right inside connectionDidFinishLoading handler. This caused crashing, so I assumed it might be because connection class pushes autorelease pool internally before calling connectionDidFinishLoading and still expects connection object to be valid when the handler returns, so it is impossible then to release or autorelease the connection object inside connectionDidFinishLoading.
If I do not release NSMutableURLRequest at all, according to Instruments it leaks with reference count 1.
Therefore I decided to do a delayed release via firing an NSRunLoop event that autoreleases NSMutableURLRequest passed to it.
This still causes a crash.
retainCount before calling autorelease is 1.
Crash stack is:
#
0 0x9448aedb in objc_msgSend
#1 0x04a47ce0 in ??
#2 0x02e51501 in HTTPMessage::~HTTPMessage
#3 0x02945621 in _CFRelease
#4 0x02e516a9 in HTTPRequest::~HTTPRequest
#5 0x02e50967 in URLRequest::~URLRequest
#6 0x02945621 in _CFRelease
#7 0x0032fb70 in -[NSURLRequestInternal dealloc]
#8 0x0032fb1a in -[NSURLRequest dealloc]
#9 0x002f27a5 in NSPopAutoreleasePool
#10 0x003b5dd0 in __NSFirePerformTimer
#11 0x0299e8a2 in __CFRunLoopDoObservers
#12 0x0296a39e in CFRunLoopRunSpecific
#13 0x0296a048 in CFRunLoopRunInMode
#14 0x031d289d in GSEventRunModal
#15 0x031d2962 in GSEventRun
#16 0x0058ede1 in UIApplicationMain
#17 0x00002b9c in main at main.m:14
Thanks for advise.
After using NSDebugEnabled/NSZombieEnabled/NSAutoreleaseFreedObjectCheckEnabled I identified the problem:
result of
http_url = [NSURL URLWithString:...]
should have been either retained or not autoreleased on its own.
Try to instantiate it as an autoreleased object using:
[NSMutableURLRequest requestWithURL:my_http_url];
I believe Instruments are not useful for any tracing in this case since the
application crashes and then is auto-restarted (it's iPad/iPhone app), so all
Intruments history is gone.
I do not see much point instantiating NSMutableURLRequest as autoreleased object
since it needs to be retained for the duration of async call spanning multiple
idle loop cycles. NSURLConnection may retain it internally or not, but keeping
an extra reference for safety should not hurt.
The initialization code boils down to essentially the following:
rq->url_encoded = [url_encode(rq->url) retain];
rq->http_url = [NSURL URLWithString:rq->url_encoded];
rq->http_request = [[NSMutableURLRequest alloc] initWithURL:rq->http_url];
[rq->http_request setHTTPMethod:#"GET"];
NSArray* availableCookies = [rq->service.CookieJar cookiesForURL:rq->http_url];
NSDictionary* headers = [NSHTTPCookie
requestHeaderFieldsWithCookies:availableCookies];
[rq->http_request setAllHTTPHeaderFields:headers];
rq->http_connection = [NSURLConnection alloc];
[rq->http_connection initWithRequest:rq->http_request delegate:rq
startImmediately:YES];
The release procedure is that connectionDidFinishLoading calls [rq->http_connection
cancel] and [rq autorelease], the latter eventually leading to:
// [http_request autorelease];
// delayedAutoRelease(http_request);
[http_connection autorelease];
[http_url autorelease];
[url release];
[url_encoded release];
[response release];
Note that [response release] just pairs previous [response retain] executed inside didReceiveResponse.
If I leave first two lines commented out, NSURLRequest leaks with reference
count 1 per Instruments, and this is the only leak observed.
Whenever I attempt to autorelease http_request whichever way as described above,
a crash occurs.
Related
I'm running into an issue with loadable bundles and KVO. It seems that any class that has KVO observers attached to an instance of it cannot be safely be unloaded via NSBundle's -unload method.
I'm doing the following:
for (int i = 0; i < 100; i++)
{
[bundle load];
Class bundleClass = [bundle principalClass];
[[[bundleClass alloc] init] release];
[bundle unload];
}
And in the bundle's principle class -init method,
[self addObserver: self
forKeyPath: #"name"
options: 0
context: nil];
self.name = #"jim";
The loop gets through a number of iterations, sometimes crashing on the second time round, sometimes on the thirtieth.
It always crashes with this backtrace, with the EXC_BAD_ACCESS signal.
#0 0x00007fff8a30deab in objc_msgSend ()
#1 0x00007fff8609d862 in NSKeyValueNotifyObserver ()
#2 0x00007fff860be99b in NSKeyValueDidChange ()
#3 0x00007fff8606b0fb in -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] ()
#4 0x00000001007a4c2c in -[Bundle init] (self=0x101902130, _cmd=0x7fff8ea369b0) at /Users/joerick/Desktop/bundleTest/testbundle/Bundle.m:26
#5 0x0000000100001731 in -[SIAppDelegate applicationDidFinishLaunching:] (self=0x100326a90, _cmd=0x7fff876e285f, aNotification=0x100131ea0) at /Users/joerick/Desktop/bundleTest/bundleTest/SIAppDelegate.m:28
#6 0x00007fff8606ade2 in __-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_1 ()
#7 0x00007fff8b470e0a in _CFXNotificationPost ()
#8 0x00007fff86057097 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#9 0x00007fff8e1bbaa7 in -[NSApplication _postDidFinishNotification] ()
#10 0x00007fff8e1bb80d in -[NSApplication _sendFinishLaunchingNotification] ()
....
Full code here
You can download a sample project showing this issue here.
I'm thinking that this is a bug in Cocoa, but I wonder if anybody could see if I'm doing anything stupid here?
I've reported this to Apple.
rdar://11017946
I've a problem with an app for Mac that I'm writing in Objective-c.
I've this situation:
In main thread (GUI):
ftEngine = [[FileT alloc] init];
[ftEngine setParameters:searchWord selectedEngine:[[pbEngines selectedItem] title] actualPage:0];
NSThread* thFileT = [[NSThread alloc] initWithTarget:ftEngine selector:#selector(setTotalResult) object:nil]; [thFileT start];
In child (ftEngine previous declared):
-(void)setTotalResult {
NSError* nsError = nil;
NSURL* urlCompleteUrl = [NSURL URLWithString:m_completeSearchWord];
}
m_completeSearchWord is initialized by setParameters function previously utilized.
And now.. my problem is:
When thread is started, it call setTotalResult function and i'll get an exception when I try to use m_completeSearchWord.
It's strange becacuse if I don't use a thread, all works correctly!
Exception is:
2011-09-08 23:24:06.731 GUI[12935:1a07] *** -[CFString respondsToSelector:]: message sent to deallocated instance 0x1003cc650
It sounds like you may not have retained m_completeSearchWord correctly when you initialized it. Add the body of -setParameters if you want help confirming that.
When calling selectors in a new thread, make sure that the selector has been properly wrapped with an autorelease pool :
-(void) setTotalResult {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
...
[pool release];
}
I see all manner of memory related issues when I forget to add the pool and your error definitely rings a bell.
An iPad app that runs fine under IOS3 fails under IOS4.2 It has a class that runs an http session from an operation queue and the failure is linked to this activity. Here is the console output:
Program received signal: “EXC_BAD_ACCESS”.
[Switching to thread 11523]
Running NSZombies enabled didn't reveal anything so I have been putting NSLog statements in the code and found that the crash occurs when a local variable is changed. Here is the code section:
self.currentOperation = [[[DeduceAccessOperation alloc] init] autorelease];
[self.currentOperation addObserver:self forKeyPath:#"isFinished"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
context:NULL];
NSLog (#"Start observer added");
[operationQueue addOperation:self.currentOperation];
NSLog (#"Start operation added");
NSLog(#"State is %d", self.status);
self.status = IEnablerServiceUpdating;
NSLog (#"State updated");
And here is the console log output:
2010-12-08 21:26:44.548 UCiEnabler[5180:307] Start observer added
2010-12-08 21:26:44.550 UCiEnabler[5180:307] Start operation added
2010-12-08 21:26:44.552 UCiEnabler[5180:307] State is 1
Program received signal: “EXC_BAD_ACCESS”.
[Switching to thread 11523]
It is like status has become read-only (It's property is declared as atomic and readwrite).
The other relevant piece of information is that a sub-view has just been changed and it triggers the call on the above routine. It's code is:
//Start the update
UCiEnablerAppDelegate *controller = (UCiEnablerAppDelegate *)[[UIApplication sharedApplication] delegate];
[controller deduceIEnablerServiceAccess];
controller.serviceBusy = TRUE; //1.04
Has anyone seen anything like this?
Has anyone ideas where to look next?
Regards
Robin
Here's the stack trace:
#0 0x34a80464 in objc_msgSend
#1 0x3119543e in NSKVOPendingNotificationCreate
#2 0x3119535a in NSKeyValuePushPendingNotificationPerThread
#3 0x3117009a in NSKeyValueWillChange
#4 0x311682c6 in -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:]
#5 0x311cc718 in _NSSetIntValueAndNotify
#6 0x000097ce in -[IEnablerService startDeducingAccessState] at IEnablerService.m:55
#7 0x00002bc0 in -[UCiEnablerAppDelegate deduceIEnablerServiceAccess] at UCiEnablerAppDelegate.m:100
#8 0x0000a33e in -[RootViewControlleriPad animationDidStop:finished:context:] at RootViewController-iPad.m:43
#9 0x341bb336 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
NSOperationQueue in iOS 4.2 now uses GrandCentralDispatch when starting NSOperations. There's a Technical Q&A here
Pretty much the queue now calls the NSOperation subclass's start method in a new thread regardless of the isConcurrent property. In my experience it means that if you are using NSURLConnection inside a start method your code will no longer run because the thread start is running on doesn't have an NSRunLoop.
Apple says that this change doesn't break compatibility because you were supposed to spawn a new thread in the start method anyway.
For backwards compatibility you should change your subclass from using start to using run.
I'm just starting out on my first 'real' cocoa app. Note that this is Mac, not iPhone.
This function is called when my async download of onemanga finishes, and is intended to parse an NSArray list of manga from it. I get a NSArray from nodesForXPath, and retain it to make sure it's mine. (Also tried retaining it twice, heh). Unfortunately, trying to retrieve the count of the NSArray causes an EXC_BAD_ACCESS. The point of crashing is marked by two comments below.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Download Succeeded! Received %d bytes of data. Beginning Parse.",[mangaListData length]);
NSString* theQuery = [[NSString alloc]initWithString:#"//tr/td[#class=\"ch-subject\"]/text()"];
NSError *XMLError=nil;
NSError *XPathError=nil;
NSString* mangaListHTML;
NSString* fixedMangaListHTML;
mangaListHTML = [[NSString alloc] initWithData:mangaListData encoding:NSUTF8StringEncoding];
fixedMangaListHTML = [mangaListHTML stringByReplacingOccurrencesOfString:#" & " withString:#" & "];
NSXMLDocument* xmlDoc = [[NSXMLDocument alloc] initWithXMLString:fixedMangaListHTML
options:(NSXMLNodePreserveWhitespace|NSXMLNodePreserveCDATA)
error:&XMLError];
if (XMLError) {
NSLog(#"XML Parse error: %#", XMLError);
return;
};
[fixedMangaListHTML release];
[mangaListHTML release];
NSArray* results = [[xmlDoc nodesForXPath:theQuery error:&XPathError] retain];
if (XMLError) {
NSLog(#"Parse error: %#", XPathError);
return;
};
NSLog(#"Parsing complete. Manga List = ");
//CRASH HAPPENS HERE
NSLog(#"Size of array: %#", [results count]);
//CRASH HAPPENS ABOVE
for(NSXMLNode* title in results){
NSLog(#"%#\n", title.description);
};
[XMLError release];
[XPathError release];
[connection release];
[mangaListData release];
}
Heres the output of where in gdb. (I don't really know how to use gdb yet, so any commands I could run to get more info here would be highly appreciated.)
#0 0x00007fff855691d1 in objc_msgSend_vtable5 ()
#1 0x00007fff87e97207 in _NSDescriptionWithLocaleFunc ()
#2 0x00007fff8509ba2d in _CFStringAppendFormatAndArgumentsAux ()
#3 0x00007fff8509aead in _CFStringCreateWithFormatAndArgumentsAux ()
#4 0x00007fff85119f5f in _CFLogvEx ()
#5 0x00007fff87ef937f in NSLogv ()
#6 0x00007fff87ef9317 in NSLog ()
#7 0x0000000100002bca in -[TMMoneManga connectionDidFinishLoading:] (self=0x1001999f0, _cmd=0x7fff8803b5de, connection=0x1001689a0) at /Users/ripdog/Documents/TheMangaMachine/TMMoneManga.m:120
#8 0x00007fff87f16b8c in _NSURLConnectionDidFinishLoading ()
#9 0x00007fff8063f18e in URLConnectionClient::_clientDidFinishLoading ()
#10 0x00007fff806a4502 in URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload ()
#11 0x00007fff8062b8fb in URLConnectionClient::processEvents ()
#12 0x00007fff8062b6d8 in MultiplexerSource::perform ()
#13 0x00007fff850b6f21 in __CFRunLoopDoSources0 ()
#14 0x00007fff850b5119 in __CFRunLoopRun ()
#15 0x00007fff850b48df in CFRunLoopRunSpecific ()
#16 0x00007fff80b83ada in RunCurrentEventLoopInMode ()
#17 0x00007fff80b838df in ReceiveNextEventCommon ()
#18 0x00007fff80b83798 in BlockUntilNextEventMatchingListInMode ()
#19 0x00007fff8845fa2a in _DPSNextEvent ()
#20 0x00007fff8845f379 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#21 0x00007fff8842505b in -[NSApplication run] ()
#22 0x00007fff8841dd7c in NSApplicationMain ()
#23 0x00000001000017cd in main (argc=1, argv=0x7fff5fbff6c0) at /Users/ripdog/Documents/TheMangaMachine/main.m:13
Thanks a lot in advance.
The problem is with your format string. The %# specifier will display an Objective-C object, but [result count] is an integer. The correct format specifier for an integer is %d.
For reference, here is a complete list of Objective-C string format specifiers.
Your question indicated that the crash happens when you try to retrieve [result count]. However if you look at the call stack, your code is frame #7, and the next function on the stack (frame #6) is NSLog. So this tells you the problem is probably something to do with the call to NSLog, and not [result count]. [result count] will already have returned before control flow enters NSLog.
There are various techniques for debugging with gdb. Since you are debugging a crash, your focus will mostly be on examining the call stack, variables and memory (as opposed to stepping through your code as it executes.) So for this kind of debugging, these commands are essential:
up This moves the "focus" of the debugger up one frame of the call stack. Let's say you want to examine the variables in your program. You can't see them in objc_msgSend_vtable5 which is where the debugger is stopped. So use up 7 to jump up seven frames so you're looking at your code.
down Is the opposite of up. Oftentimes you want to look at what led to disaster, so jumping up to your code and then going down, down, down is a way to get an understanding of how disaster unfolded. (This isn't moving you forward and backward in time, of course.)
where Shows you part of the call stack. You already discovered this. My only tip is that you often only care about what's on the top of the call stack. You can use where n to print the first n frames of the call stack.
list Shows you the source code of the "focussed" frame, with an arrow indicating the execution point. So, for example, up 7 followed by list should show you the source of connectionDidFinishLoading with an indicator next to the call to NSLog. Using list is often more convenient than finding the code in XCode, if you just need to see a few lines of the surrounding context.
print Evaluates an expression and prints it. For example, you could do print [results count] to see what [results count] evaluates to. When the debugger is stopped with your program is in a bad state, print can act funny (it can really run code.) So often simple expressions work better.
info Info can tell you lots of things, but info locals is really valuable. It shows you the local variables that are in scope in the "focussed" frame of the debugger.
count returns an integer, not an object. Print it with %d not %#.
(If you do the latter, you implicitly convert the integer to a pointer to a non-existent object in the wilds of who knows where, and then invoke its description method.)
I read this in a book.
-(IBAction) updateTweets
{
tweetsView.text = #"";
[tweetsData release];
tweetsData = [[NSMutableData alloc] init];
NSURL *url = [NSURL URLWithString:#"http://twitter.com/statuses/public_timeline.xml" ];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL: url];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[connection release];
[request release];
[activityIndicator startAnimating];
}
In this statement,is that correct to release the "connection" instance at that time? After releasing it which means this NSURLConnection instance will be destroyed since it's reference count is 0 ,how are we going to make this connection operation work after release this instance? THANKS.
I thought we should release it in one of the following callback methods,right?
connectionDidFinishLoading:
connection:didFailWithError:
It's actually fine to release it there, once the connection is sent out via initWithRequest, the only thing that matters is that the delegate exists or I believe the response will just be silently lost.
From what I can tell, the only reason to not release it there is if you want to call [connection cancel] at some point in one of the delegate functions, in which case it would be best to do what you suggest and release it in BOTH connectionDidFinishLoading and didFailWithError since only one of them will be called (right?).
Edit: For a more thorough answer, NSURLConnection initWithRequest is an asynchronous request. So it actually spawns it's own thread (but calls the delegate functions on the thread that called initWithRequest). So basically, on the thread that calls initWithRequest you are actually done with the connection object and you can release it. All the while it's doing stuff on some other thread that you don't need to be concerned with.
Also I should note that if you do release it there, make sure you DON'T release it in the finish/fail methods, because it won't be a valid object.