【发布时间】:2014-07-12 11:11:28
【问题描述】:
我有一个返回 ALAsset 数据的方法。我为一个又一个资产调用此方法,以从它们获取 NSData 并将其上传到服务器。每 4 或 5 次调用后,代码就会卡在下面的 rep.size 调用上。当我在 XCode 中暂停并恢复执行时,它又开始工作了。我完全被难住了,任何帮助将不胜感激。
澄清:死锁/代码卡在 ALAssetsLibrary 代码中,而不是我的代码中。
附加信息:我只有一个 ALAssetsLibrary 实例,我确保它没有被任何其他线程使用。
+(void)getDataFromAssetURL:(NSString *) myImageURL ofType:(enum ImageType)imageType andPerformBlock:(NSDataBlock)block blocking:(BOOL)blocking
{
NSConditionLock * albumReadLock = nil;
if (blocking) {
albumReadLock = [[NSConditionLock alloc] initWithCondition:PENDING];
}
@autoreleasepool {
@try {
NSURL *str = [[NSURL alloc] initWithString: myImageURL];
ALAsset * asset = [[AppManager sharedInstance].assetObjectCache objectForKey:str];
if (asset && NO) {
block( [Util getDataFromAsset:asset ofType:imageType] );
// notifies the lock that "all tasks are finished"
[albumReadLock lock];
[albumReadLock unlockWithCondition:ALLFINISHED];
}
else {
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
@autoreleasepool {
@try {
[[AppManager sharedInstance].assetObjectCache setObject:myasset forKey:str];
NSData * assetData = [Util getDataFromAsset:myasset ofType:imageType];
block(assetData);
// notifies the lock that "all tasks are finished"
[albumReadLock lock];
[albumReadLock unlockWithCondition:ALLFINISHED];
}
@catch (NSException *exception) {
block(nil);
// important: notifies lock that "all tasks finished" (even though they failed)
[albumReadLock lock];
[albumReadLock unlockWithCondition:ALLFINISHED];
}
@finally {
}
}
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
block(nil);
// important: notifies lock that "all tasks finished" (even though they failed)
[albumReadLock lock];
[albumReadLock unlockWithCondition:ALLFINISHED];
};
if(str)
{
NSURL *asseturl = str;
[[AppManager sharedInstance].assetslibrary assetForURL:asseturl
resultBlock:resultblock
failureBlock:failureblock];
}
else {
block(nil);
// notifies the lock that "all tasks are finished"
[albumReadLock lock];
[albumReadLock unlockWithCondition:ALLFINISHED];
}
}
}
@catch (NSException *exception) {
block(nil);
// notifies the lock that "all tasks are finished"
[albumReadLock lock];
[albumReadLock unlockWithCondition:ALLFINISHED];
}
@finally {
}
}
if (blocking) {
// non-busy wait for the asset read to finish (specifically until the condition is "all finished")
[albumReadLock lockWhenCondition:ALLFINISHED];
[albumReadLock unlock];
}
}
+(NSData *)getDataFromAsset:(ALAsset *)myasset ofType:(enum ImageType)imageType
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = nil;
NSData *assetData = nil;
if (imageType == FULL_RESOLUTION) {
Byte *buffer = (Byte*)malloc(rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
assetData = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
}
else if (imageType == LARGE_IMAGE){
iref = [rep fullScreenImage];
UIImage * uiimage = [UIImage imageWithCGImage:iref];
////NSLog(@"%f %f", uiimage.size.width, uiimage.size.height);
assetData = UIImageJPEGRepresentation(uiimage, 1.0f);
}
else if (imageType == SQUARE_THUMB){
iref = [myasset thumbnail];
assetData = UIImageJPEGRepresentation([UIImage imageWithCGImage:iref], 1.0f);
}
else if (imageType == PERSPECTIVE_THUMB){
iref = [myasset aspectRatioThumbnail];
assetData = UIImageJPEGRepresentation([UIImage imageWithCGImage:iref], 1.0f);
}
return assetData;
}
新信息:原来问题仅出现在特定设备上。如上所述,如果我在 XCode 中暂停和取消暂停调试器,代码会向前移动。
【问题讨论】:
-
我还不知道解决方案,但我知道这是一种非常神秘的方法。您需要研究 GCD,其主要目的之一是减少这种令人头疼的锁。它还使代码更加简洁,并且您获得了更高级别的抽象。此外,如果您在 ARC 环境中,则大部分情况下都不需要使用自动释放池。至于调试死锁,请参见:cocoabuilder.com/archive/xcode/324247-debugging-deadlocks.html
-
就像我在问题中解释的那样,死锁来自 iOS(ALAssetLibrary 代码),而不是因为我使用的锁。我使用的锁只是为了使函数同步(不幸的是这是一个要求)。我正在更新问题以更清楚地表明死锁在 ALAssetLibrary 代码中。
-
@try/@catch 在 Objective-C 中的含义与在其他语言中不同。简单地说,它们只是一个更好的 Assert。您应该假设您的程序在捕获异常后处于损坏状态,唯一正确的做法是尽快中止程序。
-
你解决了吗?
-
@Devfly 是和否。我用另一部 iPhone 测试了相同的代码,每次都运行良好,没有问题。然后,我尝试了另一个示例应用程序,该应用程序访问了第一部 iPhone 上的 ALAssetLibrary,并且每次都能重现该问题。那部 iPhone 的照片库似乎已损坏。我重置了那部 iPhone 并恢复了照片库,此后没有发现问题。
标签: ios iphone alassetslibrary alasset