2

NSUserDefaults にいくつかのデータを保存する演習を行っています。データは、各画像に関する一意の識別情報を含むディクショナリ オブジェクトのリストです。リストは約 20 要素で、辞書内の情報は小さな文字列の集まりです。画像自体は確かに保存されません。

メモリ管理を学べるように、意図的に ARC を無効にしています。

プロファイラーを実行したところ、その配列を NSUserDefaults に格納する行でメモリ リークが発生しました。何か案は?

+ (void) addPhotoToRecentList:(NSDictionary *)photoInformation
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *photoId = [photoInformation objectForKey:(FLICKR_PHOTO_ID)];

    NSMutableArray *recentPhotoList = [NSMutableArray arrayWithArray:[defaults objectForKey:RECENT_PHOTO_LIST]];


    if (!recentPhotoList) {
        recentPhotoList = [[[NSMutableArray alloc] init] autorelease];
    } else {
        NSLog(@"recentPhotoList is %@", recentPhotoList);
        NSDictionary *photoElement;
        for (photoElement in recentPhotoList) {
            if ([photoId isEqualToString:[photoElement objectForKey:(FLICKR_PHOTO_ID)]]) {
                [recentPhotoList removeObject:photoElement];
                break;
            }
        }

        if (recentPhotoList.count == MAX_PHOTOS) {
            [recentPhotoList removeLastObject];
        }

    }

    [recentPhotoList insertObject:photoInformation atIndex:0];
    [[NSUserDefaults standardUserDefaults] removeObjectForKey:RECENT_PHOTO_LIST];
    [[NSUserDefaults standardUserDefaults] setObject:recentPhotoList forKey:RECENT_PHOTO_LIST];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

次の行を追加したことに注意してください。

[[NSUserDefaults standardUserDefaults] removeObjectForKey:RECENT_PHOTO_LIST];

それがメモリリークに役立つかどうか疑問に思っていますが、違いはありません。

その行をコメントアウトすると: [[NSUserDefaults standardUserDefaults] setObject:recentPhotoList forKey:RECENT_PHOTO_LIST];

その後、メモリリークはなくなりましたが、最近アクセスした画像のリストを保存することもできません.

これが、メモリリークがあるという事実を明らかにしたものです。Leaks Instrument を使用して Profiler を実行しました。また、その前にアナライザーを実行し、すべての問題を解決しました。警告はありません。

また、iOS のルールに違反している可能性もあります。頻繁に保​​存されるリストを変更できる 2 つの個別のビューがあります。近道として、それを NSUserDefaults に保存することにしたので、画像のリストを頻繁にクリックすると、毎回 NSUserDefaults に保存するように呼び出します。また、Recently Viewed List コントローラーを呼び出すと、NSUserDefaults からその情報が取得され、最新の写真が一番上に表示されるように更新されます。

これらのビューから到達可能なグローバル クラスを作成して一時的にリストに保存することを検討しています。その後、アプリがバックグラウンドになるか終了すると、NSUserDefaults を呼び出して保存しますが、このメモリ リークの原因を理解したいと思います。

ここに画像の説明を入力

この関数の呼び出し元は次のとおりです。

- (void) doActualWork
{
    if (!self.selectedPhotoDict) {
        NSLog(@"AMRO No picture selected must be an iPad");
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
        return;
    }

    photoData = [[FlickrFetcher imageDataForPhotoWithFlickrInfo:self.selectedPhotoDict format:FlickrFetcherPhotoFormatLarge] retain];

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    [RecentTableViewController addPhotoToRecentList:self.selectedPhotoDict];

    //With Splitviews this is how we refresh our view
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
        [self loadPhoto];
    }

}

これの呼び出し元は、フォト ビュー コントローラーをプッシュして特定の画像を読み込む別のビューからのものです。この関数をバックグラウンドで実行して、ネットワーク インジケーターをビジーに設定できるようにします。

- (void)setSelectedPhotoDict:givenSelectedPhotoDict
{
    if (_selectedPhotoDict) {
        [_selectedPhotoDict release];
    }

    _selectedPhotoDict = [givenSelectedPhotoDict retain];

    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
        [self.imageView setNeedsDisplay]; // any time our Model changes, redraw our View
        if (photoData) {
            [photoData release];
        }

        [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
        [self performSelector:@selector(doActualWork) withObject:Nil afterDelay:0.01];
    }    
}
4

2 に答える 2

1

問題は userdefaults にはありませんが、オブジェクトを初期化し、挿入および削除している mutableArray にあります。変更可能な配列オブジェクトがリリースされているかどうかを確認してください。アクセスしようとするとクラッシュします

于 2013-10-26T06:28:36.020 に答える
0

まず、ヒントをくれた Brad Allred に感謝します。

私を失望させたのは、回線を無効にした場合:

[[NSUserDefaults standardUserDefaults] setObject:recentPhotoList forKey:RECENT_PHOTO_LIST];

その後、リークはなくなりましたが、それは根本的な原因ではなく症状に対処していました.

メソッド addPhotoToRecentList() は、私の NSDictionary のセッター メソッドによって呼び出されています。

- (void)setSelectedPhotoDict: givenSelectedPhotoDict

ブラッドの勧めに従って、物件を再調査しました。

@property (nonatomic, retain) NSDictionary *selectedPhotoDict;

セッター関数には、次の行があると思いました。

_selectedPhotoDict = [givenSelectedPhotoDict retain];

だから私は保持を削除しました: _selectedPhotoDict = givenSelectedPhotoDict;

分析を実行し、すべてがクリーンで、プロファイラーを同じテストケースのセットで数回再実行したところ、リークはなくなりました。

于 2013-10-26T05:57:34.900 に答える