你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> iOS開發——從一道題看Delegate

iOS開發——從一道題看Delegate

編輯:IOS開發基礎

delegate-is-what-leaders-do.jpg

本文授權轉載:神獸gcc(簡書)

繼上次通過Storyboard完成了簡單地頁面跳轉之後,我發現了很多問題,比如從第二個頁面回跳到第一個頁面,並不是依照正向跳轉那樣簡單地模仿就好,在實際運行中會發現程序報錯了。這次,我們將結合一道經典的題目,完成對頁面跳轉、傳值以及附帶的相關鍵盤輸入的問題總結。題目源自《iOS開發之美》一書,有興趣的小伙伴可以去翻來看看,我在學習之後加入了很多自己的感悟和實際操作的情況。原題如下:

有兩個scene,分別為Scene A和Scene B。Scene A上有一個UIButton(Button A)和一個UILable(Lable A);Scene B上有一個UITextFiled(textFiled)。當單擊Scene A上的Button A時,跳轉到Scene B,在Scene B的textFiled上輸入文字,單擊鍵盤的“完成”按鈕,返回到Scene A,並在Scene A的Lable A上顯示剛才輸入的內容。

這是一個典型的場景之間的跳轉和逆向傳值問題,看似簡單,卻暗藏殺機。我們不僅要使用Storyboard框架,還要采用Delegate模式,最後達到題目要求。

Delegate

什麼是Delegate?跟這道題目又有什麼關系呢?

簡單分析一下題目,主要包括Storyboard的應用,頁面跳轉,數據的交互,似乎跟Delegate沒什麼關系呢。在這裡我決定先不刨根問底,留一個小懸念,在實際的解決問題的過程中去慢慢“悟”關於Delegate的一切,它是一種設計模式,並不是那麼簡單就能描述清楚的。

頁面之間的數據傳遞

iOS提供了多種方法,來實現頁面之間的數據傳遞:

  • 使用SharedApplication,定義一個類似全局的變量來傳遞

  • 使用文件,或者使用NSUserdefault來傳遞

  • 通過一個單例(SingleXX)的class來傳遞

  • 通過Delegate來傳遞

關於數據的存儲方式共有五種:

  • User Defaults

  • Property List(對應)

  • Object archives

  • SQLite

  • Core Data

在本道題目當中,顯然采用Delegate方式是最佳方案。

界面搭建

有了先前我們使用Storyboard的經驗,我們先很快的對界面進行搭建。先拋開所有的segue不管,先把題目中描述的情況展現出來再說。

我們新建名為delegateSentValue的工程,在原有viewController的基礎上再新建一個,同時新建名為viewController2的.h和.m文件,對它們進行關聯。再向兩個view中拖放組件,並且將它們關聯到相應的文件。這個過程應該是很簡單的,我們暫且不管需要響應事件的Button,只是將兩個Lable和一個textFiled在兩個.h文件中進行屬性聲明。完成後如下圖:

Snip20151019_72.png

Snip20151019_73.png

搭建完成界面之後,我們先實現從Scene A到Scene B的跳轉。通過“Ctrl+drag”操作,將Button與Scene B關聯,設置為“modal”模式,然後我們選中這個Segue,將它的identifier命名為Segue_ID_AB。

Snip20151019_74.png

我們可以先來運行下,這時我們可以實現通過點擊按鈕實現頁面正向跳轉的功能,點擊輸入框,我們可以接受鍵盤的輸入。

Delegate應用

我們所剩的任務還有輸入內容,單擊鍵盤上的“完成(return)”按鈕,返回Scene A,並將剛才輸入的內容顯示在Scene A中。

對於一個Delegate應用,需要5步來完成:

  • 委托者聲明一個Delegate

  • 委托者調用Delegate內的方法

  • 關聯委托者與被委托者

  • 被委托者遵循Delegate協議

  • 被委托者重寫Delegate內的方法

  • 委托者聲明一個Delegate

在ViewController2中,#import下,@interface前添加如下代碼:

@protocol ViewController2Delegate -(void) viewController2:(ViewController2 * )sceneBVC didInputed:(NSString * )string;
@end

在@interface中聲明:

@property (weak, nonatomic) id  delegate;

通過@protocol創建一個Delegate並聲明。

