2011-08-29 22 views
24

Tôi muốn đợi mã này được thực hiện trước khi tiếp tục nhưng vì các khối này được gọi là không đồng bộ, tôi không biết cách làm ???Đợi tài sảnĐối với các khối URL được hoàn thành

NSURL *asseturl; 
NSMutableArray *tmpListAsset = [[NSMutableArray alloc] init]; 

ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease]; 
NSMutableArray *objectsToRemove = [[NSMutableArray alloc] init]; 
for (NSDictionary *dico in assetsList) { 
    asseturl = [NSURL URLWithString:[dico objectForKey:@"assetUrl"]]; 
    NSLog(@"asset url %@", asseturl); 
    // Try to load asset at mediaURL 
    [library assetForURL:asseturl resultBlock:^(ALAsset *asset) { 
     // If asset doesn't exists 
     if (!asset){ 
      [objectsToRemove addObject:dico]; 
     }else{ 
      [tmpListAsset addObject:[asseturl absoluteString]]; 
      NSLog(@"tmpListAsset : %@", tmpListAsset); 
     } 
    } failureBlock:^(NSError *error) { 
     // Type your code here for failure (when user doesn't allow location in your app) 
    }]; 
} 

Trả lời

1

Điều dễ nhất để làm là để di chuyển mã của bạn để bên trong (ở phần cuối của) các resultBlock hoặc failureBlock. Bằng cách đó, mã của bạn sẽ chạy theo đúng thứ tự và bạn cũng sẽ giữ lại hành vi không đồng bộ.

+0

Bạn có nghĩa là sau khi else} Vấn đề là tôi cần những vòng lặp sẽ được hoàn thành và cũng là mã được Sau đây là aa mảnh lớn các mã với chức năng async khác ... – Mathieu

+0

Giả sử này đang chạy trên chủ đề chính, bạn có thực sự muốn chặn toàn bộ chuỗi chính trong khi chờ khối này kết thúc không? –

+0

có bởi vì tôi gọi nó là performselectorinbackground – Mathieu

44

GCD semaphore cách tiếp cận:

dispatch_semaphore_t sema = dispatch_semaphore_create(0); 
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0); 

for (NSURL *url in self.assetUrls) { 
    dispatch_async(queue, ^{ 
     [library assetForURL:url resultBlock:^(ALAsset *asset) { 
      [self.assets addObject:asset]; 
      dispatch_semaphore_signal(sema); 
     } failureBlock:^(NSError *error) { 
      dispatch_semaphore_signal(sema); 
     }]; 
    }); 
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); 
} 
dispatch_release(sema); 

/* Check out ALAssets */ 
NSLog(@"%@", self.assets); 
+4

lưu ý rằng nếu mã này không được gọi trong chuỗi nền (ví dụ: sử dụng 'performSelectorInBackground:'), do bế tắc sẽ xảy ra (các khối dường như được gọi trên cùng một chuỗi, do đó semaphore không bao giờ được báo hiệu). –

+1

Đây phải là câu trả lời được chọn @Mathieu – brandonscript

4

Lưu ý rằng assetForURL: resultBlock: failureBlock: sẽ bị mắc kẹt nếu các chủ đề chính đang chờ đợi mà không runloop chạy. Đây là giải pháp thay thế (sạch :-)):

#import <libkern/OSAtomic.h> 

... 

ALAssetsLibrary *library; 
NSMutableArray *assets; 
... 
__block int32_t counter = 0; 
for (NSURL *url in urls) { 
    OSAtomicIncrement32(&counter); 
    [library assetForURL:url resultBlock:^(ALAsset *asset) { 
     if (asset) 
      [assets addObject:asset]; 
     OSAtomicDecrement32(&counter); 
    } failureBlock:^(NSError *error) { 
     OSAtomicDecrement32(&counter); 
    }]; 
} 
while (counter > 0) { 
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01]]; 
} 
+1

Tìm thấy rằng phương pháp của tôi không phải lúc nào cũng hoạt động (chờ đợi vô hạn có thể xảy ra). Tôi đề nghị phương pháp semaphore GCD của shacked có hiệu quả đối với tôi. –

1

Đây là cách dễ dàng để thực hiện. Có lẽ không phải là thanh lịch như sử dụng GCD nhưng nó sẽ nhận được công việc làm ... Điều này sẽ làm cho phương pháp của bạn chặn thay vì không chặn.

__block BOOL isFinished = NO; 
NSURL *asseturl; 
NSMutableArray *tmpListAsset = [[NSMutableArray alloc] init]; 

ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init]; 
NSMutableArray *objectsToRemove = [[NSMutableArray alloc] init]; 
for (NSDictionary *dico in assetsList) { 
    asseturl = [NSURL URLWithString:[dico objectForKey:@"assetUrl"]]; 
    NSLog(@"asset url %@", asseturl); 
    // Try to load asset at mediaURL 
    [library assetForURL:asseturl resultBlock:^(ALAsset *asset) { 
     // If asset doesn't exists 
     if (!asset){ 
      [objectsToRemove addObject:dico]; 
     }else{ 
      [tmpListAsset addObject:[asseturl absoluteString]]; 
      NSLog(@"tmpListAsset : %@", tmpListAsset); 
     } 
     if (objectsToRemove.count + tmpListAsset.count == assetsList.count) { 
      isFinished = YES; 
     } 
    } failureBlock:^(NSError *error) { 
     // Type your code here for failure (when user doesn't allow location in your app) 
     isFinished = YES; 
    }]; 
} 

while (!isFinished) { 
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.01f]]; 
} 
Các vấn đề liên quan