2011-02-10 7 views
25

Tôi đang cố gắng tìm ra mối quan hệ giữa appdelegate, RootViewControoler và UIApplication. Dưới đây là những gì tôi đã tìm ra cho đến thời điểm này:Mối quan hệ giữa AppDelegate, RootViewController và UIApplication là gì?

Khi bắt đầu đăng ký, main.m được tải.

Từ đây, tệp MainWindow.xib của bạn được tải.

Trong MainWindow.xib, Chủ sở hữu tệp của bạn thuộc loại UIApplication.

Bạn đặt đại biểu của UIApplication cho AppDelegate của mình.

Trong mã nguồn của AppDelegate, bạn có thể đặt RootViewController là chế độ xem đầu tiên được hiển thị.

Điều này có đúng không? Điều gì sẽ nhắc AppDelegate ban đầu chạy nó là

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { } 

phương pháp?

+1

đúng !, "didFinishLaunchingWithOptions" là phương pháp đầu tiên để thực thi! –

Trả lời

44

Khi ứng dụng Objective-C bắt đầu, nó bắt đầu bằng cách chạy hàm có tên main(). Nó không phải nằm trong tệp "main.m" nhưng đó là cách trình hướng dẫn Xcode thiết lập mọi thứ.

Bên trong chính chức năng wizard sản xuất(), có dòng này:

int retVal = UIApplicationMain(argc, argv, nil, nil); 

Đó là những gì bắt đầu "UIKit" khuôn khổ tạo nên toàn bộ ứng dụng. Bên trong UIApplicationMain, một đối tượng kiểu UIApplication được tạo ra. Và một phần của những gì UIApplication thực hiện khi ứng dụng khởi động là gọi phương thức applicationDidFinishLaunchingWithOptions trên thành viên ủy nhiệm của lớp UIApplication. Đại biểu này được thiết lập trong tệp MainWindow.xib là một thể hiện của lớp ProjectAppDelegate của bạn, một lớp con của NSObject tuân theo giao thức UIApplicationDelegate.

gì nhắc appdelegate ban đầu chạy nó ...

Bởi vì trong file MainWindow.xib của bạn, bạn đã kết nối (cũng wizard dự án đã kết nối thực tế) Chủ đầu tư của tập tin (đó là Đối tượng UIApplication) của "đại biểu" outlet cho đối tượng UIApplicationDelegate trong tệp .xib và lớp của UIApplicationDelegate được đặt thành lớp con UIApplicationDelegate của ứng dụng của bạn.

Và không có gì kỳ diệu về "MainWindow.xib", nó có thể được gọi là "Foo.xib", điều quan trọng là thuộc tính trong tệp Info.plist của bạn có tên "Main nib file base name" là "MainWindow". Đang thử đổi tên MainWindow.xib thành Foo.xib và thay đổi "Tên cơ sở tệp chính nib" trong Info.plist thành "Foo" và bạn sẽ thấy nó vẫn hoạt động.

EDIT: thêm về RootController

Một lần nữa, không có gì kỳ diệu về cái gọi là "RootController". Đây chỉ là tên của lớp con UIViewController được tạo cho bạn bởi trình thủ thuật dự án mới Xcode.

Thuật sĩ đặt mã trong dự án cho hai lớp: ProjectAppDelegate và ProjectViewController. Lớp ProjectAppDelegate chứa hai thành viên cửa hàng:

IBOutlet UIWindow *window; 
IBOutlet ProjectViewController *viewController; 

trong file MainWindow.xib, trường hợp của cả hai UIWindow và ProjectViewController được đặt, và nối với các cửa hàng trên trong ProjectAppDelegate.

gì được công cụ của bạn lên trên màn hình là mã này trong lớp ProjectAppDelegate của bạn:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {  

    // Override point for customization after application launch. 

    // Add the view controller's view to the window and display. 
    [self.window addSubview:viewController.view]; 
    [self.window makeKeyAndVisible]; 

    return YES; 
} 

Một lần nữa, không có gì thực sự kỳ diệu về điều này: wizard dự án tạo ra mã sẽ thêm "root" xem ViewController của bạn đến cửa sổ xem và làm cho cửa sổ hiển thị. Bộ điều khiển xem "gốc" của bạn đã được tạo trong tệp .xib và được nối với ổ cắm ProjectAppDelegate.

Rất hữu ích khi cố tạo một ứng dụng hoàn toàn một mình mà không cần sử dụng bất kỳ tệp nào trong trình hướng dẫn. Bạn sẽ tìm hiểu rất nhiều về cách các tệp .xib hoạt động và cách chúng liên quan đến các đối tượng mã.

