一天一點xib:6該聊聊SB了

引言

下面我們來學習比xib更強大的SB

如何理解SB?

最簡單的理解就是:一個.storyboard文件相當于多個基于VC使用的.xib文件,由此我們可以看出,SB(只能基于VC,不能基于View),我們有多個VC的類是可以和一個SB文件建立關系的,使用方法:

SecVC *secVC = [[UIStoryboard storyboardWithName:@"Demo" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:@"SecVC"];

之前的一天一點xib:2初識xib有過介紹, 通過這個方法,我們傳入不同VC的identifier,就會得到不同的VC對象。

為什么是強大了?

xib可以基于View、VC甚至自己獨立的使用,而SB只能基于VC使用,為什么說比xib更加強大呢?主要是下面的兩個原因:

1.SB支持segue

2.SB對cell的支持更加強大

什么是segue?

想象我們點擊一個VC中的button后跳轉到另一個VC的場景,通常用的都是navigationController的push,或者present一個模態視圖,即使有xib的情況下,要完成跳轉其實也不簡單,要把按鈕拖到@implementation中實現一個IBAction的方法,然后在里面寫上:

[self.navigationController pushViewController:Sec animated:YES]

或者

[self presentViewController:Sec animated:YES completion:nil]

要想簡化這個沒有技術含量的過程,就要用到SB的segue。


我們在一個VC中選擇要發生跳轉的按鈕,按control拖動到另一個VC上就會出現一個菜單,在菜單上你就可以選擇跳轉的方式push、present,這樣不用寫一行代碼就能完成頁面間的跳轉,而兩個VC之間的像紐扣一樣用線連著兩個VC的的東西就是segue,是一個UIStoryboardSegue對象,我們可以簡單的理解成是完成頁面跳轉相關功能的一個類,是不是很簡單?

segue雖然簡單,如何傳參?

我們知道用SB的segue來實現也頁面跳轉十分方便,但是如果要向跳轉的頁面傳參該怎么辦?

假設我們要點擊ViewController這個VC里的一個按鈕,跳轉到SecVC這個VC中,把testTitle這個參數傳過去。第一步還是要選中按鈕,拖到SecVC里,然后選中這個segue,給它一個id值,確保用代碼可以找到它,然后在ViewController中編碼:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"sec"]) {
        SecVC *secVC = (SecVC *)segue.destinationViewController;
        secVC.testTite = @"hello world";
    }
}

設置SB中segue的identifier,主要就是要在這里使用,因為多個button發生的多個頁面跳轉都是回調這個函數,所以要用identifier來區分是哪個segue,跳哪個頁面,傳哪些參數。
id的sender就是觸發跳轉的那個button或其他控件。

不確定的跳轉如何使用segue?

一下場景經常出現:甲VC中有個button,點擊后有可能跳轉到乙頁面,也可能跳轉的丙頁面,怎么解?

我們假設我們要點擊ViewController這個VC里的一個按鈕,有可能要跳到SecVC,有可能要跳thirdVC。
1.在SB中準備segue。

注意我們這次創建的segue的方式并不是選中button按control拖到另一個VC中,而是選中VC,右鍵選中triggered segues里manual后面的+拖動到另一個VC里,這個很重要,而且還是要給segue一個id。

2.編碼實現跳轉:

- (IBAction)testSegue:(id)sender
{
    BOOL flag = NO;
    if (flag) {
        [self performSegueWithIdentifier:@"sec" sender:sender];
    } else {
        [self performSegueWithIdentifier:@"third" sender:sender];
    }
}

代碼實現segue跳轉也很簡單:

- (void)performSegueWithIdentifier:(NSString *)identifier sender:(nullable id)sender

第一個參數是segue的id,第二個參數是觸發這個跳轉的控件。
在segue跳轉頁面的過程中還會調一個函數,我們可以重寫這個函數,來決定是否讓這個跳轉發生。eg:

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    if (_islogin) {
        return YES;
    } else {
        NSLog(@"您還沒有登錄,請先登錄"); //用log舉個例子
        return NO;
    }
}

更靈活的segue

如果你熟練掌握了segue他其實可以做很多事情,其實segue并不僅僅能完成跳轉,還有一類segue叫做relationship segue,之前是幫助大家理解,所以說的比較簡單,其實我們選中一個NavigationController按control鍵拖動到另一個VC上的話也可以生成segue,我們選中root view controller,就將Nav的rootViewController屬性設置成了這個VC,這個segue就是relationship segue,同樣,拖動一個tabbarController也會出現viewControllers的relationship segue。

