私の iOS アプリには、ページングが有効になっている UIScrollView があります。各ページにはビュー (複数のサブビューを含む) が表示されます。常に 3 つの「ページ」のみが読み込まれます。現在表示されているページ、左側のページ、右側のページです。ロードはバックグラウンドで遅延して行われます。アプリはARCを使用しています。
各ページのビューは、主に Core Data から取得した画像で構成されています。この画像は大きい可能性があるため、最初にサムネイルが読み込まれ、後で大きな画像に置き換えられます。この大きな画像は、実際にはデータ ストアにあるものを縮小したものです。フル解像度のバージョンは別の画面に必要ですが、この画像スクローラーの場合は、ページに収まるだけで済みます。実際に保存された画像は、はるかに大きい場合があります (カメラからの写真の場合は 2448x3264)。Core Data の画像プロパティは外部ストレージを許可するように設定されているため、ほとんどの場合、SQLite データベースには保存されないことに注意してください。
すべてが正常に「機能」します。スクローラーと画像はすばやくロードされ (サムネイルが最初に表示され、すぐに大きな画像が表示されます)、スクロールも高速です。Instruments によると、メモリ使用量も良好です。後続のイメージが読み込まれると、より多くのメモリ スパイクが発生する可能性があります (すべてのイメージではなく、他のすべてのイメージでさらに 5 MB のスパイクが発生する可能性があります)。スパイクの原因となっている特定の画像はありません (読み込まれる画像の順序を変更しました。常に 11 番目です)。この記憶は決して解放されないようです。
画像がバックグラウンドで読み込まれるコードのスニペットを次に示します。
- (void)loadImageWithCardInstanceObjectId:(NSManagedObjectID *)cardInstanceObjectId
imageIndex:(NSUInteger)imageIndex
withInitialImageHandler:(void (^)(UIImage *image))initialImageHandler
withFinalImageHandler:(void (^)(UIImage *image))finalImageHandler
{
NSManagedObjectContext *tempMoc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
tempMoc.parentContext = [[DataManager sharedInstance] managedObjectContext];
[tempMoc performBlock:^{
CardInstance *ci = (CardInstance *)[tempMoc objectWithID:cardInstanceObjectId];
if (ci.cardInstanceImages.count == 0) {
// no card images, return the default image
dispatch_async(dispatch_get_main_queue(), ^{
initialImageHandler([UIImage imageNamed:@"CardNoImage.png"]);
});
return;
}
// have card images, pick the one according to the passed in index
UIImage *thumbnail = [[ci.cardInstanceImages objectAtIndex:imageIndex] thumbnailRepresentation];
dispatch_async(dispatch_get_main_queue(), ^{
initialImageHandler(thumbnail);
});
// THIS IS THE OFFENDING LINE
UIImage *fullImage = [[ci.cardInstanceImages objectAtIndex:imageIndex] imageRepresentation];
CGSize size = fullImage.size;
CGFloat ratio = 0;
if (size.width > size.height) {
ratio = 240.0 / size.width;
}
else {
ratio = 240.0 / size.height;
}
CGRect rect = CGRectMake(0.0, 0.0, ceilf(ratio * size.width), ceilf(ratio * size.height));
// create the image to display
UIGraphicsBeginImageContextWithOptions(rect.size, YES, 0);
[fullImage drawInRect:rect];
UIImage *imageToDisplay = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(), ^{
finalImageHandler(imageToDisplay);
});
}];
}
計測器では、割り当てを担当するライブラリ/呼び出し元は CoreData +[_PFRoutines readExternalReferenceDataFromFile:] です。
このメモリ スパイクが発生する理由について何か考えはありますか? ありがとう