5

我正在尝试创建一种方法,该方法将为给定的资产 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。

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

4

2 回答 2

9

一些东西:

  1. 只要您使用资产,就必须ALAssetsLibrary创建的实例保留在周围。ALAsset
  2. 必须为 注册一个观察者ALAssetsLibraryChangedNotification,当收到ALAsset您拥有的任何 s 时,任何其他 AssetsLibrary 对象都需要重新获取,因为它们将不再有效。这可能随时发生。
  3. 不应期望-assetForURL:resultBlock:failureBlock:或任何带有 a 的 AssetsLibrary 方法failureBlock:是同步的。他们可能需要提示用户访问库,并且不会总是立即执行他们的块。最好将成功时需要发生的操作放在成功块本身中。
  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];
}
于 2011-10-02T21:52:31.787 回答
1

你应该retainautorelease资产:

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

return [assetToReturn autorelease];
于 2011-10-02T08:55:33.393 回答