web-dev-qa-db-ja.com

UIViewControllerの初期化とロードの順序

私はMacとiPhoneでのUIプログラミングにかなり慣れていないので、やや困惑する何かに出くわしました。

UIViewControllerには、その初期化とビューを含む3つのメソッドがあります。

  1. init(およびinit-likeメソッド)
  2. loadView
  3. viewDidLoad(デリゲートメソッド)

これらが上記の順序で発生することを期待しています。最初にUIViewControllerが他のオブジェクトによって割り当てられ、次にinitがすぐに呼び出されます(またはinitWithStyleなどの他のinitメソッド)。

オブジェクトが初期化されると、独自のloadView関数が呼び出され、その後、ビューが読み込まれるとviewDidLoadデリゲートメソッドが呼び出されます。

たとえば、これは起こりません。

@implementation UIViewControllerSubclass

- (id)init {
        NSLog(@"0");
    if (self = [super init]) {
        NSLog(@"1");
    }
    return self;
}

- (void)loadView {
    [super loadView];
    NSLog(@"2");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"3");
}

@end

コンソール出力を生成します。

0
2
3
1

したがって、loadViewメソッドとviewDidLoadメソッドは、デリゲートを呼び出すことができません。デリゲートは通常[super init]の呼び出しの後に設定されるため(上​​記を参照)、afterloadViewとviewDidLoadが実行されました:

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] init];
[viewController setDelegate:self];

何らかの方法でViewControllerをセットアップするコードを実行して、デリゲートに通知する場合、コードはinitメソッドに存在する必要がありますか?そのようなコードを適切なタイミングで実行できるようにするために、loadViewが存在する理由はありませんか?

私は、デリゲートivarbeforeを設定する新しいinitWithDelegateメソッドを作成する必要があるように見えます[super init]を呼び出す、または私はこれについて間違った方法で行っていますか?

前もって感謝します :)

37
Dani

IPhoneのビュー読み込みシステムは次のように機能します。

View Controllerを初期化するとき(-initまたは-initWithNibName:bundle:を使用)、実際にビューを作成および初期化することはありません。初めて-viewを呼び出すと、-loadViewが呼び出されます。デフォルトでは、-loadViewはxibファイル(nibName)からビューをロードするだけです。ただし、これをオーバーライドする場合は、ビューを作成し、View ControllerのViewプロパティに割り当てる必要があります。例として:

- (void)loadView
{
   UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
   // add subviews 
   self.view = view;
   [view release];
}

ビューを作成するたびに、表示されて画面に表示されるビューとは異なります、-viewDidLoadを呼び出します。 (-viewDidAppear/-viewDidDisappearは、画面上のビューの可視性のためです)

すでに軌道に乗っていないので、メモリ管理について考えてみましょう。ビューが画面外にある場合、システムは自動的にView ControllerのViewプロパティをnilに設定します。問題は、そのビューのすべてのサブビューがリークしていることです。どうして?さて、各サブビューの保持カウントは2です(ビューはサブビューを保持し、View Controllerにはアウトレット/ ivarがあります)。ビューがnilの場合、そのビューの保持カウントは1です。ビューが表示されていない場合、ビューが保持されても意味がないので、-viewDidUnload(これは、ビューがnilに設定されている場合)。

30
Saurabh Sharan

initWithNibName:bundle: メソッドは、UIViewControllerクラスの指定された初期化子です。

Initの代わりにオーバーライドして使用してみてください。

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

...

UIViewControllerSubClass *someViewController = [[UIViewControllerSubclass alloc] initWithNibName:@"UIViewControllerSubclass" bundle:nil];
16
gerry3
-(void)awakeFromNib
{
}

は、ストーリーボードを使用して、ストーリーボードのNib --- meansインターフェイスバンドルに描画されたViewControllerを格納する場合にのみ呼び出されます。

適切なシーケンスは

-(void)initWithCoder
-(void)awakefromNib    //(if story board is used)
    or
-(void)loadView----() //if manually generating the view contoller

-(void)viewDidLoad-----(called only once in the life cycle of viewController)
-(void)viewWillAppear
-(void)viewDidAppear

新しいViewControllerに移動中

-(void)viewWillDisappear
-(void)viewDidDisappear

最初のViewControllerに戻る間

-(void)viewWillAppear
-(void)viewDidAppear
13
Sauvik Dolui

gerry3が正しい。このことも私を混乱させます。 指定イニシャライザ のドキュメントをご覧ください。

また、ロードされるnibによってコントローラーが作成された場合、initWithCoderのみが呼び出されることに注意してください。その場合、loadViewも呼び出されません。

このため、私が見たコードのほとんどは、それが間違っているように見えてもviewDidLoadのようなものでほとんどの初期化を行っているように見えますが、何かがペン先にロードされて作成される両方のケースで呼び出される最良の方法のようですプログラムで。

しかし、これが順不同に思える理由は、[super init]がloadViewなどを呼び出しているためです。

4
Nimrod

@Nimrodの提案を受けて、私は次のようなことをしました:

-(void)viewDidLoad
{
    // Init code here
}

これがメモリリークの問題を引き起こす可能性があるかどうかはわかりませんが、Appleのドキュメントを見ると、サイクルを作成していないようです。

ライフサイクルを見るhttp://developer.Apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Art/loading_a_view_into_memory.jpg

これは、 http://developer.Apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//Apple_ref/doc/uid/TP40007457-CH10から取得されました-SW1

0
bitoiu