NSThread, NSTimer and AutoreleasePools in an iPhone SDK application - iphone

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

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)];

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.

passing variables when calling methon in new thread (iphone)

i need to pass variables to the thread method when creating a new thread
my code is the follwing
//generating thread
[NSThread
detachNewThreadSelector:#selector(startThread)
toTarget:self withObject:nil];
thread job
- (void)startThread:(NSInteger *)var img:(UIImageView *) Img{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[NSThread sleepForTimeInterval:var];
[self performSelectorOnMainThread:#selector(threadMethod) withObject:nil waitUntilDone:NO];
//i need to pass Img to threadMethod:
[pool release];
}
thread Method
- (void)threadMethod:(UIImageView *) Img {
//do some coding.
}
so how i can do this (pass parameter to both of methods
The code you provided as I see it is only using the thread to implement a delay. You can do this easily without introducing a thread like this:
[myImageView performSelector:#selector(setImage:)
withObject:image
afterDelay:5.0];
For more complex needs I have written a category on NSInvocation that allow you to easily call any method, independent of the arguments, on any thread.
You have for example this method as I see it:
-(void)doStuffWithImage:(UIImage*)image callbackAfterDelay:(NSTimeInterval)to {
NSAutoreleasePool* pool = [[UIAutoreleasePool alloc] init];
// ... do stuff
[NSThread sleepForTimeInterval:ti];
[self performSelectorOnMainThread:#selector(callbackWithImage:)
withObject:image
waitUntilDone:NO];
[pool release];
}
This is easy enough, but spawning this method on a secondary thread is not that easy. My category allow you to do it with this simple code:
[[NSInvocation invocationWithTarget:self
selector:#selector(doStuffWithImage:callbackAfterDelay:)
retainArguments:YES, image, 5.0] invokeInBackground];
This is where you can find the code and a blog post elaborating on why and how it was implemented:
http://blog.jayway.com/2010/03/30/performing-any-selector-on-the-main-thread/
You can pass only one argument by using withObject:, change your code as follows
[self performSelectorOnMainThread:#selector(threadMethod)
withObject:image
waitUntilDone:NO];
If you need to pass more than one value make it as a array, and then pass it.
And UIComponents are not thread safe, so be careful while passing UIcomponents to threads.
I'm reasonably certain UIImage isn't thread safe, so you may be out of luck there. In general though, any of these:
Make the object an instance variable
Make the object a global
Capture the variable in a block and use dispatch_async to do your threaded work instead of NSThread
Send the object to the thread using NSConnection
etc...
Remember though, just because you have a reference to the object doesn't mean it's safe to use. Consider thread-safety guarantees (main thread only vs one thread only vs one writer only vs thread safe), and consider where you need to use locks or queues to guard resources shared between threads.

Call a delegate's method within a background

this is my first question here, so excuse me if I made any mistakes!
In my iPhone project I have a method running in a thread which takes a long time to execute (that's why it runs in a thread).
[NSThread detachNewThreadSelector:#selector(methodToBeCalledInAThread) toTarget:self withObject:nil];
// ...
-(void)methodToBeCalledInAThread {
MyClass *myClass = [[MyClass alloc] init];
[myClass setDelegate:self];
[myClass veryIntensiveComputing];
[myClass release];
}
My goal is to notifiy the ViewController calling this method of any progress going on in this method. This is why I set the ViewController as a delegate of the class.
Now in the expensive method I do the following:
if(self.delegate != nil) {
[self.delegate madeSomeProgress];
}
But unfortunately this does not work, because (I think) I'm in a background thread.
How do I achieve to notify the delegate of any changes with the method being executed asynchronously?
Try [self.delegate performSelectorOnMainThread: #selector(madeSomeProgress) withObject: nil waitUntilDone: YES];....
See the documentation for details.
This will synchronously perform the operation on the main thread. As long as nothing in the main thread tries to execute stuff in that secondary thread, this is mostly safe to do.
However if you don't want to block the computation until the main thread services the request, you can pass NO to not wait. If you do so, then you also have to worry about thread synchronization. The main thread may not immediately service the request and, when it does, your background thread may be in the process of mutating state.
Threads are hard.

Keep an NSThread containing an NSTimer around indefinitely? (iPhone)

I have some web service data in my app that needs to be updated every 3 minutes.
I had tried out a few approaches but got a really good piece of advise in here last week, I should not build a new thread every 3 minutes and then subsequently try and dealloc and synchronize all the different parts so that I avoided memory bug. Instead I should have a "worker thread" that was always running, but only did actual work when I asked it too (every 3 minutes).
As my small POC works now, I spawn a new thread in the applicationDidFinishLaunching
method. I do this like so:
[NSThread detachNewThreadSelector:#selector(updateModel) toTarget:self withObject:nil];
- (void) updateModel {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
BackgroundUpdate *update = [[BackgroundUpdate alloc] initWithTimerInterval:180];
[update release];
[pool release];
}
Ok, this inits the "BackgroundUpdate" object with the update interval in seconds. Inside the updater it is simply like this for now:
#implementation BackgroundUpdate
- (id) initWithTimerInterval:(NSInteger) secondsBetweenUpdates {
if(self = [super init]) {
[NSTimer scheduledTimerWithTimeInterval:secondsBetweenUpdates
target:self
selector:#selector(testIfUpdateNeeded)
userInfo:nil
repeats:YES];
}
return self;
}
- (void) testIfUpdateNeeded {
NSLog(#"Im contemplating an update...");
}
I have never used threads like this before. I has always been "setup autoReleasePool, do work, get your autoReleasePool drained, and goodbye".
My problem is that as soon as the initWithTimerInterval has run, the NSThread is done, it therefore returns to the updateModel method and has its pool drained. I guess it has to do with the NSTimer having it's own thread/runloop? I would like for the thread to keep having the testIfUpdateNeeded method run every 3 minutes.
So how will I keep this NSThread alive for the entire duration of my app?
Thank You for any help/advice given:)
You're close. All you need to do now is start the run loop running so the thread doesn't exit and the timer runs. After your call to initWithTimerInterval:, just call
[[NSRunLoop currentRunLoop] run];
The thread will run its run loop indefinitely and your timer will work.
It sounds like you might want an NSOperation instead of an old fashion thread. You could active the operation via a universal timer then it would execute on its own thread and then clean up its own memory when done.