尝试从assetForURL内部分配__block ALAsset时出错:resultBlock:

mit*_*tnt 5 cocoa-touch objective-c-blocks alasset

我正在尝试创建一个方法,它将返回给定资产网址的ALAsset.(我需要稍后上传资产,并希望在结果块之外进行结果.)

+ (ALAsset*) assetForPhoto:(Photo*)photo
{
    ALAssetsLibrary* library = [[[ALAssetsLibrary alloc] init] autorelease];
    __block ALAsset* assetToReturn = nil;

    NSURL* url = [NSURL URLWithString:photo.assetUrl];
    NSLog(@"assetForPhoto: %@[", url);

    [library assetForURL:url resultBlock:^(ALAsset *asset) 
    {
        NSLog(@"asset: %@", asset);
        assetToReturn = asset;
        NSLog(@"asset: %@ %d", assetToReturn, [assetToReturn retainCount]);        

    } failureBlock:^(NSError *error) 
    {
        assetToReturn = nil;
    }];

    NSLog(@"assetForPhoto: %@]", url);
    NSLog(@"assetToReturn: %@", assetToReturn); // Invalid access exception coming here.

    return assetToReturn;
}
Run Code Online (Sandbox Code Playgroud)

问题是assetToReturn提供了EXC_BAD_ACCESS.

如果我尝试从块内部指定指针,是否有问题?我看到了一些块的例子,但它们总是有简单的类型,如整数等.

Ash*_*ark 9

一些东西:

  1. 必须保持ALAssetsLibrary周围创建的实例ALAsset,只要您使用的资产.
  2. 必须注册一个观察者ALAssetsLibraryChangedNotification,当收到ALAsset您的任何内容时,任何其他AssetsLibrary对象都需要重新获取,因为它们将不再有效.这可以随时发生.
  3. 不应期望-assetForURL:resultBlock:failureBlock:具有a的AssetsLibrary方法或任何AssetsLibrary方法failureBlock:是同步的.他们可能需要提示用户访问库,并且不会立即执行其块.最好在成功块本身中将需要执行的操作放在成功块上.
  4. 只有当你绝对必须在你的应用程序中使这个方法同步时(我建议你不要这样做),你需要在调用之后等待一个信号量,assetForURL:resultBlock:failureBlock:并且如果最终阻塞主线程,可以选择旋转runloop.

以下实现应满足所有情况下的同步调用,但实际上,您应该非常努力地使代码异步.

- (ALAsset *)assetForURL:(NSURL *)url {
    __block ALAsset *result = nil;
    __block NSError *assetError = nil;
    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    [[self assetsLibrary] assetForURL:url resultBlock:^(ALAsset *asset) {
        result = [asset retain];
        dispatch_semaphore_signal(sema);
    } failureBlock:^(NSError *error) {
        assetError = [error retain];
        dispatch_semaphore_signal(sema);
    }];


    if ([NSThread isMainThread]) {
        while (!result && !assetError) {
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
    }
    else {
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    }

    dispatch_release(sema);
    [assetError release];

    return [result autorelease];
}
Run Code Online (Sandbox Code Playgroud)