+0

Chỉ cần upvoted này vì vậy tôi có thể nhìn thấy bạn đi từ 9997 đến 10k: p. Không phải là một câu trả lời xấu quá. –

+0

w00t :) Tuyệt vời, cảm ơn – Bogatyr

1

MainWindow.xib được định nghĩa trong info.plist của bạn là Main nib file base name. Trong MainWindow.xib của bạn, bạn xác định bộ điều khiển đầu tiên mà bạn muốn tải, trong trường hợp của bạn, RootViewController.

didFinishLaunchingWithOptions: là một phần của giao thức UIApplicationDelegate. Phương pháp này (trong iOS4.0 +) luôn được biết là người đầu tiên được gọi khi khởi chạy ứng dụng.

1

AppDelegate là đại biểu của UIApplication - nó lắng nghe tất cả các thông báo rằng UIApplication bài đăng lớp trong suốt vòng đời của nó. didFinishLaunching thông báo là một trong số đó và nó gây ra AppDelegate của bạn để gọi phương thức nói trên.

+5

Vâng, đại biểu không thực sự "nghe" thông báo (như đăng ký với tư cách người quan sát đến NSNotificationCenter). Thay vào đó, UIApplication xem liệu delegate có triển khai thực hiện các phương thức khác nhau hay không bằng cách sử dụng 'respondsToSelector:' và gọi chúng nếu chúng tồn tại (cần phải có chính xác tên được xác định trước, trái ngược với việc nghe thông báo nơi bạn có thể tự đặt tên cho bộ chọn đích). – DarkDust

15

Điểm khởi đầu của ứng dụng iOS luôn là main() chức năng (nhờ @bogatyr) mà thường chứa mã tương tự,

int main(int argc, char *argv[]) { 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 
    int retVal = UIApplicationMain(argc, argv, nil, nil); 
    [pool release]; 
    return retVal; 
} 

Hai thông số cuối cùng của UIApplicationMain rất quan trọng và ghi rõ tên lớp trưởng, và ứng dụng ủy nhiệm. Nếu chúng là nil, thì Info.plist sẽ được tìm kiếm cho cửa sổ chính xib (thường là MainWindow.xib).

// If nil is specified for principalClassName, the value for NSPrincipalClass 
// from the Info.plist is used. If there is no NSPrincipalClass key specified, the 
// UIApplication class is used. The delegate class will be instantiated 
// using init. 
.. UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName); 

Không nhất thiết phải đặt Chủ sở hữu tệp thông qua xib và chúng có thể được chỉ định trực tiếp trong hàm UIApplicationMain này.

principalClassName có thể là chuỗi UIApplication hoặc một lớp con của UIApplication. Tương tự, delegateClassName có thể được chỉ định trực tiếp trong phương pháp này. Lớp đại biểu được khởi tạo bằng cách sử dụng init như các tài liệu nói. Giả sử chúng ta xác định lớp của chúng tôi đại biểu - MyAppDelegate như là một chuỗi,

UIApplicationMain(int argc, char *argv[], nil, @"MyAppDelegate"); 

Đầu tiên một thể hiện của UIApplication được khởi tạo, sau đó sẽ tạo ra các lớp đại biểu từ chuỗi này sử dụng NSClassFromString Tôi cho rằng.

Khi delegateObject đã được khởi tạo và ứng dụng đã sẵn sàng, delegateObject này sẽ được thông báo bằng phương thức ủy nhiệm, didFinishLaunchingWithOptions.

Class delegateClass = NSClassFromString(@"MyAppDelegate"); 
id <UIApplicationDelegate> delegateObject = [[delegateClass alloc] init]; 

// load whatever else is needed, then launch the app 
// once everything is done, call the delegate object to 
// notify app is launched 
[delegateObject application:self didFinishLaunchingWithOptions:...]; 

Đây là cách UIApplication sẽ xử lý theo chương trình, nếu không sử dụng ngòi bút. Sử dụng ngòi ở giữa không khác nhiều.

+0

Không có gì ma thuật về main.m, nó có thể được gọi là foo.m, nơi bắt đầu là hàm int main (int argc, char * argv []). – Bogatyr

+0

@Bogatyr - vâng đó là hàm 'main()' là điểm bắt đầu. N Không có gì đặc biệt về 'main.m' như bạn đã nói. – Anurag

1

