0

アップデート:
質問の文脈を明確にするため。問題は問題を回避する方法ではなく、ドキュメントの一部が何を意味するかを明確にすることです。私の実験では、ドキュメントに基づいてアンロードする予定だったビューがアンロードされていないことが示唆されています。これがバグなのか、ドキュメントを誤解しているのかを理解したいと思います。代わりに問題を解決するために、viewDidLoad ではなく viewWillAppear で画像を設定し、viewDidDisappear で画像を nil に設定すると、メモリが解放され、アプリがクラッシュしないことがわかっています。ただし、初期コードでメモリを解放する必要があるかどうかを理解したいと思います。実験は、このようなビュー コントローラーをアウトレットとして使用し、UI 画像 (背景...) を設定する代わりに Interface Builder で設定することをシミュレートするためです。ビューのコードでそれらを表示します...

オリジナル:
View Controller Programming Guide に記載されているように、iOS6 のいくつかの新しい側面を理解しようとしています:

iOS 6 以降では、View Controller は必要に応じて独自のビューをアンロードする View Controller のデフォルトの動作は、View プロパティが最初にアクセスされたときにビュー階層をロードし、その後、View Controller が破棄されるまでメモリに保持することです。ビューが画面上に自分自身を描画するために使用するメモリは、潜在的に非常に大きくなります。ただし、ビューがウィンドウに関連付けられていない場合、システムはこれらの高価なリソースを自動的に解放します。ほとんどのビューで使用される残りのメモリは十分に小さいため、システムがビュー階層を自動的に消去して再作成する価値はありません。

rootViewController を使用して単純なアプリを作成しているとしましょう。この rootViewController にはいくつかの子 View Controller があり、コードで割り当てられるのではなく、すべて IBOutlets として宣言されています。

@property(nonatomic,strong) IBOutlet ChildViewController *childViewController1;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController2;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController3;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController4;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController6;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController7;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController8;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController9;
@property(nonatomic,strong) IBOutlet ChildViewController *childViewController10;

rootViewController にはいくつかのボタンがあり、それぞれを押すと、各 childViewController で簡単な presentModalViewController 操作が実行されます。

-(IBAction)showChild1Action:(id)sender{
  [self presentModalViewController:self.childViewController1 animated:true];
}


各 childViewController には、子ビュー コントローラーを閉じる閉じるボタンがあります。

-(IBAction)closeAction:(id)sender{
  [self dismissModalViewControllerAnimated:true];
}


ドキュメントからの私の期待は、子View Controllerが閉じられると、子View Controllerビューオブジェクトがメモリから解放されることでした。
ただし、大きなビュー オブジェクトを使用して意図的にテストし、そのようなアプリでプロファイルを実行すると、子コントローラーが表示されるたびにメモリ使用量が増加し続け、子コントローラー #7 などを表示するとアプリが最終的にクラッシュします。

その点で iOS6 で何が変わったのか、あなたはどのように理解していますか?

RootViewController.h

#import <UIKit/UIKit.h>
#import "ChildViewController.h"

@interface RootViewController : UIViewController

@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController1;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController2;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController3;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController4;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController5;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController6;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController7;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController8;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController9;
@property(nonatomic,strong) IBOutlet ChildViewController *level2ViewController10;

-(IBAction)showChild1Action:(id)sender;
-(IBAction)showChild2Action:(id)sender;
-(IBAction)showChild3Action:(id)sender;
-(IBAction)showChild4Action:(id)sender;
-(IBAction)showChild5Action:(id)sender;
-(IBAction)showChild6Action:(id)sender;
-(IBAction)showChild7Action:(id)sender;
-(IBAction)showChild8Action:(id)sender;
-(IBAction)showChild9Action:(id)sender;
-(IBAction)showChild10Action:(id)sender;

@end

RootViewController.m

#import "RootViewController.h"

@interface RootViewController ()

@end

@implementation RootViewController

@synthesize level2ViewController1;
@synthesize level2ViewController2;
@synthesize level2ViewController3;
@synthesize level2ViewController4;
@synthesize level2ViewController5;
@synthesize level2ViewController6;
@synthesize level2ViewController7;
@synthesize level2ViewController8;
@synthesize level2ViewController9;
@synthesize level2ViewController10;


- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

