没有收到通知dispatch_group_notify

时间:2014-10-01 12:15:24

标签: ios grand-central-dispatch

我目前正在使用dispatch_group在所有并发任务完成时获取通知。我正在[TWReaderDocument documentFileURL:url withCompletionBlock:]类方法中的一个并发队列上卸载一些繁重的任务。

我已实现以下代码但从未收到任何通知。我在下面的代码中看不到我可能做错了什么:

    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 个答案:

答案 0 :(得分: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:返回NO,则永远不会调用completionBlock,返回的值将为nil

顺便说一句,你永远不应该比较== YES。 (任何非零都等于YES,但YES定义为1。只需if ([ReaderDocument isPDF:fullFilePath])。它等同,更安全。