thisのアプローチでは、Jesse Rusakの問題があります。資産が大きすぎるとアプリは、以下のスタックでクラッシュします。
0 CoreGraphics 0x2f602f1c x_malloc + 16
1 libsystem_malloc.dylib 0x39fadd63 malloc + 52
2 CoreGraphics 0x2f62413f CGDataProviderCopyData + 178
3 ImageIO 0x302e27b7 CGImageReadCreateWithProvider + 156
4 ImageIO 0x302e2699 CGImageSourceCreateWithDataProvider + 180
...
Link Register Analysis:
Symbol: malloc + 52
Description: We have determined that the link register (lr) is very likely to contain the return address of frame #0's calling function, and have inserted it into the crashing thread's backtrace as frame #1 to aid in analysis. This determination was made by applying a heuristic to determine whether the crashing function was likely to have created a new stack frame at the time of the crash.
Type: 1
クラッシュをシミュレートすることは非常に簡単です。ちょっとした塊で、getAssetBytesCallbackのALAssetRepresentationからデータを読みましょう。チャンクの特定のサイズは重要ではありません。重要なことは、コールバックを約20回呼び出すことだけです。ここで
static size_t getAssetBytesCallback(void *info, void *buffer, off_t position, size_t count) {
static int i = 0; ++i;
ALAssetRepresentation *rep = (__bridge id)info;
NSError *error = nil;
NSLog(@"%d: off:%lld len:%zu", i, position, count);
const size_t countRead = [rep getBytes:(uint8_t *)buffer fromOffset:position length:128 error:&error];
return countRead;
}
ログのテールラインは、私はこのクラッシュを防止するためのカウンタを導入
2014-03-21 11:21:14.250 MRCloudApp[3461:1303] 20: off:2432 len:2156064
MRCloudApp(3461,0x701000) malloc: *** mach_vm_map(size=217636864) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
です。
typedef struct {
void *assetRepresentation;
int decodingIterationCount;
} ThumbnailDecodingContext;
static const int kThumbnailDecodingContextMaxIterationCount = 16;
static size_t getAssetBytesCallback(void *info, void *buffer, off_t position, size_t count) {
ThumbnailDecodingContext *decodingContext = (ThumbnailDecodingContext *)info;
ALAssetRepresentation *assetRepresentation = (__bridge ALAssetRepresentation *)decodingContext->assetRepresentation;
if (decodingContext->decodingIterationCount == kThumbnailDecodingContextMaxIterationCount) {
NSLog(@"WARNING: Image %@ is too large for thumbnail extraction.", [assetRepresentation url]);
return 0;
}
++decodingContext->decodingIterationCount;
NSError *error = nil;
size_t countRead = [assetRepresentation getBytes:(uint8_t *)buffer fromOffset:position length:count error:&error];
if (countRead == 0 || error != nil) {
NSLog(@"ERROR: Failed to decode image %@: %@", [assetRepresentation url], error);
return 0;
}
return countRead;
}
- (UIImage *)thumbnailForAsset:(ALAsset *)asset maxPixelSize:(CGFloat)size {
NSParameterAssert(asset);
NSParameterAssert(size > 0);
ALAssetRepresentation *representation = [asset defaultRepresentation];
if (!representation) {
return nil;
}
CGDataProviderDirectCallbacks callbacks = {
.version = 0,
.getBytePointer = NULL,
.releaseBytePointer = NULL,
.getBytesAtPosition = getAssetBytesCallback,
.releaseInfo = NULL
};
ThumbnailDecodingContext decodingContext = {
.assetRepresentation = (__bridge void *)representation,
.decodingIterationCount = 0
};
CGDataProviderRef provider = CGDataProviderCreateDirect((void *)&decodingContext, [representation size], &callbacks);
NSParameterAssert(provider);
if (!provider) {
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithDataProvider(provider, NULL);
NSParameterAssert(source);
if (!source) {
CGDataProviderRelease(provider);
return nil;
}
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef) @{(NSString *)kCGImageSourceCreateThumbnailFromImageAlways : @YES,
(NSString *)kCGImageSourceThumbnailMaxPixelSize : [NSNumber numberWithFloat:size],
(NSString *)kCGImageSourceCreateThumbnailWithTransform : @YES});
UIImage *image = nil;
if (imageRef) {
image = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
}
CFRelease(source);
CGDataProviderRelease(provider);
return image;
}
+1:あなたは以下の私の修正を見ることができます。ドキュメントは、kCGImageSourceThumbnailMaxPixelSizeがこれに対して機能することを述べている間違っています。それはしません。 – akaru
ここに私の答えを参照してくださいhttp://stackoverflow.com/questions/8116524/the-best-way-to-get-thumbnails-with-alassetslibrary/13598533#13598533 UIViewContentModeScaleAspectFitなどとしてあなたImageViewのコンテンツモードを設定します。imageView.contentMode = UIViewContentModeScaleAspectFit ;そして、それは正方形のサムネイルを作成しないことが可能であるので、私はメインスレッド –