Pertanyaan Urutan inisialisasi dan pemuatan UIViewController


Saya cukup baru dalam pemrograman UI di Mac dan iPhone, dan saya telah menjalankan sesuatu yang agak membingungkan saya.

UIViewController memiliki 3 metode yang melibatkan inisialisasi dan tampilan:

  1. init (dan metode init-like)
  2. loadView
  3. viewDidLoad (metode delegasi)

Saya berharap ini terjadi dalam urutan di atas. Pertama UIViewController dialokasikan oleh beberapa objek lain, maka init segera dipanggil (atau beberapa metode init lainnya, seperti initWithStyle).

Hanya setelah objek diinisialisasi, saya berharap untuk memanggil fungsi loadView sendiri, setelah itu tampilan, setelah dimuat, memanggil metode delegasi viewDidLoad.

Ini tidak terjadi, misalnya:

@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

Menghasilkan keluaran konsol:

0
2
3
1

Metode loadView dan viewDidLoad, oleh karena itu, tidak dapat membuat panggilan delegasi, karena delegasi biasanya diatur setelah panggilan ke [super init], yang (seperti yang ditunjukkan di atas) disebut setelah loadView dan viewDidLoad telah berjalan:

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

Jika saya ingin menjalankan kode yang mengatur ViewController dalam beberapa cara, memberitahukan delegasi ketika berjalan, haruskah kode berada dalam metode init? Bukankah alasan untuk loadView ada untuk memungkinkan kode tersebut dijalankan pada saat yang tepat?

Sepertinya saya harus membuat metode initWithDelegate baru yang menetapkan delegasi ivar sebelum memanggil [super init], apakah ini benar, atau saya akan tentang ini dengan cara yang salah?

Terima kasih sebelumnya :)


35
2018-01-13 00:21


asal


Jawaban:


Sistem pemuatan tampilan pada iPhone bekerja seperti ini:

Ketika Anda menginisialisasi pengendali tampilan (baik dengan -init atau -initWithNibName: bundle :), itu tidak benar-benar membuat dan menginisialisasi tampilan. Saat Anda memanggil -view untuk pertama kalinya, panggilan -loadView. Secara default, -loadView hanya memuat tampilan dari file xib (nibName). Jika Anda menimpanya, Anda bertanggung jawab untuk membuat tampilan dan menugaskannya ke properti tampilan pengawas tampilan. Sebagai contoh:

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

Setiap kali Anda membuat tampilan, yang berbeda dari tampilan yang terlihat dan ditampilkan di layar, itu panggilan -viewDidLoad. (-viewDidAppear / -viewDidDisappear adalah untuk visibilitas tampilan di layar)

Karena kita sudah di luar jalur, mari pertimbangkan manajemen memori. Ketika tampilan di luar layar, sistem akan secara otomatis mengatur properti tampilan dari pengontrol tampilan ke nol. Masalahnya adalah semua subview dari pandangan itu bocor. Bagaimana? Nah, jumlah retensi untuk setiap subview adalah 2 (views mempertahankan subviews, dan controller view Anda memiliki outlet / ivar untuk itu). Ketika tampilan tidak ada, jumlah yang tersisa dari tampilan tersebut adalah 1. Tidak masuk akal jika tampilan tetap bertahan jika tampilan tidak ditampilkan, jadi Anda mengaturnya ke nol di -viewDidUnload (yang merupakan pengait untuk setiap kali tampilan diatur ke nol).


30
2018-01-13 01:16



Itu initWithNibName: bundle: metode adalah penginisialisasi yang ditunjuk untuk kelas UIViewController.

Coba ganti dan gunakan alih-alih 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
2018-01-13 00:32



-(void)awakeFromNib
{
}

hanya dipanggil jika Anda menggunakan papan cerita untuk menyimpan ViewController yang digambar di papan cerita Nib --- berarti bundel antarmuka.

urutan yang tepat adalah

-(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

Saat pindah ke ViewController baru

-(void)viewWillDisappear
-(void)viewDidDisappear

Saat kembali ke ViewController pertama

-(void)viewWillAppear
-(void)viewDidAppear

13
2017-09-11 10:03



Gerry3 benar. Barang-barang ini masih membingungkan saya juga. Lihat dokumennya inisialisasi yang ditunjuk.

Juga perhatikan bahwa jika pengontrol Anda dibuat oleh pena yang dimuat maka hanya initWithCoder yang akan dipanggil. loadView tidak dipanggil dalam kasus itu juga.

Karena ini sepertinya sebagian besar kode yang pernah saya lihat melakukan inisialisasi dalam hal-hal seperti viewDidLoad meskipun itu kelihatannya salah, tetapi tampaknya menjadi metode terbaik yang dipanggil dalam kedua kasus di mana sesuatu dimuat dalam pena dan dibuat secara terprogram.

Tapi alasan ini tampaknya rusak adalah bahwa [super init] memanggil loadView dll. -


4
2018-01-13 00:43



Mengambil saran @ Nimrod saya melakukan sesuatu seperti:

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

Saya tidak tahu apakah ini dapat menyebabkan masalah dengan memori bocor tetapi melihat dokumen Apple itu tampaknya tidak menciptakan siklus:

lihat lifecycle http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/Art/loading_a_view_into_memory.jpg

Ini diambil dari: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW1


0
2017-07-09 21:44