passing variables when calling methon in new thread (iphone) - 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.

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

performSelectorOnMainThread with multiple parameter

I am trying to perform this action on the main thread:
[curItem.mButton setBackgroundImage:newArt forState:UIControlStateNormal];
So I do this...
cWrapperObject* obj = [cWrapperObject alloc];
[obj setupParams :curItem.mButton :newArt];
[obj performSelectorOnMainThread:#selector(setImageForButton) withObject:nil waitUntilDone:YES];
I feel like this is bad, does anyone has any suggestions on how I could approach this differently?
Another option is GCD. You can invoke a block on the main queue which gets run serially when the run loop runs. blocks aren't limited to one object like performSelectorOnMainThread.
dispatch_async(dispatch_get_main_queue(), ^{
// code here
});
I wrote a more comprehensive comparison of performSelectorXXX and GCD here complete with samples:
GCD, Threads, Program Flow and UI Updating
Also, here's another related SO post:
GCD to perform task in main thread
If you need to pass only one parameter, you should set up "withObject:" argument in method performSelectorOnMainThread:withObject:waitUntilDone. So your method should be declared as
-(void)setImageForButton:(id)parameter
and you should invoke method on main thread with:
[obj performSelectorOnMainThread:#selector(setImageForButton:) withObject:newArt waitUntilDone:YES];
Note ':' in #selector(setImageForButton:) this means that this method will be messaged with one argument, passed in withObject:

objective-c/iphone: how to set that all methods of some object will run on a specific thread?

here is what i want:
create an object that 'lives' in its own thread, all the methods should be executed in that thread.
i.e:
// i'm in the main thread
MyClass *myObject = [ [MyClass alloc] init ]; // it creates its own thread
[myObject method1]; // should execute the method1 in myObject's thread
[myObject method2]; // should execute the method2 in myObject's thread
[myobject release]; // should deallocate everything that is used for myObject and remove myObject's thread
i have been reading about threads and runloops. I created a new thread on the init method, its entry point is the runloop method. The runloopMethod just set the most basic stuff needed for running a NSRunLoop and runs it.
aThread = [[NSThread alloc] initWithTarget:self selector:#selector(runloopMethod) object:nil];
[aThread start];
it worked fine, but when i call a method ( i.e: [myObject method1];) from the main thread it runs it on the main thread, how do i know it?, well, because method1 performs several operations that blocks the UI. What i have done is to redirect the call in this way:
// on MyClass.m
-(void) method1 {
if ([NSThread currentThread] != aThread) {
[self performSelector:#selector(method1) onThread:aThread withObject:nil waitUntilDone:YES];
}else {
// do my stuff
}
it's working, but this way limits me, also i have some questions for you:
i have realized that if i'm in X-thread and call a method of some object, it will be executed in X-thread. I think that the method call will be added (not sure if it's the word) to the X-thread's runloop. right?
Is there a way to set that: any call to my object's methods will be executed on the object's thread? (without doing all this stuff).
also, is it the correct way for what am i doing?
method1, method2, and so on are the sync version of my functions..so they will block the UI. that' why i assume having another thread is the way.
thanks for reading!.
btw. i'm not using GCD since i need to support iOS 3
The Objective C method dispatch runtime code has no mechanism (AFAIK) to determine implicitly whether to do a generic method call on a different thread than the current one, so you will have to implement your own explicit background call mechanism, as you did, using performSelector.
If you set waitUntilDone to YES on your call to your background thread from the main thread, you will still block the UI.
If you want your method1 to run in the background and not block the UI, set waitUntilDone to NO, and have to background thread inform the main thread about completion (or anything else) using performSelectorOnMainThread.
You might alternatively be able to use operation queues to send messages to your background thread's run loop.
I'm guessing you are trying to use threads to run background tasks in order to keep the UI responsive. That's good, but this would be a very difficult approach. Try this instead:
1) From the main thread, fire off a new thread:
[NSThread detachNewThreadSelector:#selector(methodThatTheThreadWillRun)
toTarget:nil
withObject:nil];
2) Write methodThatTheThreadShouldRun and do whatever you need to do in it. It will be executed in the thread you just created. When it finishes, have it call a threadIsFinished on the main thread:
- (void)methodThatTheThreadWillRun {
MyClass *myObject = [ [MyClass alloc] init ];
[myObject method1];
[myObject method2];
[myobject release];
[self performSelectorOnMainThread:#selector(threadIsFinished)];
}
3) Finally, write threadIsFinished:
- (void)threadIsFinished {
// do whatever you need to do here: stop a spinner, etc.
// this will be invoked by the background thread but will
// execute on the main thread
}

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.

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