for example, i have 100 times the for loop. and need to update UIImageView,and the last 2 method is same slowly. why? what is the different between they?
//fastest
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[btnThumb setImage:[UIImage imageWithData:data] forState:UIControlStateNormal];
[scrollView addSubview:btnThumb];
}];
//slowly
dispatch_async(dispatch_get_main_queue(), ^
{
[btnThumb setImage:[UIImage imageWithData:data] forState:UIControlStateNormal];
[scrollView addSubview:btnThumb];
});
//slowly
[btnThumb setImage:[UIImage imageWithData:data] forState:UIControlStateNormal];
[self performSelectorOnMainThread:@selector(testMethod:) withObject:[NSArray arrayWithObjects:scrollView, btnThumb, nil] waitUntilDone:NO];
-(void) testMethod:(NSArray*)objs
{
UIScrollView *scroll = [objs objectAtIndex:0];
UIButton *btn = [objs lastObject];
[scroll addSubview:btn];
}
For posterity, lest there be any doubt about this, let's consider the following test harness, built in a simple empty application template. It does 1000 operations using each mechanism, and also has a run loop observer, so we can see how our enqueued asynchronous tasks relate to the spinning of the main run loop. It logs to console, but does so asynchronously, so that the cost of
NSLog
isn't confounding our measurement. It also intentionally blocks the main thread while it enqueuesNSOperations
/dispatch_asyncs
/performSelectors
tasks, so that the act of enqueuing also doesn't interfere. Here's the code:In the output of this code, we see the following (with irrelevant/repeating portions removed):
What this shows us is that
NSOperation
s enqueued on the main queue get executed one per pass of the run loop. (Incidentally, this is going to allow views to draw for each operation, so if you're updating a UI control in these tasks as the OP was, this will allow them to draw.) Withdispatch_async(dispatch_get_main_queue(),...)
and-[performSelectorOnMainThread:...]
all enqueued blocks/selectors are called one after the other without letting views draw or anything like that. (If you don't forcibly pause the main runloop while you enqueue tasks, you sometimes can see the run loop spin once or twice during the enqueueing process.)In the end, the results are about what I expected they would be:
NSOperationQueue
will always be slower, because spinning the run loop isn't free. In this test harness, the run loop isn't even doing anything of substance, and it's already 10% slower thandispatch_async
. If it were doing anything of substance, like redrawing a view, it would be much slower. As fordispatch_async
vsperformSelectorOnMainThread:
both execute all enqueued items in one spin of the run loop, so the difference is pretty marginal. I expect it's down to message send overhead and managing the retain/releases on the target and argument of theperformSelector...
.So contrary to the implication of the question,
NSOperationQueue
is not, objectively, the fastest of the three mechanisms, but rather the slowest. My suspicion is that in OP's case,NSOperationQueue
appears faster because its "time to first visible change" is going to be much shorter, whereas fordispatch_async
andperformSelector
all enqueued operations are going to be executed, and only then will the view redraw and show the new state. In the pathological case, I would expect this to mean that only the last frame was ever seen, although if you don't block the main thread while enqueueing, you could get a handful of visible frames (but you'll effectively be dropping most of the frames on the ground.)Regardless of which asynchronous execution mechanism is objectively fastest, they're all pretty crappy ways to do animation.