How can I cancel performSelectorOnMainThread? - iphone

How can I cancel performSelectorOnMainThread?
I have this code:
myClass = [[MyClass alloc] init];
[myClass performSelectorOnMainThread:#selector(setupPlayer) withObject:nil waitUntilDone:YES];

Per the documentation:
You cannot cancel messages queued using this method.

If you're careful about the thread on which you originally queued the message, you can cancel it by calling + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget on that same thread. That previous answer was missing an important bit:
You cannot cancel messages queued using this method. If you want the
option of canceling a message on the current thread, you must use
either the performSelector:withObject:afterDelay: or
performSelector:withObject:afterDelay:inModes: method.

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

NSTimer setFireDate

Is considered thread-safe to call setFireDate: from another thread than the one in which the timer is scheduled? I mean, I detach this function in a new thread:
-(void)CFRunLoopTest {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
timer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(timerFireMethod:) userInfo:nil repeats:YES];
runLoop = CFRunLoopGetCurrent();
CFRunLoopAddTimer(runLoop, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes);
CFRunLoopRun();
[pool drain];
}
May I call [timer setFireDate:] from the main thread? I did not found anything in documentation that forbids it...
A note from the NSTimer reference for setFireDate: method says
You could potentially call this method
on a non-repeating timer that had not
yet fired, although you should always
do so from the thread to which the
timer is attached to avoid potential
race conditions.
Also see if the following
Discussion helps.
Why not run the timer on the main thread? I don't understand why you would need to run it in a separate thread. You could always have the timerFireMethod: spawn a new thread if it consumes a lot of time, Just run the appropriate method with performSelectorInBackground:withObject:.
EDIT: So the documentation actually says that it isn't thread safe to call[timer setFireDate:] from another thread. However, my advice is still valid.

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.

How to stop a NSThread sub-thread in iphone

I created a sub-thread using NSThread in main thread
NSThread *newThread = [[NSThread alloc] initWithTarget:self selector:#selector(MyThread:) object:timer];
5 sec later,i used [newThread cancel] in main thread to stop the sub-thread,but it didnt work,
Method MyThread: in newThread still working
so,whats the correct answer to stop newThread,THX
actually [newThread isCancelled] is YES,but selector MyThread was still woking
The cancel method only informs the thread that it is cancelled (as you mentioned changes the isCancelled to YES. It's then the responsibility of the thread itself to check this and exit. For example, in your MyThread: method you could do this:
// At some checkpoint
if([[NSThread currentThread] isCancelled]) {
/* do some clean up here */
[NSThread exit];
}
You should do this check periodically, and exit from within the thread as shown; otherwise the cancel doesn't have any effect.
-(void)cancel
Discussion
The semantics of this method are the same as those used for the NSOperation object. This method sets state information in the receiver that is then reflected by the isCancelled method. Threads that support cancellation should periodically call the isCancelled method to determine if the thread has in fact been cancelled, and exit if it has been.
more information see NSThread API Reference