浅谈iOS 开发中的界面通信
在任何的軟件開發中都離不開界面與界面之間的通信,界面通信的最直接的方法就是界面傳值.
在開發過程中我們在頁面傳值時我們通常使用的方法有:屬性傳值法,block傳值法,代理傳值法,以及單例傳值法,通知傳值法
屬性傳值
屬性傳值多用于在將前一個頁面的值傳到后一個頁面去,也就是我們通常說的從前往后傳值
當第一個頁面push到第二個頁面的時候,我們在第二個頁面聲明一個屬性用于接受從第一個頁面傳遞過去的值,然后在push這個事件被觸發的時候進行賦值,也就是說,先初始化創建第二個控制器(頁面),然后通過創建的控制器來訪問它所對應的屬性,將即將傳遞的值賦給它,這樣就完成了屬性傳值.于是當頁面(控制器)被push到第二個頁面之后我們訪問它的屬性的時候,也就順便獲取到了傳遞過來的值.
例如:現在有兩個控制器FirstViewController和SecondViewController.我們在FirstViewController中創建一個UITextFiled,在SecondViewController中創建一個UILabel,然后在textField中輸入文字,我們使用導航控制器來控制頁面之間的跳轉,當我們跳轉到第二個頁面的時候,將在textField中輸入的文字傳遞給label,作為label上的文字.
代碼如下:
FirstViewController中:
self.navigationItem.title = @"First"; // 設置控制器的背景顏色 self.view.backgroundColor = [UIColor yellowColor]; // 設置控制器的右按鈕,并創建事件點擊調到下一頁面 self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"第二頁" style:UIBarButtonItemStyleDone target:self action:@selector(next:)]; // 創建輸入框 self.firstTF = [[UITextField alloc] initWithFrame:CGRectMake(50, 100, 314, 40)]; self.firstTF.placeholder = @"請輸入文字!"; _firstTF.borderStyle = UITextBorderStyleLine; [self.view addSubview:_firstTF]; 復制代碼SecondViewController中:
self.navigationItem.title = @"Second"; self.view.backgroundColor = [UIColor cyanColor]; self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回" style:UIBarButtonItemStyleDone target:self action:@selector(back:)]; self.secondLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 314, 40)]; self.secondLabel.backgroundColor = [UIColor orangeColor]; // 由上一個頁面通過屬性傳值傳過來 self.secondLabel.text = _tfString; [self.view addSubview:_secondLabel]; 復制代碼我們在SecondViewController的.h文件中設置一個字符串屬性用來接收從FirstViewController中傳遞過來的值.
@property(nonatomic,strong)NSString *tfString;
那么我們在什么時候傳遞這個值呢?
合適的地方應該是在第一個頁面跳轉到第二個頁面的時候創建,也就是在push方法執行之前進行傳值.我們在FirsrViewController的右按鈕點擊事件也就是next方法中進行傳值.
-(void)next:(UINavigationController *)sender{ScondViewController *secondNC = [[ScondViewController alloc] init];// 將第一個界面的輸入框信息賦值給第二個頁面的LabelsecondNC.tfString = _firstTF.text;[self.navigationController pushViewController:secondNC animated:YES]; } 復制代碼這樣就實現了從前往后傳值,也就是屬性傳值
代理傳值
代理傳值多用于從后往前傳值.
我們還是使用上面的額例子,比如我們現在在SecondViewController中進行的相關的操作,現在我們要返回到第一個頁面,但是我們現在有一個需求就是需要在SecondViewController中創建一個UITextField,在FirstViewController中創建一個UILabel,當頁面pop回第一個頁面的時候將SecondViewController中textField中的文字傳遞到FirstViewController中的label上,這個時候,我們就可以使用代理傳值.
我們在SecondViewController的.h中創建一個協議,并且設置代理屬性,讓其遵循該協議.
代碼如下:
// 設置一個協議方法 @protocol SecondVCDelegate // 代理傳值 - (void)passValue:(NSString *)value; @end 復制代碼// 聲明代理屬性進行代理傳值 @property(nonatomic,weak)id delegate; 復制代碼在SecondViewController中創建textField
self.secondTF = [[UITextField alloc] initWithFrame:CGRectMake(50, 200, 314, 40)];self.secondTF.placeholder = @"請輸入";self.secondTF.borderStyle = UITextBorderStyleLine;[self.view addSubview:_secondTF]; 復制代碼在FirstViewController中創建label并讓其遵循協議
#import "FirstViewController.h" #import "ScondViewController.h" @interface FirstViewController ()@property(nonatomic,strong)UILabel *firstLab;@end 復制代碼創建UILabel
self.firstLab = [[UILabel alloc] initWithFrame:CGRectMake(50, 200, 314, 40)];self.firstLab.backgroundColor = [UIColor magentaColor];[self.view addSubview:_firstLab]; 復制代碼我們在上述屬性傳值代碼中已經為SecondViewController的導航控制器設置了右按鈕(返回按鈕),那么,我們只需要在其觸發事件(back:)中讓代理去執行傳值即可. 代碼如下:
- (void)back:(UINavigationController *)sender{// 代理去執行傳值[_delegate passValue:_secondTF.text];[self.navigationController popViewControllerAnimated:YES]; } 復制代碼然后在FirstViewController的next方法中為SecondNC制定其代理為其自身即可.
實現其代理方法
- (void)passValue:(NSString *)value{_firstLab.text = value; } 復制代碼這樣我們就可以在第一個頁面得到第二個頁面的值了.
block傳值
block的本質就和其他OC中變量類似,只不過,block中存儲的數據是函數體,但是在使用block時完全可以像調用其他函數似的,傳入參數,然后得到返回值.關于詳細的block,在這里就不贅述了.
在iOS開發中我們用到block進行傳值的情況多數情況下也是在從后往前傳值.所以我們依然使用上述例子.
使用block傳值,首先我們需要在SecondViewController中定義并聲明block屬性.
// 定義有參無返回值的匿名函數(傳遞字符串) typedef void(^MyBlock)(NSString *); 復制代碼@interface SecondViewController : UIViewController @property(nonatomic,copy)MyBlock block; @end 復制代碼同上,我們將SecondViewController中textField中輸入的文字傳遞到FirstViewController中的label上顯示.
我們在SecondViewController的back方法中調用block,并且將在這個控制器的textField中的文字作為block的參數傳遞給block.
- (void)back:(UINavigationController *)sender{// 代理去執行傳值self.block(_secondTF.text);[self.navigationController popViewControllerAnimated:YES]; } 復制代碼然后我們在FirstViewController的next方法中,也就是alloc出SecondViewController的時候調用SecondViewController的block,實現傳值
- (void)back:(UINavigationController *)sender{__weak typeof(self)temp = self;secVC.block = ^(NSString *string){// 通過回調將傳進來的字符串賦值給labeltemp.firstLab.text = string;};[self.navigationController popViewControllerAnimated:YES]; } 復制代碼在上述代碼中,因為block里面不能直接使用屬性,實例變量和方法(因為會造成循環引用),所以我們重新用__weak修飾self并重新命名為temp.這樣我們就實現了傳值.
單例傳值
由于單例在內存中只創建一次的并且可以全局訪問的屬性,我們可以在必要的時候將數據存放在單例的屬性中,并且在必要的時候從單例中通過訪問其屬性進行調用,這樣就實現值的傳遞
首先我們先創建一個單例類DataHandle,在其.h文件中我們使用類方法聲明單例創建的方法,并且聲明一個字符串屬性用來保存值,(因為我們依然使用上述的例子,所以聲明字符串,來保存textField中輸入的文字,在實際的開發過程中,讀者可以自己根據實際情況而定).
@interface DataHandle : NSObject // 創建單例 + (instancetype)sharedDataHandle; @property(nonatomic,strong)NSString *Str; @end 復制代碼在.m文件中實現其初始化方法
@implementation DataHandle // 聲明靜態區對象的原因,希望程序運行期間,在內存中一直存在,這樣對外界來說,可以隨時讀取數據 static DataHandle *dataHandle = nil; // 創建單例(全局區) + (instancetype)sharedDataHandle{if (nil == dataHandle) {// 我們創建單例使用加號方法的原因是因為,在創建之前,無法存在一個實例對象去調用動態方法來創建它本身dataHandle = [[DataHandle alloc] init];}return dataHandle; } @end 復制代碼無論是從FirstViewController中將textField的值傳到SecondViewController的label上還是反過來傳值.我們只需要在需要的時候通過其類方法(+ (instancetype)sharedDataHandle)來創建出單例對象來,然后將textField的text屬性以賦值的方式賦給單例的Srt屬性即可
代碼如下:
-(void)next:(UINavigationController *)sender{DataHandle *dataHandle = [DataHandle sharedDataHandle];ScondViewController *secondNC = [[ScondViewController alloc] init];// 將第一個界面的輸入框信息賦值給第二個頁面的LabeldataHandle.Str = _firstTF.text;[self.navigationController pushViewController:secondNC animated:YES]; } 復制代碼假使在SecondViewController中我們為label的text賦值,而其值就是FirstViewController中在textField中輸入的值,那么我們可以這樣寫:
DataHandle *dataHandle = [DataHandle sharedDataHandle]; self.secondLabel.text = dataHandle.str; 復制代碼如上所述就實現了值的傳遞. 其實單例不知是在兩個頁面之間進行傳遞,由于單例的一次創建全局訪問的特點,我們可以將值傳遞到ThreeViewController,FourViewController等等的控制器,相反的也可以反向傳遞,在此就不在重復了,其實原理都是相同的.
通知傳值
通知在iOS開發中占據著非常重要的地位,通常在兩個頁面關聯不大,但是需要傳遞信息的時候傳遞,這樣就可以通過通知來實現.
我們新建一個控制器來一鍵切換所有控制器的背景顏色.我們為其取名為:SettingViewController
創建一個UIButton來控制背景顏色的切換.并且為其設置觸發事件 在其出發事件中我們發送消息,并且設置通知的name為"change"用來標記通知,設置userInfo,userInfo是一個字典,我們需要將所有控制器的顏色設置為灰色,于是,我們在創建字典的時候其Value值為[UIColor lioghtGrayConlor].
- (void)changeColor:(UIButton *)sender { // 發送消息[[NSNotificationCenter defaultCenter] postNotificationName:@"change" object:nil userInfo:@{@"color":[UIColor lightGrayColor]}]; } 復制代碼這樣當我們點擊該button的時候,就發送了一條消息.在其他控制器里,我們設置觀察者,注冊消息.
// 注冊消息[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(changeTheme:) name:@"change" object:nil]; 復制代碼當收到消息之后,就會執行changeTheme:方法,我們就可在該方法中獲取發送的消息中所傳遞過來的數據(顏色信息),進行控制器背景顏色的改變.
- (void)changeTheme:(NSNotification *)sender{ self.view.backgroundColor = sender.userInfo[@"color"]; } 復制代碼在所有控制器里都添加觀察者注冊消息,并且實現changeTheme方法就實現了背景顏色的切換,而sender.userInfo[@"color"]就是從其他控制器中傳遞過來的值.我們可以改變userInfo這個字典的信息,從而實現其他類型的值的傳遞.
總結
以上介紹了五種界面通信的方法,由于筆者自身水平有限,其中難免會有疏漏,還請讀者指正,如果有不明白的問題,歡迎在評論區留言討論指教,我將不勝感激,另,轉載請注明出處......
總結
以上是生活随笔為你收集整理的浅谈iOS 开发中的界面通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 贝聊运维自动化体系演化
- 下一篇: Powershell统计一周内创建的账户