我正在尝试创建一个方法,它将返回给定资产网址的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。
如果我尝试从块内部指定指针,是否会出现问题?我看到了一些块的例子,但它们总是使用整数等简单类型。
答案 0 :(得分:9)
一些事情:
ALAssetsLibrary
实例围绕创建ALAsset
的实例。ALAssetsLibraryChangedNotification
的观察者,当收到任何ALAsset
时,您需要重新获取任何其他的AssetsLibrary对象,因为他们不会更长时间有效。这可以随时发生。-assetForURL:resultBlock:failureBlock:
或任何与failureBlock:
的AssetsLibrary方法同步。他们可能需要提示用户访问库,并且不会立即执行其块。最好在成功块本身中将需要执行的操作放在成功上。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];
}
答案 1 :(得分:1)
您应该retain
和autorelease
资产:
// ...
assetToReturn = [asset retain];
// ...
return [assetToReturn autorelease];