-(IBAction)showChild1Action:(id)sender{
    self.level2ViewController1.index=0;
    [self presentModalViewController:self.level2ViewController1 animated:true];
}
-(IBAction)showChild2Action:(id)sender{
    self.level2ViewController2.index=1;
    [self presentModalViewController:self.level2ViewController2 animated:true];
}
-(IBAction)showChild3Action:(id)sender{
    self.level2ViewController3.index=2;
    [self presentModalViewController:self.level2ViewController3 animated:true];
}
-(IBAction)showChild4Action:(id)sender{
    self.level2ViewController4.index=3;
    [self presentModalViewController:self.level2ViewController4 animated:true];
}
-(IBAction)showChild5Action:(id)sender{
    self.level2ViewController5.index=4;
    [self presentModalViewController:self.level2ViewController5 animated:true];
}
-(IBAction)showChild6Action:(id)sender{
    self.level2ViewController6.index=5;
    [self presentModalViewController:self.level2ViewController6 animated:true];
}
-(IBAction)showChild7Action:(id)sender{
    self.level2ViewController7.index=6;
    [self presentModalViewController:self.level2ViewController7 animated:true];
}
-(IBAction)showChild8Action:(id)sender{
    self.level2ViewController8.index=7;
    [self presentModalViewController:self.level2ViewController8 animated:true];
}
-(IBAction)showChild9Action:(id)sender{
    self.level2ViewController9.index=8;
    [self presentModalViewController:self.level2ViewController9 animated:true];
}
-(IBAction)showChild10Action:(id)sender{
    self.level2ViewController10.index=9;
    [self presentModalViewController:self.level2ViewController10 animated:true];
}

@end

ChildViewController.h

#import <UIKit/UIKit.h>

@interface ChildViewController : UIViewController

@property(nonatomic,weak) IBOutlet UIImageView *image1;

@property NSInteger index;

-(IBAction)closeAction:(id)sender;

@end

ChildViewController.m

#import "ChildViewController.h"

@interface ChildViewController ()

@end

@implementation ChildViewController

@synthesize image1;
@synthesize index;


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    if(self.index==0)
        [self.image1 setImage:[UIImage imageNamed:@"IMG1.JPG"]];
    if(self.index==1)
        [self.image1 setImage:[UIImage imageNamed:@"IMG2.JPG"]];
    if(self.index==2)
        [self.image1 setImage:[UIImage imageNamed:@"IMG3.JPG"]];
    if(self.index==3)
        [self.image1 setImage:[UIImage imageNamed:@"IMG4.JPG"]];
    if(self.index==4)
        [self.image1 setImage:[UIImage imageNamed:@"IMG5.JPG"]];
    if(self.index==5)
        [self.image1 setImage:[UIImage imageNamed:@"IMG6.JPG"]];
    if(self.index==6)
        [self.image1 setImage:[UIImage imageNamed:@"IMG7.JPG"]];
    if(self.index==7)
        [self.image1 setImage:[UIImage imageNamed:@"IMG8.JPG"]];
    if(self.index==8)
        [self.image1 setImage:[UIImage imageNamed:@"IMG9.JPG"]];
    if(self.index==9)
        [self.image1 setImage:[UIImage imageNamed:@"IMG10.JPG"]];

}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

-(IBAction)closeAction:(id)sender{
    [self dismissModalViewControllerAnimated:true];
}

Instrumentsを使用すると、次のような観察結果が得られます。

  • メモリ割り当てインストゥルメントは、私が期待するものを示しています:子ビューコントローラーが表示されると増加し、子ビューが閉じられると減少する合計割り当て これは、3 つの子ビュー コントローラーを表示してから閉じた後です。

  • ただし、アクティビティ インジケーターは別の話をしています。実際のメモリはすべての presentModalViewController で増加し、それらを破棄しても決して減少しません。

これは、3つの子View Controllerを表示/非表示にした後でもあります

4

3 に答える 3

1

最終的にAppleから返された答え:

あなたの「大きなリソース」は、たまたま +imageNamed: 経由でキャッシュにロードした画像です。それらはキャッシュされてロードされるため、自動クリーンアップから除外されます。通常、-drawRect: または Core Animation によって生成されたコンテンツのみが、ここで自動的にリリースされます。ビューは引き続き存在するため、これらのキャッシュされた画像への参照を保持し続け、メモリ警告でそれらをパージすることもできません

キャッシュされたリソースは、ドキュメントに記載されている自動クリーンアップの一部ではないようです。これらのリソースは、参照が停止したときにのみ割り当てが解除されます。

于 2013-02-01T00:26:09.630 に答える
0

imageNamed:useを使用する代わりにinitWithContentsOfFile.

例えば:

__weak NSString *filePath = [[NSBundle mainBundle] pathForResource:@"image" ofType:@"png"];
self.imageView.image = [[UIImage alloc] initWithContentsOfFile:filePath];

allocメソッドが使用されているため、GC はこのオブジェクトをマークしています。filePathGC クリーンアップのために文字列をマークすることもできます 。

于 2013-05-03T14:50:54.003 に答える
0

どこかで漏れているようですね。システムがこれらのビューを解放していない場合でも、10 個の子コントローラーすべてを提示した後は、メモリ使用量が最大になるはずです。メモリの使用量が際限なく増加する場合、子コントローラーはおそらくビューをあきらめています (そのため、表示されるたびに新しいビューを作成しています) が、ビューの割り当てが解除されていません。子コントローラーの数を 2 つに減らしてみて、最終的に同じことが起こるかどうかを確認してください。または、Instruments を使用してリークを探します。

更新: -[UIImage imageNamed]ロードしたイメージを解放しないという評判があります。これがメモリの増加の原因である可能性があります。別の方法を使用して画像を読み込んでみるか、まったく読み込まないでください (実験にとってそれほど重要ではないため)。

于 2012-10-02T23:13:06.493 に答える