Inter Thread Communication

Discussion in 'iOS Programming' started by Hawkeye75, Jun 10, 2010.

  1. Hawkeye75 macrumors member

    Joined:
    Mar 29, 2010
    #1
    Hey folks,

    I need to run a timer independently of the main loop. So I've been reading up on NSOperation and NSOperationQueue. Most of the documentation is straightforward.

    My only question is in regards to the communication between threads. I want to be able to output the timer to a label back on my view controller that is going to queue the NSOperation subclass. I've found "performSelectorOnMainThread:" method which should do what I need. However, I'm a little fuzzy on how I can reference the main thread in that function.

    See question marks in code...

    Code:
    [??? performSelectorOnMainThread:@selector(someMethodInViewController:) withObject:someObject waitUntilDone:NO];
    Also is this the only way to pass information back to the main thread?
     
  2. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #2
    Using performSelectorOnMainThread is not the only way to communicate with the main thread but it's the best way in most cases. It is simple to use, reliable, and guarantees sequencing.

    The first parameter to the method is the object that you want to message, same as any other method.

    Code:
    [viewController performSelectorOnMainThread:@selector(someMethodInViewController:) withObject:someObject waitUntilDone:NO];
    
    However, when using operations I almost always send a message to self and then on the main thread have self message the other object.

    Code:
    // main thread
    - (void)reportProgress:(NSString*)progressString
    {
    	if (! [self isCancelled] && [self.delegate respondsToSelector:@selector(reportProgress:)])
    	{	
    		[self.delegate reportProgress:progressString];
    	}
    }
    
    // background thread
    - (void)reportProgressInternalL(NSString*)inString
    {
    	NSString*	progressString = [inString copy];
    	[self performSelectorOnMainThread:@selector(reportProgress:) withObject:progressString waitUntilDone:NO];
    	[progressString release];
    }
    
     
  3. Hawkeye75 thread starter macrumors member

    Joined:
    Mar 29, 2010
    #3
    Thanks Phoney, I think I know where I got mixed up conceptually. I guess since I thought I was kicking off a separate thread that the NSOperation class was operating completely independently. So I couldn't visualize how the one class would call another one.

    However, it seems you just create an instance of that class like you would any other class. Now using "self" makes sense. I can also see why it's useful to create a protocol for the NSOperation class and have the viewController conform to that protocol. The code would blow up if you tried to call a method from within the Operation that didn't exist in the view controller.
     
  4. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #4
    If you have an object send a message to itself from another thread to the main thread, you may have to make sure the object is reentrant and thread safe, which may be non-trivial. Better to have it send a message directly to an object which only ever runs in the main thread, thus letting the runtime take care of that thread safety issue.
     
  5. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #5
    The whole point of using performSelectorOnMainThread is to avoid having to make "sure the object is reentrant and thread safe" Is there something about the code that I showed that isn't thread safe?

    One of the reasons to use NSOperation is to be able to use its cancellable property. Sending the message to self allows your code to reliably use this property. I show this in my code. If you send the message directly to the object from the background thread you will find that it's impossible to prevent the message from being sent even when the operation has been cancelled and the operation and the operation queue have been released.

    Sending to self guarantees that the message is received on the main thread in an object that exists and that is in the correct state. If you send the message to any other object you can't be sure that the object is still expecting to receive the message.
     
  6. seepel macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #6
    It sounds like you might want to look at the NSTimer class. It allows you to set up a timer that will trigger a selector at a specified interval fairly easily.
     
  7. Hawkeye75 thread starter macrumors member

    Joined:
    Mar 29, 2010
    #7
    Well my plan was to create an NSTimer within the separate thread so it would run independently and not interferer with UI interactions. I basically want to time how long it takes to solve a puzzle. So the timer needs to run continuously until I kill it.
     
  8. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #8
    Why don't you just subtract the clock time at the beginning and end? Then you don't need a timer process at all.
     
  9. Hawkeye75 thread starter macrumors member

    Joined:
    Mar 29, 2010
    #9
    Interesting simplistic approach using NSDate no doubt. However, I actually want to be able to display the elapsed time.
     
  10. firewood macrumors 604

    Joined:
    Jul 29, 2003
    Location:
    Silicon Valley
    #10
    If you want to display it, you have to do all UI on the main thread anyway, so you might as well set the timer on your setneedsdisplay setup method in the main thread.
     
  11. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #11
    Displaying the elapsed time is possible using a couple of NSDates and some date arithmetic.
     
  12. xsmasher macrumors regular

    xsmasher

    Joined:
    Jul 18, 2008
    #12
    Seepel is right, you don't want to use threads here. You want an NSTimer instead. It'll be much easier than multithreading, and it won't interfere with your UI at all.
     
  13. Hawkeye75 thread starter macrumors member

    Joined:
    Mar 29, 2010
    #13
    Just using NSTimer alone may be good enough. However I also read that NSTimer isn't guaranteed to trigger at the exact time interval specified. This is dependant on how many other messages are being fired until loop comes back to check to see if the appropriate interval has passed.

    For accuracy sake I figured I would try running the timer in it's own thread.

    I'm willing to admit that I'm probably making it more difficult on myself. On the other hand I'm learning a lot by trying new things. :)

    It won't hurt to just try firing NSTimer on the main thread and see how accurate the timer is. Since I'm only updating the label every 1 second it will probably work fine.
     

Share This Page