更好的使用Cell

用xib的時候,要想用cell,通常是建立一個cell子類,一個與之對應的.xib文件。用SB的時候要想用cell就簡單的多了,因為cell是可以直接拖動到tableView里的,直接在tableView里管理cell設置屬性,當然如果是復雜的cell還是要子類話對應的.h、.m的。

SB在使用cell分兩種情況:1靜態cell,2動態cell。

靜態cell

設置靜態cell:

注意靜態cell一定要基于UITableViewController,否則會報錯。
展示靜態cell的tableView是不用調用自己必須實現的datasource協議的

你會很驚訝,為什么必須調用的datasource協議都不用實現?答案是靜態,靜態的cell,意義就在于你在xib中設置成什么樣,他就展現什么樣,不會再調用datasource向你要cell了,因為在SB文件中已經確定下來了。

在做一些“死”頁面的時候SB的靜態cell是很好的選擇,靜態cell也不是什么都不能做,靜態cell里的button還是可以拖到@implementation中形成IBAction的,但是是無法生成IBOutlet屬性或字段的。

即使你強行的給一個靜態的cell指定了一個cell的類,也是無法向其內部拖入IBOutlet的。這就是靜態cell的局限性,但是如果你要設置的數據不多還是可以考慮用靜態cell,因為你可以通過給cell上的控件設tag來找到它從而賦值。

動態cell的使用

在上圖中設置content屬性為Dynamic Prototypes就可以了。使用動態cell的話就要在VC中實現那兩個必須實現的datasource協議了,下面舉個簡單的例子:
1.給cell指定一個class

2.給cell設置id,重用機制使用,其他屬性就不詳細說明了,和其他控件的屬性差不多。

3.給cell添加一些控件,并拖到TestCell源文件中生成IBOutlet的屬性,在VC中實現那兩個必須實現的協議方法:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 20;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestCell *testCell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:@"testCell"];
    testCell.testLabel.text = @"hello world";
    return testCell;
}

這里注意,不需要在tableView:cellForRowAtIndexPath:中創建cell了,這是與xib使用cell最大的區別,下面是xib使用cell的方法舉例:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TestCell *testCell = (TestCell *)[tableView dequeueReusableCellWithIdentifier:@"testCell"];
    if (!testCell) {
        testCell = [[NSBundle mainBundle] loadNibNamed:@"TestCell" owner:self options:nil];
    }
    testCell.testLabel.text = @"hello world";
    return testCell;
}

這是很重要的,千萬記住,因為我們是直接拖cell到SB文件的tableView里的,所以直接從重用池里取就好了。

這里稍微提一個地方:我們這里取重用cell用的是函數:
dequeueReusableCellWithIdentifier:,而系統中還有另一個重用的函數:dequeueReusableCellWithIdentifier:forIndexPath:這個函數比我們代碼中用的那個好,是我們用的那個api的優化版,它是iOS6引入的api,完全符合我們一般app對版本兼容的要求,這里感謝簡書用戶coderzcj在評論中給我留言,謝謝你。我后續會再寫一篇文章專門說說系統對xib優化的事情的,非常感謝大家的支持。

總結

SB的segue和cell使用是它最大意義的地方,當然之前xib能做的設置,SB也都能做,而且多個.xib對應一個SB文件,使文件量變少了不少,但是如果想單獨用View的地方還是要用xib。

歡迎大家和我交流溝通,若文章中有錯誤和紕漏,懇請指正,謝謝。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 引言 這兩天突然想起之前看到過有的項目中用到了object, 好奇心起,就順便回溯下xib的使用吧 xib優缺點分...
    舞動夢想閱讀 1,970評論 0 3
  • 引言 學到這里,xib給我帶來的幫助已經很大了,最大的莫過于UI控件的創建、屬性的賦值再也不用寫代碼,就UI開發來...
    二亮子閱讀 7,267評論 41 82
  • 1.自定義控件 a.繼承某個控件 b.重寫initWithFrame方法可以設置一些它的屬性 c.在layouts...
    圍繞的城閱讀 3,444評論 2 4
  • 一 來看一下IB開發的優點以及缺點 1.1 優點 1.1.1 開發和維護效率高IB開發與純代碼開發相比, 效率至...
    奧卡姆剃須刀閱讀 1,522評論 5 10
  • ●理解widow對象--BOM的核心●控制窗口、框架和彈出窗口●利用location對象中的頁面信息(locati...
    royluck閱讀 230評論 0 0