2014-10-01 101 views
0

我正在使用dispatch_group在所有併發任務完成時獲取通知。我正在卸載[TWReaderDocument documentFileURL:url withCompletionBlock:]類方法內的一個併發隊列中的一些繁重任務。未收到通知dispatch_group_notify

我已經實現了下面的代碼,但從未收到任何通知。我看不出什麼,我可能做錯了在下面的代碼:

dispatch_group_t readingGroup = dispatch_group_create(); 

    NSFileManager* manager = [NSFileManager defaultManager]; 

    NSString *docsDir = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Data"]; 

    NSDirectoryEnumerator *dirEnumerator = [manager enumeratorAtURL:[NSURL fileURLWithPath:docsDir] 
             includingPropertiesForKeys:[NSArray arrayWithObjects:NSURLNameKey, 
                    NSURLIsDirectoryKey,nil] 
                  options:NSDirectoryEnumerationSkipsHiddenFiles 
                 errorHandler:nil]; 


    // An array to store the all the enumerated file names in 
    NSMutableArray *arrayFiles; 

    // Enumerate the dirEnumerator results, each value is stored in allURLs 
    for (NSURL *url in dirEnumerator) { 

     // Retrieve the file name. From NSURLNameKey, cached during the enumeration. 
     NSString *fileName; 
     [url getResourceValue:&fileName forKey:NSURLNameKey error:NULL]; 

     // Retrieve whether a directory. From NSURLIsDirectoryKey, also cached during the enumeration. 
     NSNumber *isDirectory; 
     [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:NULL]; 


     if (![isDirectory boolValue]) { 

       dispatch_group_enter(readingGroup); 
       TWReaderDocument* doc = [TWReaderDocument documentFileURL:url withCompletionBlock:^(BOOL success) { 

        dispatch_group_leave(readingGroup); 

       }]; 

       [arrayFiles addObject:doc]; 

     } 
     else if ([[[fileName componentsSeparatedByString:@"_" ] objectAtIndex:0] isEqualToString:@"XXXXXX"]) { 

      TreeItem* treeItem = [[TreeItem alloc] init]; 

      arrayFiles = [NSMutableArray arrayWithCapacity:10]; 

      treeItem.child = arrayFiles; 
      treeItem.nodeName = [[fileName componentsSeparatedByString:@"_" ] lastObject]; 
      [self addItem:treeItem]; 


     } 
    } 

    dispatch_group_notify(readingGroup, dispatch_get_main_queue(), ^{ // 4 

     NSLog(@"All concurrent tasks completed"); 

    }); 

是否dispatch_group_enterdispatch_group_leave必須是同一個線程上執行?

編輯 我的工廠方法的代碼片段可能有助於藏漢:

+ (TWReaderDocument *)documentFileURL:(NSURL *)url withCompletionBlock:(readingCompletionBlock)completionBlock{ 


      TWReaderDocument * twDoc = [[TWReaderDocument alloc] init]; 
      twDoc.status = ReaderDocCreated; 

      twDoc.doc = [ReaderDocument withDocumentFilePath:[url path] withURL:url withLoadingCompletionBLock:^(BOOL completed) { 

       twDoc.status = completed ? ReaderDocReady : ReaderDocFailed; 

       completionBlock(completed); 

      }]; 

      return twDoc; 

     } 

TWReaderDocument是一個包裝類,內部調用第三方庫的下列方法(它是一個PDF閱讀器)

+ (ReaderDocument *)withDocumentFilePath:(NSString *)filePath withURL:(NSURL*)url withLoadingCompletionBLock:(readingCompletionBlock)completionBlock{ 

    ReaderDocument *document = [[ReaderDocument alloc] initWithFilePath:filePath withURL:url withLoadingCompletionBLock:[completionBlock copy]]; 
    return document; 
} 