Đối với Universal - iPhone + iPad - ứng dụng bạn có thể chỉ định các NIB khác nhau tải trên mỗi nền tảng, trong bảng thông tin mục tiêu hoặc bằng cách thêm các phím NSMainNibFile~ipadNSMainNibFile~iphone vào Info.plist. Ngoài ra, bạn có thể thêm MainWindow~ipad.xib NIB vào mục tiêu của mình, nó sẽ được tải trên iPad thay vì MainWindow.xib, dựa trên khóa NSMainNibFile trong Info.plist.

Nếu bạn cần kiểm soát và tùy chỉnh nhiều hơn cho ứng dụng Universal, bạn có thể tải NIB bắt đầu theo cách thủ công. Mẫu dự án "Universal" có bản mẫu cho phương thức này, vì vậy cách nhanh nhất để bắt đầu sử dụng kỹ thuật này là tạo một dự án iOS mới với cấu hình Universal.

Trong các ví dụ trên, Main NIB File được đặt trong Info.plist (cài đặt đích) để bạn đã có NIB được nạp khi ủy nhiệm ứng dụng của bạn được gọi. Thông thường trong thiết lập này, đối tượng MyAppDelegate cũng sẽ được lưu trữ trong NIB (với một số IBOutlets) và số File's Owner của NIB sẽ được đặt thành UIApplication.

Để một dự án phổ quát có thể chứa hai bố cục thay thế, khóa Tệp NIB chính bị bỏ sót khỏi số Info.plist. Sau đó, nó instantiates đối tượng áp dụng đại biểu lập trình trong UIApplicationMain:

#import "MYAppDelegate.h" 

int main(int argc, char *argv[]) 
{ 
    @autoreleasepool { 
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([MYAppDelegate class])); 
    } 
} 

Sau đó kiểm tra môi trường và các thiết lập của bạn và tải các NIB thích hợp trong application:DidFinishLaunchingWithOptions:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
    _window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease]; 
    // Override point for customization after application launch. 
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 
    _viewController = [[[MYViewController alloc] initWithNibName:@"MYViewController_iPhone" bundle:nil] autorelease]; 
    } else { 
    _viewController = [[[MYViewController alloc] initWithNibName:@"MYViewController_iPad" bundle:nil] autorelease]; 
    } 
    _window.rootViewController = _viewController; 
    [_window makeKeyAndVisible]; 
    return YES; 
} 

- (void)dealloc { 
    [_window release]; 
    [_viewController release]; 
    [super dealloc]; 
} 

Bước mới là tạo ra một thư mục gốc MYViewController bằng tay, bốc NIB thích hợp. Trong thiết lập này, File's Owner là số MYViewController mới sáng bóng của bạn thay vì UIApplication. Nếu bạn muốn, MYViewController có thể chấp nhận phần lớn những gì bạn có thể đang sử dụng ứng dụng của bạn - thường đóng gói lớp mô hình cốt lõi của ứng dụng, hoạt động như một nguồn dữ liệu và ủy quyền cho các khung nhìn và những thứ khác trong NIB.

Vì vậy, bạn đang dự kiến ​​sẽ có một số gốc UIView trong NIB, và nó phải được nối với các ổ cắm view của File's Owner (MYViewController).

Lưu ý rằng NIB của MYViewController không thực sự được tải cho đến khi lần đầu tiên truy cập thuộc tính MYViewController.view. Chỉ sau đó sẽ được gọi là [MyViewController viewDidLoad]! Thời gian có thể xảy ra nhất là khi bạn thêm nó vào cửa sổ gốc.

Trong mã mẫu được hiển thị phía trên gốc UIWindow được khởi tạo bởi ứng dụng đại biểu, nhưng không có lý do nào bạn không thể đưa mã vào NIB thay thế. Nếu bạn chọn làm điều này, hãy cẩn thận. Nếu bạn đặt rootViewController của cửa sổ trong NIB cho chủ sở hữu của Tệp trong trường hợp đó, nó sẽ làm cho khung nhìn của trình điều khiển được thêm vào cửa sổ khi cửa sổ được kích hoạt. Hãy cẩn thận xây dựng NIB đầu tiên trong mọi trường hợp.

Đại biểu ứng dụng không nhất thiết cần phải có tham chiếu đến thư mục gốc UIWindow nếu bạn muốn MYViewController quản lý nó, nhưng nó có thể sạch hơn để giữ cửa sổ gốc khỏi NIB và quản lý nó trong ủy nhiệm ứng dụng .

Bên ngoài đó (!) Không có nhiều khác biệt so với phương pháp tiếp cận một nền tảng.