开发者

NSOperation synchronization problem

I am struggling to find a way to synchronize operation on IPhone app. I have three main NSOperation.

    NSInvocationOperation *showSpinner = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(spinnerOn:) object:YES];
    NSInvocationOperation *reloadDatasource = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(reloadDatasource) object:nil];
    NSInvocationOperation *hideSpinner = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(spinnerOn:) object:NO];
    // Add dependency
    [reloadDatasource addDependency:showSpinner];
    [hideSpinner addDependency:reloadDatasource];

    [self.queue addOperation:showSpinner];
    [self.queue addOperation:reloadDatasource];
    [self.queue addOperation:hideSpinner];

I can see that the three operations are correctly started in sequence. However, as you can imagine, the first operation create a UIView and attach it on top, while the last one should remove it.

It happens that graphically speaking the operations happens at once on the s开发者_运维知识库creen. So I can see the table already loaded, while the spinner is on screen, or other strange unsynchronized things.

I understood that change on the graphic side happen on the main thread. So I am asking how can I modify the code to do what it is supposed to do. Which is: create spinner, load data, and remove spinner ? Is there a common way to separate graphic operation and data operation ? For example create two distinct operation.

thanks


How about writing

[self spinnerOn:YES];
[self performSelectorInBackground:@selector(reloadDatasource) withObject:nil];

and then make call back to your main thread in 'reloadDataSource' method with

[self performSelectorInMainThread:@selector(spinnerOn:) withObject:NO];


Is it obligatory to use the NSOperation? If not, then I guess you are choosing the hard way to solve the simple problem, use the delegate of the NSConnection (or something similar as I am not sure what does your reloadDataSource do) to start and stop the spinner and then you'are done.


In your spinnerOn: method, can you try adding a bit of logic to make sure the operation occurs on the main thread?

if ( ![NSThread isMainThread] ) { 
    [self performSelectorOnMainThread:@selector(spinnerOn:) withObject:anObject waitUntilDone:NO];
    return;
}

I'd be curious to see if that makes a difference. My suspicion is that if you call a UI task from an alternate thread, those get queued up and might end up happening all at once at a later, undefined time on the main thread.

Another option to try is making your operation queue a serial queue. By this I mean have it only perform one task at a time. Then you can forget about your dependencies as it will always just execute tasks in the order that you add them. You can try that by setting it:

[self.queue setMaxConcurrentOperationCount:1];

Let me know if this is helpful at all.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