块中的NSMutableArray addObject给出了null数组

时间:2014-12-10 12:31:09

标签: ios objective-c arrays alassetslibrary

我有一个列表ALAsset URL的数组。我想将该URL逐个转换为ALAsset并将其添加到新数组中。

这是我的代码:

-(void)retrieveAssetsWithArray:(NSArray *)assetsArray
{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Background work
        __block NSMutableArray *retrievedAssetsArray = [[NSMutableArray alloc] init];
        for (int i = 0; i < [assetsArray count]; i++)
        {
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
            [library assetForURL:[NSURL URLWithString:[assetsArray objectAtIndex:i]]
                     resultBlock:^(ALAsset *asset)
             {
                 if (asset)
                 {
                     NSLog(@"assetss: %@", asset);
                     [retrievedAssetsArray addObject:asset];
                     NSLog(@"assets arayyyy: %@", retrievedAssetsArray);
                 }
             }
             failureBlock:^(NSError *error)
             {
                 NSLog(@"Error: Cannot load asset - %@", [error localizedDescription]);
             }
             ];
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            // Update UI
            if ([self.delegate respondsToSelector:@selector(getRetrievedAssetsFromPhotoLibrary:)])
            {
                NSLog(@"retrievedAssetsArray :%@", retrievedAssetsArray);
                [self.delegate getRetrievedAssetsFromPhotoLibrary:retrievedAssetsArray];
            }
        });
    });
}

将URL转换为ALAsset的部分工作正常。但是当我尝试在retrievedAssetsArray

中记录时,dispatch_async(dispatch_get_main_queue()会返回这样的内容
retrievedAssetsArray :(
    "ALAsset - Type:Unknown, URLs:(null)",
    "ALAsset - Type:Unknown, URLs:(null)",
    "ALAsset - Type:Unknown, URLs:(null)",
    "ALAsset - Type:Unknown, URLs:(null)"
)

为什么会这样?任何人都可以告诉我如何解决这个问题?欢呼声。

4 个答案:

答案 0 :(得分:1)

我找到了问题的答案:

-(void)retrieveAssetsWithArray:(NSArray *)assetsArray
{
    __block NSMutableArray *retrievedAssetsArray = [[NSMutableArray alloc] init];
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

    for (NSString *string in assetsArray) {
        dispatch_async(queue, ^{
            [library assetForURL:[NSURL URLWithString:string] resultBlock:^(ALAsset *asset) {
                [retrievedAssetsArray 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 and return in delegate methods*/    
    dispatch_async(dispatch_get_main_queue(), ^{
        // Update UI
        if ([self.delegate respondsToSelector:@selector(getRetrievedAssetsFromPhotoLibrary:)])
        {
            NSLog(@"retrieve %@", retrievedAssetsArray);
            [self.delegate getRetrievedAssetsFromPhotoLibrary:retrievedAssetsArray];
        }
    });

}

答案 1 :(得分:0)

你应该像那样:

typedef void (^VoidBlock)(void);

-(void)retrieveAssetsWithArray:(NSArray *)assetsArray
{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        // Background work
        __block NSMutableArray *retrievedAssetsArray = [[NSMutableArray alloc] init];


        __block NSNumber *completCount = @0;
        VoidBlock internalCompletionBlock = ^{
            completCount = @(completCount.integerValue + 1);

            if (completCount.integerValue != assetsArray.count)
                return;

            dispatch_async(dispatch_get_main_queue(), ^{
                // Update UI
                if ([self.delegate respondsToSelector:@selector(getRetrievedAssetsFromPhotoLibrary:)])
                {
                    NSLog(@"retrievedAssetsArray :%@", retrievedAssetsArray);
                    [self.delegate getRetrievedAssetsFromPhotoLibrary:retrievedAssetsArray];
                }
            });
        };


        for (int i = 0; i < [assetsArray count]; i++)
        {
            ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
            [library assetForURL:[NSURL URLWithString:[assetsArray objectAtIndex:i]]
                     resultBlock:^(ALAsset *asset)
             {
                 if (asset)
                 {
                     NSLog(@"assetss: %@", asset);
                     [retrievedAssetsArray addObject:asset];
                     NSLog(@"assets arayyyy: %@", retrievedAssetsArray);
                 }
                 internalCompletionBlock();

             }
                    failureBlock:^(NSError *error)
             {
                 internalCompletionBlock();
                 NSLog(@"Error: Cannot load asset - %@", [error localizedDescription]);
             }
             ];
        }
    });
}

答案 2 :(得分:0)

尽管日志语句在任何结果块保证运行之前运行,但您的代码已设法通过外观恢复四个资产。

结果块是异步调用的,这意味着在任何资产实际放入retrievedAssetArray之前,您可以轻松地退出for循环。然后在主队列上执行NSLog。

您需要重构代码以计算结果块的执行次数,并在计数达到assetsArray中的对象数时调度到主队列。您需要检查结果块中的

答案 3 :(得分:0)

作为问题的一部分,您必须在异步ALAssetLibrary的整个持续时间内保留assetForURL:resultBlock:failureBlock:

因此,您可以考虑为ALAssetLibrary组织单例实例,例如:

static ALAssetsLibrary* library;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
});

主要问题是assetForURL:resultBlock:failureBlock:是异步方法,因此无论是通过调用resultBlock:还是failureBlock:,您都需要等到它完成执行。

您可以等待异步操作完成使用dispatch_groupdispatch_semaphore或减少异步操作次数的简单块,并在达到零时调用完成。