- (id)initWithFilePath:(NSString *)fullFilePath withURL:(NSURL*)url withLoadingCompletionBLock:(readingCompletionBlock)completionBlock { 
    id object = nil; // ReaderDocument object; 

    if ([ReaderDocument isPDF:fullFilePath] == YES) // File must exist 
    { 
     if ((self = [super init])) // Initialize superclass object first 
     { 

      _fileName = [ReaderDocument relativeApplicationFilePath:fullFilePath]; // File name 

      dispatch_async([ReaderDocument concurrentLoadingQueue], ^{ 

       self.guid = [ReaderDocument GUID]; // Create a document GUID 

       self.password = nil; // Keep copy of any document password 

       self.bookmarks = [NSMutableIndexSet indexSet]; // Bookmarked pages index set 

       self.pageNumber = [NSNumber numberWithInteger:1]; // Start on page 1 

       CFURLRef docURLRef = (__bridge CFURLRef)url;// CFURLRef from NSURL 
       self.fileURL = url; 

       CGPDFDocumentRef thePDFDocRef = CGPDFDocumentCreateX(docURLRef, self.password); 

       BOOL success; 
       if (thePDFDocRef != NULL) // Get the number of pages in the document 
       { 
        NSInteger pageCount = CGPDFDocumentGetNumberOfPages(thePDFDocRef); 

        self.pageCount = [NSNumber numberWithInteger:pageCount]; 

        CGPDFDocumentRelease(thePDFDocRef); // Cleanup 

        success = YES; 
       } 
       else // Cupertino, we have a problem with the document 
       { 
//     NSAssert(NO, @"CGPDFDocumentRef == NULL"); 
        success = NO; 
       } 


       NSFileManager *fileManager = [NSFileManager new]; // File manager instance 

       self.lastOpen = [NSDate dateWithTimeIntervalSinceReferenceDate:0.0]; // Last opened 

       NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:fullFilePath error:NULL]; 

       self.fileDate = [fileAttributes objectForKey:NSFileModificationDate]; // File date 

       self.fileSize = [fileAttributes objectForKey:NSFileSize]; // File size (bytes) 

       completionBlock(success); 

      }); 


      //[self saveReaderDocument]; // Save the ReaderDocument object 

      object = self; // Return initialized ReaderDocument object 
     } 
    } 

    return object; 
} 

回答

1

很難說什麼是怎麼回事不知道更多關於TWReaderDocument,但我懷疑...

首先,否,dispatch_group_enterdispatch_group_leave不是必須在同一個線程上執行。當然不。

根據這裏的信息,我最好的猜測是,對於某些輸入,[TWReaderDocument documentFileURL:withCompletionBlock:]正在返回nil。你可以試試這個:

if (![isDirectory boolValue]) { 

      dispatch_group_enter(readingGroup); 
      TWReaderDocument* doc = [TWReaderDocument documentFileURL:url withCompletionBlock:^(BOOL success) { 

       dispatch_group_leave(readingGroup); 

      }]; 

      // If the doc wasn't created, leave might never be called. 
      if (nil == doc) { 
       dispatch_group_leave(readingGroup); 
      } 

      [arrayFiles addObject:doc]; 

    } 

試試看。

編輯: 這完全如我所料。有些情況下,這種工廠方法不會調用完成。例如:

if ([ReaderDocument isPDF:fullFilePath] == YES) // File must exist 

如果-isPDF:回報NOcompletionBlock將永遠不會被調用,並且返回值將是nil

順便說一句,你永遠不應該比較一下東西== YES。 (任何非零相當於YES,但YES被定義爲1。只是做if ([ReaderDocument isPDF:fullFilePath])。這相當於,更安全。

+0

文檔實際上是在完成塊中調用零,但爲什麼它涉及到dispatch_group_leave? – tiguero 2014-10-01 17:03:23

+0

什麼我想說的是,它看起來像' - [TWReaderDocument documentFileURL:withCompletionBlock:]'實際上是一個工廠方法,它返回一個新的'TWReaderDocument'實例,如果由於某種原因沒有創建實例,'completionBlock'可能永遠不會如前所述,如果不知道更多關於TWReaderDocument內部的知識是不可能的 - 從另一方面來推斷:如果你的dispatch_group_notify沒有被調用,那麼dispatch_group_leave的一個或多個實例是*還*不被稱爲 – ipmcc 2014-10-01 17:13:09

+0

看到我的編輯我已經暴露了我的工廠方法:它是相當長的...順便說一句doc只是無完成塊內沒有外面。 – tiguero 2014-10-01 18:19:29