這裏咱們用一個demo來講明ios是如何在視圖控制器之間傳遞重要的參數的。本文先從手寫UI來討論,在下一篇文章中討論在storyboard中傳遞數據。html
首先新建一個空工程,並添加一個根視圖控制器類,以下圖所示:java
#ios
在函數didFinishLunchingWithOption中添加幾行代碼,完成後以下:app
1
2
3
4
5
6
7
8
9
10
11
12
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
RootViewController *myRootViewController = [[RootViewController alloc] init];
myRootViewController.view.backgroundColor = [UIColor lightGrayColor];
self.window.rootViewController = myRootViewController;
return
YES;
}
|
完成之後運行,iOS模擬器顯示結果以下:ide
#函數
由圖中能夠看出,咱們自定義的myRootViewController已經成功在啓動時加載,顯示出了一個淺灰色的界面。post
隨後如法炮製新建另外一個viewController命名爲FirstSubViewController,同時在RootViewController的viewDidLoad函數中添加以下代碼:atom
1
2
3
4
5
6
7
8
9
10
|
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
// Do any additional setup after loading the view.
UIButton *firstVC = [UIButton buttonWithType:UIButtonTypeSystem];
firstVC.frame = CGRectMake(
60
,
244
,
200
,
80
);
[firstVC setTitle:@
"顯示下一個視圖"
forState:UIControlStateNormal];
[firstVC addTarget:self action:
@selector
(displayNextViewController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:firstVC];
}
|
以後還需定義一個函數,名爲displayNextViewController,函數體暫時設爲空。此時運行程序,界面中央將顯示一個按鈕「顯示下一個視圖」,可是單擊該按鈕沒有任何反應。這是由於響應函數displayNextViewController尚未實現。如今在該函數中添加代碼:spa
1
2
3
4
5
6
7
|
- (
void
)displayNextViewController
{
FirstSubViewController *firstSubVC = [[FirstSubViewController alloc] init];
[self presentViewController:firstSubVC animated:YES completion:^{
NSLog(@
"present first sub VC ok"
);
}];
}
|
完成後運行程序發現,按鈕已經有反應了,按下後回出現一個新的白色背景的新界面,這就是咱們在這裏定義的firstSubVC;代理
下一步實現界面的返回操做。在FirstSubViewController的viewDidLoad函數中創建一個回退按鈕,並實現其響應函數。代碼以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
// Do any additional setup after loading the view.
UIButton *goBack = [UIButton buttonWithType:UIButtonTypeSystem];
goBack.frame = CGRectMake(
60
,
244
,
200
,
80
);
[goBack setTitle:@
"返回上級界面"
forState:UIControlStateNormal];
[goBack addTarget:self action:
@selector
(goBackToPreviousViewController) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:goBack];
}
- (
void
)goBackToPreviousViewController
{
[self dismissViewControllerAnimated:YES completion:^{
NSLog(@
"Back to previous OK"
);
}];
}
|
到此爲止,咱們已經經過presentViewController和dismissViewController實現了視圖的切換,下面來考慮兩個視圖控制器之間的數據交流的問題。
在此以前,分別在RootViewController和FirstSubViewController中添加一個標籤和文本框,做爲數據的顯示和輸入部分。咱們的目的是在FirstSubViewController中輸入一個數字,而後再RootViewController顯示出來。
在這兩個類中分別用property來實現文本框和標籤欄:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
//RootViewController.m
@interface
RootViewController ()
@property
(strong,nonatomic) UILabel *lable;
@end
@implementation
RootViewController
- (UILabel *)lable
{
if
(!_lable)
{
_lable= [[UILabel alloc] initWithFrame:CGRectMake(
60
,
150
,
200
,
30
)];
_lable.textAlignment = NSTextAlignmentCenter;
_lable.text = @
"Hello World!"
;
_lable.backgroundColor = [UIColor whiteColor];
}
return
_lable;
}
…..
@end
//FirstSubViewController
@interface
FirstSubViewController ()
@property
(strong,nonatomic) UITextField *inputText;
@end
@implementation
FirstSubViewController
- (UITextField *)inputText
{
if
(!_inputText)
{
_inputText = [[UITextField alloc] initWithFrame:CGRectMake(
60
,
150
,
200
,
30
)];
_inputText.backgroundColor = [UIColor lightGrayColor];
}
return
_inputText;
}
…..
@end
|
在這兩個視圖控制器的viewDidLoad中分別添加以下代碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//RootViewController.m
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
// Do any additional setup after loading the view.
[self.view addSubview:self.label];
UIButton *firstVC = [UIButton buttonWithType:UIButtonTypeSystem];
…..
}
…..
//FirstSubViewController
- (
void
)viewDidLoad
{
[
super
viewDidLoad];
// Do any additional setup after loading the view.
//添加輸入框
[self.view addSubview:self.inputText];
UIButton *goBack = [UIButton buttonWithType:UIButtonTypeSystem];
…..
}
|
在視圖控制器之間進行數據傳遞能夠經過多種方法,下面將逐個實驗:
一、使用代理delegate的方法:
基本原理:FirstSubViewControllers試圖改變RootViewController的數據,可是除了操做本身內部的數據的能力以外,不能改變其餘類的數據。想要將這些數據傳遞出去,須要設置代理方法,獲取FirstSubViewControllers中數據的類來遵循該方法,經過實現該代理協議中的方法來獲取FirstSubViewControllers中的數據。
具體步驟:
首先在FirstSubViewController.h中定義協議:
1
2
3
4
5
6
|
@protocol
FirstSubViewControllerDelegate <nsobject>
@optional
- (
void
)getStringFromFirstSubViewControllerDelegate:(NSString *)outputString;
@end
</nsobject>
|
而後添加一個符合該協議的代理屬性:
1
2
|
@property
(nonatomic,weak) id<firstsubviewcontrollerdelegate> delegate;
</firstsubviewcontrollerdelegate>
|
在RootViewControlller.h中,聲明該類符合FirstSubViewControllerDelegate協議:
1
|
@interface
RootViewController : UIViewController<firstsubviewcontrollerdelegate></firstsubviewcontrollerdelegate>
|
在新建FirstSubViewController的實例後,將其delegate屬性定義爲self,同時實現協議中的方法,兩個函數以下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
- (
void
)getStringFromFirstSubViewControllerDelegate:(NSString *)outputString
{
self.lable.text = outputString;
}
- (
void
)displayNextViewController
{
FirstSubViewController *firstSubVC = [[FirstSubViewController alloc] init];
firstSubVC.delegate = self;
[self presentViewController:firstSubVC animated:YES completion:^{
NSLog(@
"present first sub VC ok"
);
}];
}
|
最後在FirstSubViewController.m的goBackToPreviousViewController中添加一句向delegate屬性發送獲取數據的消息:
1
2
3
4
5
6
7
|
- (
void
)goBackToPreviousViewController
{
[self.delegate getStringFromFirstSubViewControllerDelegate:self.inputText.text];
[self dismissViewControllerAnimated:YES completion:^{
NSLog(@
"Back to previous OK"
);
}];
}
|
這樣,大功告成了,在FirstSubViewController中的輸入框中輸入的內容,在按返回按鈕後回顯示在第一個界面的標籤上。
二、使用通知Notification的方法
關於通知的知識在將來將會詳述,在這裏只是簡要介紹一種使用通知這一機制的方法。
在使用通知以前,必須在默認通知中內心添加一個所謂「觀察者」和通知,這個通知是命名的,同時還指定了回調的方法。當該通知中心收到了某個對象發送了相應的通知時,將會調用指定的方法執行某項操做。通知的發送者同時還能夠發送相應的消息做爲通知的參數。
註冊通知中心能夠在RootViewController.m中的viewDidLoad函數的末尾添加以下函數:
1
2
|
//使用通知的方式實現
[[NSNotificationCenter defaultCenter] addObserver:self selector:
@selector
(changeLabelText:) name:@
"ChangeLabelTextNotification"
object:Nil];
|
此外還要實現觀察者的回調函數:
1
2
3
4
5
|
- (
void
)changeLabelText:(NSNotification *)notification
{
id text = notification.object;
_lable.text = text;
}
|
自此通知的接收端已經完成。
通知的發送端,只需在「返回上級界面」的相應函數中按照事先定義的名稱發送通知和參數便可:
1
2
|
//使用通知方式實現
[[NSNotificationCenter defaultCenter] postNotificationName:@
"ChangeLabelTextNotification"
object:_inputText.text];
|
此時運行,將會發現和代理模式起到了相同的做用。
除了代理和通知以外,還有其餘如KVO等方法,將來還會詳細探討。