EXC_BAD_ACCESS with NSAutoReleasePool - iphone

I am detaching a new thread
[NSThread detachNewThreadSelector:#selector(loadAvatar) toTarget:self withObject:nil];
I am getting an EXC_BAD_ACCESS on
STObject* st = [cellitem get:#"stobject"];
In my following method
-(void)loadAvatar
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
STObject* st = [cellitem get:#"stobject"];
//do stuff...
[pool release];
}
I have tried retaining st but no luck. When I run this code without detaching a new thread I have no problems. I am not really sure what I am missing.
UPDATE
cellitem is a subclass of NSObject that contains some properties such as a dictionary and strings.
The get method basically returns a string from a dictionary

Retaining st is not going to do you much good, since the EXC_BAD_ACCESS error originates from before the assignment takes place. The problem lies either with accessing cellItem or in your get method. Either way you are likely trying to access an object that has already been released. Try running Instruments with zombie detection enabled.

Not exactly sure why this solution works, but I told my thread to sleep for 0.1 seconds and it seems to solve all of the problems.
[NSThread detachNewThreadSelector:#selector(loadAvatar) toTarget:self withObject:nil];
[NSThread sleepForTimeInterval:0.1];
Does anyone know why this is so? I am guessing sleeping prevents some object from being released too early? Could be a hacky fix.

Related

Using NSThread in this code piece

I am working on someone else's code. I came across a line of code
[NSThread detachNewThreadSelector:#selector(myMethod) toTarget:self withObject:nil];
I have 2 questions to ask.
Its just calling a method. Why is NSThread used here?
While running the code, On some instances, this method doesn't get called. When I put a breakpoint inside the method, it always get called. But if I remove the breakpoint, on some instances the method doesn't get called. Is this the problem of NSThread?
Using NSThread in this way means that the method "myMethod" is being called on a background thread, concurrently with the rest of the code. It is equivalent to this, which you may also have seen:
[self performSelectorInBackground:#selector(myMethod) withObject:nil];
If the method is not getting called (or seeming to not get called), it may be down to concurrency issues, i.e. the fact that the execution order of that method and ones you call after in on the main thread is not guaranteed, so you are expecting it to be called earlier than it actually is.
If you say:
[NSThread detachNewThreadSelector:#selector(methodA) toTarget:self withObject:nil];
[self methodB];
Then methodA and methodB will be running at the same time and there is no guarantee that methodA will finish before methodB.
I always use NSThread detachNewThreadSelector in combination with an auto-release pool, like so:
-(void)myMethod {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
// .. Do stuff in this thread
[pool release];
};
If you want to "simply" perform a selector, do it like this:
[self performSelector:#selector(myMethod)];

object is leaking. NSAutorelease pool

i got an message at my log file (GDB) as object is leaking...
NsAutorelease pool.. like something nearly for 10 times.
Can anyone explain me. why this message is displaying..?
Thanks in advance.
It means you are autoreleasing objects with no autorelease pool in place. So those objects are not being released, and are probably leaking as a result.
So you should make sure you have a pool in place.
I generally use:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Your autoreleased objects
[pool release];
But it depends on where in your code you're running in to the issue... Are you using multi-threading? Or is everything happening in the main thread?

How to handle leaks when using a multiple threads in iphone?

I have called a method in separate thread in viewdidload method
[NSThread detachNewThreadSelector:#selector(callWebService) toTarget:self withObject:nil];
-(void)callWebService{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread detachNewThreadSelector:#selector(loadImages) toTarget:self withObject:nil];
[pool release];
}
-(void)loadImages{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self performSelectorOnMainThread:#selector(reloadTable) withObject:nil waitUntilDone:false];
[pool release];
}
-(void)reloadTable
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[myTableView reloadData];
[pool release];
}
How to handle leaks while using thread? I want to use threads.
Errors
*** __NSAutoreleaseNoPool(): Object 0x604b830 of class NSCFString autoreleased with no pool in place - just leaking
*** -[NSAutoreleasePool release]: This pool has already been drained, do not release it (double release).
The autorelease pool must be drain, not release. So I think if you change it to [pool drain] it should be working fine.
Don't know if you found your answer yet, but as I had hit something similar to your problem, I did some looking. It seems that when you drain a pool, that is (effectively) equivalent to releasing it. The documentation on the class says:
Since you cannot retain an autorelease pool (or autorelease it—see
retain and autorelease), draining a pool ultimately has the effect of
deallocating it.
So, you should only drain a pool once. If you need another context after that point, you should generate a new pool in the same way you generated one earlier in your code.
If there is no pool available, then you can end up leaking (as you mentioned). However, autorelease calls should log a warning message in that instance. Regarding threads, the documentation has this to say
The Application Kit creates an autorelease pool on the main thread at
the beginning of every cycle of the event loop, and drains it at the
end, thereby releasing any autoreleased objects generated while
processing an event. If you use the Application Kit, you therefore
typically don’t have to create your own pools. If your application
creates a lot of temporary autoreleased objects within the event loop,
however, it may be beneficial to create “local” autorelease pools to
help to minimize the peak memory footprint.
Hope this helps.

PerformSelectorInBackground leaking on device

While it seems to not pose a problem on the simulator, using performSelectorInBackground on the device causes memory leaks. Or at least that's what Instruments indicates. Looking at the code I don't have a single clue what the cause could be.
I tried to strip the affected code to a bare minimum but still strangely Instruments keeps showing a leak every time this piece of code is executed.
Anything unusual going on here?
//In viewcontrollerA:
-(void)mainLoop
{
[self.viewControllerB performSelectorInBackground:#selector(calculateTotals) withObject:nil];
//This gives the same problem
//[NSThread detachNewThreadSelector:#selector(calculateTotals) toTarget:self.viewControllerB withObject:nil];
//UI stuff ...
}
//viewControllerB:
-(void)calculateTotals
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Heavy calculations ...
[pool release];
}
Edit:
I'm still looking into this and it seems that the leak is caused by the fact that somewhere down the stack [NSThread start] is never followed by [NSThread exit]. So it appears like there is occasionally a thread which is kept running without ever ending it.
Now my question is, is there something I could do to make end those 'hanging' threats manually?
Perhaps one of your threads is throwing an exception? Exceptions in threads don't get reported in the debug console, you have to catch the exception in the thread.

NSThread, NSTimer and AutoreleasePools in an iPhone SDK application

I want to create an appilication in iPhone in which I want to use NSThread. I have created one thread using
[NSThread detachNewThreadSelector:#selector(doThread:)
toTarget:self
withObject:nil];
I want that my one thread will handle all the touches and other user interaction and the second thread handle the NSTimer. So, In doThread() I have allocate NSTimer like,
-(void) doThread:(NSString *)poststring {
NSLog(#"create thread:");
[lock lock];
T1 = [NSTimer scheduledTimerWithTimeInterval:(5)
target : self
selector:#selector(onTimer)
userInfo : nil
repeats : YES];
NSLog(#"after timer");
usleep(1);
[lock unlock];
}
In onTImer,
-(void)onTimer
{
NSLog(#"in timer");
}
Now I can't able to call the onTimer method of NSTimer. But I can see the "after timer" printed in the log.Is that anything that I can't use the NSTimer within the thread?
This is also I can get while execution.
NSAutoreleaseNoPool(): Object 0xd15880 of class __NSCFDate autoreleased with no pool in place - just leaking
Stack: (0x305a2e6f 0x30504682 0x30525acf 0x27b5 0x3050a79d 0x3050a338 0x926ae155 0x926ae012)
Please help me for that.
Thank you.
NSTimer schedules its time events on the current NSRunLoop--your thread doesn't start one.
If all you are trying to do is run something after a certain amount of time, use -[NSObject performSelector:withObject:afterDelay:]:
[self performSelector:#selector(onTimer) withObject:nil afterDelay:5.0f];
If you are trying to actually do work in the background, +[NSThread detachNewThreadSelector:toTarget:withObject:] will work as expected but you shouldn't run timer events in the background without an NSRunLoop. Also, you will need to wrap your code in an autorelease pool:
- (void)doThread:(NSString *)poststring
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Your code goes in here
[pool drain];
}
I'm not sure I understand your question about the onTimer method. Can you restate it?
As for:
NSAutoreleaseNoPool(): Object 0xd15880 of class __NSCFDate autoreleased with no pool in place - just leaking
A few things can cause this:
If you're not delegating or subclassing an UIApplication object, you won't have an autorelease pool in place and would have to create one on your own. However, the right answer in that case is just to be sure you're using UIApplication correctly.
In this case however, since you're detaching the thread, that's likely the cause for the error. Detached threads don't have autorelease pools, so you'd have to create your own.
See the documentation:
Autorelease Pools