Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Hawkeye75

macrumors member
Original poster
Mar 29, 2010
32
0
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?
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
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];
}
 

Hawkeye75

macrumors member
Original poster
Mar 29, 2010
32
0
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.
 

firewood

macrumors G3
Jul 29, 2003
8,113
1,353
Silicon Valley
However, when using operations I almost always send a message to self and then on the main thread have self message the other object.

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.
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
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.
 

seepel

macrumors 6502
Dec 22, 2009
471
1
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.
 

Hawkeye75

macrumors member
Original poster
Mar 29, 2010
32
0
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.

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.
 

Hawkeye75

macrumors member
Original poster
Mar 29, 2010
32
0
Why don't you just subtract the clock time at the beginning and end? Then you don't need a timer process at all.

Interesting simplistic approach using NSDate no doubt. However, I actually want to be able to display the elapsed time.
 

firewood

macrumors G3
Jul 29, 2003
8,113
1,353
Silicon Valley
Interesting simplistic approach using NSDate no doubt. However, I actually want to be able to display the elapsed time.

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.
 

xsmasher

macrumors regular
Jul 18, 2008
140
0
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.
 

Hawkeye75

macrumors member
Original poster
Mar 29, 2010
32
0
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.

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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.