3

私の 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:] です。

このメモリ スパイクが発生する理由について何か考えはありますか? ありがとう

4

0 に答える 0