문제

I am trying to complete a long calculation with a determinate progress bar. This is working fine with the below code. However, in the method which calls scan, it immediately moves on to scoreWithEquation before scan has finished updating the StoredLibrary object. I've tried all the different methods for waiting for the dispatch queues to finish, but they all end up hanging the UI. Do I need to be using a callback? I've looked into this solution, but I don't understand how to pass all the arguments and return variables back and forth.

-(void) scan{
if (!_sheet){
    [NSBundle loadNibNamed: @"ProgressSheet" owner: self];
}
[NSApp beginSheet: _sheet
   modalForWindow: [[NSApp delegate]window]
    modalDelegate: self
   didEndSelector: NULL
      contextInfo: nil];

[_sheet makeKeyAndOrderFront:self];

[_progressBar setIndeterminate:YES];
[_progressBar setMinValue:0];
[_progressBar startAnimation:self];

__block NSMutableArray *tempTracks = [[NSMutableArray alloc]init];

//do stuff

dispatch_async(dispatch_get_global_queue(0, 0), ^{

        //do stuff
        [_progressBar setDoubleValue:0.f];
        [_progressBar setMaxValue:[listTracks count]];
        [_progressBar setIndeterminate:NO];

        for (iTunesTrack *listTrack in listTracks) {
            //do stuff to tempTracks
            }
            dispatch_async(dispatch_get_main_queue(), ^{
                [_progressBar incrementBy:1];
            }); 
        }
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        [_progressBar setIndeterminate:YES];
        [NSApp endSheet:self.sheet];
        [self.sheet orderOut:self];
        self.listTracks = tempTracks;
    });
});
}

Below is the code which calls scan:

- (IBAction)evaluate:(id)sender {
        if (self.storedLibrary == nil){
            self.storedLibrary = [[StoredLibrary alloc] init];
            [self.storedLibrary scan];
        }
self.tableTracks = [self.storedLibrary scoreWithequation:[_scoringEquation stringValue]
                                               sortOrder:[_sortOrder titleOfSelectedItem]                                                                                                   
                                              trackLimit:[_trackLimit integerValue]];
}

I would like to keep scan and scoreWithEquation as separate methods, as they are called elsewhere separately.

도움이 되었습니까?

해결책

When you use dispatch_async the block dispatched will not block the current thread, and the execution will continue immediatly.

In your case, when you call scan, you do some stuff and then call dispatch_async to do other stuff. everything in the dispatch block will not be executed in this run loop and [self.storedLibrary scan] returns so scoreWithequation will be executed immediatly.

If you want to block the current thread (the thread on which the dispatch call is executed) you need to use dispatch_sync.

if you want to execute scoreWithequation after scan, you can create a serial_queue, and dispatch_async both scan and then scoreWithequation to the custom serial_queue. Doing so the execution will not block the current thread, and they will be executed in serie.

check "creating serial dispatch queue" ( http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html )

or retaining a completion block to execute scoreWithequation as a callback is also a possibility.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top