【问题标题】:Error trying to assigning __block ALAsset from inside assetForURL:resultBlock:尝试从assetForURL:resultBlock 中分配__block ALAsset 时出错:
【发布时间】:2011-11-29 08:05:58
【问题描述】:

我正在尝试创建一个方法,该方法将为给定的资产 url 返回一个 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;
}

问题是 assetToReturn 给出了 EXC_BAD_ACCESS。

如果我尝试从块内部分配指针,会有问题吗?我看到了一些块的例子,但它们总是使用简单的类型,比如整数等。

【问题讨论】:

  • 在 iOS(iPhone、iPad)上询问有关 Cocoa Touch 的问题时,请使用“cocoa-touch”标签。 “cocoa”标签是针对 Mac OS X 上的 Cocoa 的问题。
  • 顺便说一句:retainCount 在这种情况下毫无用处。

标签: cocoa-touch objective-c-blocks alasset


【解决方案1】:

一些事情:

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

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

- (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];
}

【讨论】:

    【解决方案2】:

    您应该retainautorelease 资产:

    // ...
    assetToReturn = [asset retain];
    // ...
    
    return [assetToReturn autorelease];
    

    【讨论】:

    • 这绝对是正确的。资产必须保留才能在区块范围之外继续存在。
    • 在 ARC 下,这不适用。
    • 确实如此,但是在ARC下__block是strong而不是assign,所以编译器仍然会添加缺少的retain。这个问题虽然没有使用 ARC。
    猜你喜欢
    • 2018-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-02
    • 2012-03-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多