阻止在一个块内不知道该怎么做

时间:2014-01-07 21:59:55

标签: ios objective-c

我弄得一团糟,我正试图找出一种熟练的方法来解决这个问题,但我却陷入困境。我现在的问题是,在我想要它们之前我已经执行了代码,它与我的块有关。

以下代码的问题是在添加postToForm之前调用convertedImages方法并执行。我该如何解决这个问题呢?等待这种情况发生?或者我是否会以错误的方式解决这个问题? (我需要知道内存使用情况,需要在发布帖子后释放内存。)

以下是包含问题的代码:

// create serial queue
dispatch_queue_t queue = dispatch_queue_create("myQueue", 0);

// create dispatch group
dispatch_group_t group = dispatch_group_create();

for(id photos in photoUrls) {
    NSString *urlString = photos;

    // enqueue operation in queue
    dispatch_async(queue, ^{
        // enter the group
        dispatch_group_enter(group);

        // do something async, I do use another dispatch_queue for example
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            // wrap in autoreleasepool to release memory upon completion
            @autoreleasepool {
                // here for example the nested operation sleeps for two seconds
                NSURL *url = [NSURL URLWithString:urlString];
                ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

                [library assetForURL:url resultBlock:^(ALAsset *asset) {

                    //TODO: Deal with JPG or PNG
                    NSData *imageData = UIImageJPEGRepresentation([self thumbnailForAsset:asset maxPixelSize:1000], 0);
                    NSString *base64 = [imageData base64EncodedString];
                    NSLog(@"base64::%@",base64);
                    [convertedImages addObject:base64];

                } failureBlock:^(NSError *error) {
                    NSLog(@"that didn't work %@", error);
                }];


                dispatch_group_leave(group);
            }
        });

        // wait until the nested async operation leaves the group (e.g finishes its job)
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

        NSLog(@"Finished single operation.");
    });
}

// will be called once all operations complete
dispatch_async(queue, ^{
    NSLog(@"Finished all jobs. ");
    NSLog(@"how many::%lu",(unsigned long)convertedImages.count);
    [jsonWithPhotos setObject:convertedImages forKey:@"photo64"];
    [self postToForm];
});

4 个答案:

答案 0 :(得分:4)

在加载所有图像之前调用完成块的原因是您在错误的位置调用dispatch_group_leave(group);。您应该在ALAssetsLibrary的结果块(和错误块)中调用它。其余的是正确的(实际上正如Apple建议实现队列的完成块一样:由于GCD的私有队列是连续的,完成块不过是队列本身的最后一个块)。

编辑:据问: 事实是ALAssetsLibrary需要一些时间来提取所请求URL的数据(实际上有一个完成块,暗示操作是异步的)。因此,在请求当前URL的图像之后,您立即释放由dispatch_group_enter创建的信号量,并且可能在ALAssetsLibrary可以执行完成块之前发生这种情况。

现在,请注意您实现队列完成块的方式仅对串行队列有效,从iOS 5+开始,您可以通过指定创建并发队列(作为全局队列) DISPATCH_QUEUE_CONCURRENT作为队列类型,这种方法不再有效。如果没有一个串行队列,在这种情况下你有一个并发队列我会检查当前url是否是ALAssetsLibrary结果块中的最后一个并在那里调用完成块。

为了完整性,您可以使用dispatch_semaphore_t来处理这种情况,这在逻辑上比使用组等待更正确(这里您的组由1次操作组成),但是,我再说一遍,只是在逻辑上更好,结果是一样的。

我写的所有内容都是用Apple's concurrency programming guide

写的

答案 1 :(得分:0)

如果你想对所有这些使用dispatch_async,那么你将不得不以不同的方式运行。形成我可以告诉你的只是试图在后台完成所有这些。有几种不同的方法可以做到这一点,但我看到你的代码在后台线程中的一个块中进行,然后在完成时回调。这也是最节省内存的(而不是膨胀),因为它一次运行一次转换,而不是一次性完成所有操作并填满可用内存(并可能崩溃)。

dispatch_async into queue
{

    for loop to do all of your images
    {

    }

    dispatch_async into main thread saying finished queue
    {
        //function call or block with executing code
    }
}

将所有内容包裹在autoreleasepool中,只是为了增加内存管理的乐趣。

答案 2 :(得分:0)

为什么要将循环中的每个任务作为单独的异步作业来运行?将整个循环作为单个任务运行,并在该完成处理程序中调用主线程上的函数postToForm。

这样的东西
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 
                                         (unsigned long)NULL), ^(void) {
      [self convertImages];

   });

   // Call this on background thread
   - (void)convertImages {

      for(id photos in photoUrls) {
         // Do stuff  
      }

      // Now call function on main thread
      [[NSOperationQueue mainQueue] addOperationWithBlock:^ {
              [self updateUI];
      }];
    }

    // Must call this on main thread because we update the UI
    - (void)updateUI {
           NSLog(@"Finished all jobs. ");
           NSLog(@"how many::%lu",(unsigned long)convertedImages.count);
           [jsonWithPhotos setObject:convertedImages forKey:@"photo64"];
           [self postToForm];
    }

答案 3 :(得分:-1)

如果您有依赖项,则需要使用NSOperationQueues。使用操作队列,您可以设置操作之间的依赖关系,使得一个(或多个)在特定操作完成之前不会执行。

因此,例如,使用块(就像您拥有的那样),您可以实现如下所示。

NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ /* your work */ }];
NSBlockOperation* dependentOperation = [NSBlockOperation blockOperationWithBlock:^{ /* dependent work */ }];

[dependentOperation addDependency:operation];

NSOperationQueue* q = [[NSOperationQueue alloc] init];
[q addOperations:@[ operation, dependentOperation] waitUntilFinished:NO];

NSOperationQueues还会给你一些巧妙的东西,比如能够处理取消,如果你担心如果在其他地方出现故障而取消postToForm,这可能会派上用场。

如果您担心内存,可以将最大并发操作数设置为NSOperationQueue的一部分。

q.maxConcurrentOperationCount = 5;