2014-10-01 1 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합니까 동일한 스레드에서 실행될 수있다?

EDIT 내 팩토리 메소드의 코드가 aswell 도움이 될 :

+ (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에 해당하지만, YES1로 정의됩니다. 그냥 if ([ReaderDocument isPDF:fullFilePath])을한다. 그것은 동등하고 안전하다.

+0

문서는 완료 블록 내에서 호출 할 때 nil을 효과적으로하지만 왜 dispatch_group_leave 관련이 있습니까? – tiguero

+0

무엇 말하자면, TWReaderDocument documentFileURL : withCompletionBlock :]은 사실상 TWReaderDocument의 새로운 인스턴스를 반환하는 factory 메소드입니다. 어떤 이유로 든 인스턴스가 생성되지 않으면 completionBlock은 절대로 앞에서 설명한 것처럼 TWReaderDocument의 내부에 대해 알지 못해서는 알 수 없다. 다른 쪽에서 추론하기 : 만일 당신의'dispatch_group_notify'가 호출되지 않으면'dispatch_group_leave'의 하나 또는 그 이상의 인스턴스가 * 또한 * 호출되지 않음 – ipmcc

+0

내 편집을 참조하십시오. 내 공장 방식을 공개했습니다. 상당히 길지만 ... Btw 문서는 외부가 아닌 완료 블록 내에서만 nil입니다. – tiguero