這裡需要注意的一點是,如果僅僅是按照上面的要求去添加代碼,會出現“Expected a type.”的錯誤,原因是我們要使用ViewController2類型,而這個類型先前是沒有定義過的,可是如果我們把@protocol,也就是上面三行代碼移到@property下面去的時候呢,在聲明中的ViewController2Delegate又出現了同樣的問題。於是乎,我們需要修改一下代碼的結構,我們首先創建Delegate,然後聲明,最後再在@interface的後面定義Delegate內的方法,這樣一來就沒有問題了。最後完整的ViewController2.h的代碼如下:

#import @protocol ViewController2Delegate;
@interface ViewController2 : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *showInformation2;
@property (weak, nonatomic) IBOutlet UITextField *inputInformation;
@property (weak, nonatomic) id  delegate;
@end
@protocol ViewController2Delegate -(void) viewController:(ViewController2 *) sceneBVC didInputed:(NSString *) string;
@end

委托者調用Delegate內的方法

解決了上面的問題後,這一步就比較簡單了,添加代碼即可:

-(BOOL)textFieldShouldReturn:(UITextField *) textField{
if (self.delegate) {
//將UITextField內容傳遞給Delegate內的方法
[self.delegate viewController:self didInputed:self.inputInformation.text];
//讓當前呈現的Scene B頁面消失
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
}
//讓鍵盤消失
[textField resignFirstResponder];
return YES;
}

僅僅添加代碼是遠遠不夠的,我們還要關聯,具體做法是在Storyboard中,選中ViewController2中的TextFiled控件,采用“Ctrl+drag”操作將其與ViewController2關聯。

Snip20151019_75.png

在Outlets中選中delegate。

Snip20151019_76.png

關於讓鍵盤消失這個問題,我會單獨寫篇文章說明,在這裡先占個坑。

關聯委托者與被委托者

明確這兩者的關系在Delegate的應用中顯得尤為重要,在ViewController.m中添加如下代碼:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:@"Segue_ID_AB"]) {
ViewController2 *sceneBVC = segue.destinationViewController;
sceneBVC.delegate = self;
}
}

在完成上面代碼之後可能會收到來自編譯器的報錯,不過不用擔心,等我們完成所有步驟,把代碼完善了以後就沒問題了。

這裡最重要的就是prepareForSegue方法的使用,該方法的完整描述是:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender

segue:用以描述一個跳轉的相關信息,比如是A controller 跳轉至B controller頁面,則我們可以通過它獲取到Acontroller的一個實例對象,和B controller的一個實例對象。注意調用這個函數的時候,跳轉行為還沒有發生,所以我們可以在這個方法內部,獲取到B controller的實例,然後傳遞一些參數過去。

sender:表示是誰觸發了這次跳轉。因為是從A--->B,所以這個sender可能是A controller裡面的任何一個對象。我們可以用它來區分同一個頁面上觸發的不同的跳轉行為。

比如:A頁面上有2個按鈕x和y,當點擊x按鈕時,就跳B頁面;當點擊y按鈕時,就跳C頁面。所以當點擊x按鈕時,觸發了一個跳轉,UIStoryboard的運行時就會去調用A controller裡面的這個函數,其中sender就是x按鈕。點擊y按鈕類似。這時候我們就可以判斷如果sender是x按鈕,則給B頁面傳遞數據;如果按鈕時y,則給C頁面傳遞數據。或者是其他業務邏輯。

相關資料:storyboard之prepareForSegue

被委托者遵循Delegate協議

在ViewController.h中引入ViewController2.h,並讓ViewController遵循委托者協議:

#import //引入
#import "ViewController2.h"
//讓ViewController遵循委托者協議
@interface ViewController : UIViewController @property (weak, nonatomic) IBOutlet UILabel *showInformation;
@end

被委托者重寫Delegate內的方法

在ViewController.m中,重寫Delegate內的方法:

-(void)viewController:(ViewController2 *)sceneBVC didInputed:(NSString *)string{
self.showInformation.text = string;
}

測試與總結

先上圖!

Snip20151019_77.png

Snip20151019_78.png

Snip20151019_79.png

這樣,我們就完整的解決了這個看似簡單實際暗藏玄機的題目了。

Delegate實現了不同場景之間的數據交互。它屬於事件驅動的范疇,只有當某一事件觸發時,Delegate才被調用。從這到例題中我們使用到的Delegate還只是很少的一部分,想要熟練的使用並且有深入的理解還需要更多的探索。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved