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

youPhone

macrumors member
Original poster
Sep 8, 2008
41
0
Some things need to be run on the mainThread as per the guidelines. One example is reloadData for a table. If I don't run this on mainThread I will get problems or even crashes. Other things like updating frames have to be done like this too.

I was wondering if this is a safe way to make sure something is run on the mainThread. I've tested it out some and it always seems to work, but it could be a bad practice.


Code:
- (void) reloadTable
{
	if ([NSThread isMainThread]) {
		@synchronized (self.tableView) {
			[self.tableView reloadData];
		}
	} else {
		[self performSelectorOnMainThread:@selector(reloadTable) withObject:nil waitUntilDone:YES];
	}
}

The only problem I see is if somehow the performSelectorOnMainThread somehow didn't get called on the mainThread and it got stuck in an infinite loop
 

newb16

macrumors regular
Feb 27, 2008
100
0
The only problem I see is if somehow the performSelectorOnMainThread somehow didn't get called on the mainThread and it got stuck in an infinite loop


I don't know if it is different from 'big' os x, where it posts an event in event loop and waits until it is processed. So it will be fetched sometime and will be processed. Btw, isn't @synchronised within if(is_main_thread) redundant?
 

jnic

macrumors 6502a
Oct 24, 2008
567
0
Cambridge
Is the if/else not rather redundant given that performSelectorOnMainThread will have the same effect regardless of which thread you're in (including the main thread)?
 

youPhone

macrumors member
Original poster
Sep 8, 2008
41
0
I have had some weird display problems if I don't run reloadData on the main thread. There are other cases such as setting text in a UILabel where the text will not display unless that command was called on the main thread. So I could have used the example:

Code:
- (void) setLabelText:(NSString*)someText
{
	if ([NSThread isMainThread]) {
		someLabel.text = someText;
	} else {
		[self performSelectorOnMainThread:@selector(setLabelText:) withObject:someText waitUntilDone:YES];
	}
}

So my real question is if this would be good practice or not. I seem to be wanting to use this code in quite a few places where I download XML feed data on a new thread, then when the data is processed, I want to update the display layer on the main thread.
 

jnic

macrumors 6502a
Oct 24, 2008
567
0
Cambridge
What I mean is, why not simply replace

Code:
- (void) setLabelText:(NSString*)someText
{
	if ([NSThread isMainThread]) {
		someLabel.text = someText;
	} else {
		[self performSelectorOnMainThread:@selector(setLabelText:) withObject:someText waitUntilDone:YES];
	}
}

with

Code:
- (void) setLabelText:(NSString*)someText
{
	[self performSelectorOnMainThread:@selector(setLabelText:) withObject:someText waitUntilDone:YES];
}

Yes, any UI updates must be in the main thread to have any effect, but I can't see any advantage to testing the thread when performSelectorOnMainThread works correctly regardless of the calling thread.
 

youPhone

macrumors member
Original poster
Sep 8, 2008
41
0
Suppose that there are 4 labels that need to be updated. So I can either:

Code:
- (void) updateLabels
{
	if ([NSThread isMainThread]) {
		someLabel1.text = someField1.text;
		someLabel2.text = someField2.text;
		someLabel3.text = someField3.text;
		someLabel4.text = someField4.text;
	} else {
		[self performSelectorOnMainThread:@selector(setLabelsText:) withObject:someText waitUntilDone:YES];
	}
}

or

Code:
- (void) updateLabels
{
	[someLabel1 performSelectorOnMainThread:@selector(setText:) withObject:someField1.text waitUntilDone:YES];
	[someLabel2 performSelectorOnMainThread:@selector(setText:) withObject:someField2.text waitUntilDone:YES];
	[someLabel3 performSelectorOnMainThread:@selector(setText:) withObject:someField3.text waitUntilDone:YES];
	[someLabel4 performSelectorOnMainThread:@selector(setText:) withObject:someField4.text waitUntilDone:YES];
}

It seems like running performSelectorOnMainThread:withObject:waitUntilDone: four times in the second code block would be more expensive than running the first code block.

I could just run
Code:
[someObject performSelectorOnMainThread:@selector(updateLabels) withObject:nil waitUntilDone:YES];

I think the main thing I'm trying to do is make certain that some selectors are always run on the main thread. I suppose the header comment for the selector could just say that this selector must be run on the main thread.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.