本文由CocoaChina翻譯小組@TurtleFromMars翻譯自raywenderlich,原文:Storyboards Tutorial in Swift: Part 2swift
更新記錄:該Storyboard教程由Caroline Begbie更新iOS 8和Swift相關內容。原文做者爲教程編纂組的成員Matthijs Hollemans。數組
2014/12/5更新:更新至 Xcode 6.2 Beta。app
若是你想學習Storyboard,你來對地方了!編輯器
在本系列Storyboard教程的第一部分,咱們已經學習瞭如何使用Interface Builder建立並鏈接不一樣的視圖控制器,還有如何直接在Storyboard編輯器中建立自定義表項。ide
本教程的第二部分,也是最終部分,內容包括segue(轉場),static table view cell(靜態表項),添加玩家頁面和遊戲選擇頁面!函數
咱們從上部分結束的地方開始,請先打開以前的項目,或者下載上半部分教程的示例代碼。工具
好,如今讓咱們一塊兒探索Storyboard的其餘酷炫特性吧!佈局
轉場(Segue)性能
讓咱們向Storyboard中繼續添加視圖控制器,建立一個讓用戶添加新玩家的頁面。學習
打開Main.storyboard,在包含表視圖的那個Players場景的導航欄右側拖入一個Bar Button Item(欄按鈕項),在屬性檢查器中將Identifier設爲Add,使其成爲標準添加(加號)按鈕。
當用戶點按這個按鈕時,你但願App會彈出一個模態頁面讓用戶輸入新玩家的詳細信息。
在Players場景的右邊拖入一個新的Navigation Controller(導航控制器)。記得雙擊面板能夠縮放畫面騰出空間。新加入的導航控制器附帶一個表視圖控制器,很方便。
這裏有個小技巧:選擇剛纔在Players頁面里加入的加號按鈕,按住control鍵把它拖向新建的導航控制器,鬆手,在彈出的小選單中選擇modal(模態)。
還記得嗎:當Storyboard面板處於縮小狀態時,沒法添加或修改內容。若是在建立轉場時遇到問題,請嘗試雙擊放大!
如今Players頁面和導航控制器之間多了一個新箭頭。
這 種鏈接的類型叫作segue(轉場,讀做seg-way,源自電影術語,原指兩個場景間的過渡銜接),表示一個頁面到另外一個頁面的過渡。此前咱們所見的 Storyboard鏈接描述的都是視圖控制器的包含關係,而轉場是用來切換頁面的。轉場能夠由點擊按鈕、表項、手勢等條件觸發。
使用轉場的好處是,不再用爲呈現新頁面寫代碼了,也不用把按鈕鏈接到IBAction方法上,你只須要在Storyboard中從一個欄按鈕項拖到下一個頁面就能夠建立過渡了。(注:若是你的控件已經綁定了IBAction鏈接,該鏈接會被轉場屏蔽。)
運行App,點擊加號按鈕,一個新的表視圖會從屏幕下方滑入。
這就是所謂的模態轉場。新頁面徹底覆蓋原頁面,在關閉模態頁面以前,用戶只能在新頁面進行交互。後面咱們還會看到push(入棧)轉場,這種轉場會把新頁面壓入導航控制器的導航棧(navigation stack)。
如今新頁面還沒什麼用,連關閉頁面返回都作不到,有去無回,由於轉場是單向操做。
爲返回頁面,Storyboard提供了unwind(回退)轉場。接下來咱們要實現返回功能,主要分三個步驟:
1. 建立讓用戶點選的控件,一般是個按鈕。
2. 在你想返回的控制器建立回退方法。
3. 在Storyboard中將控件與回退方法鏈接。
首 先打開Main.storyboard,選擇新的表視圖控制器場景(叫「Root View Controller」的那個)。雙擊導航欄,把標題改爲「Add Player」。而後在導航欄添加兩個欄按鈕項,在屬性檢查器中設置左側按鈕的Identifier爲Cancel,右側按鈕爲Done,並將右側按鈕的 Style改爲Done。
接 下來在項目中用Cocoa Touch Class模板添加一個新文件,命名爲PlayerDetailsViewController並令其繼承 `UITableViewController`。要把這個類關聯到Storyboard,先切回Main.storyboard,選擇添加玩家的場景, 而後在身份檢查器(Identity inspector)中設Class爲PlayerDetailsViewController。這個步驟我常常忘掉,在此特意提醒,還請讀者牢記。
如今終於能夠建立回退轉場了。在PlayersViewController.swift(不是detail那個)的類定義下面添加以下的回退方法:
@IBAction func cancelToPlayersViewController(segue:UIStoryboardSegue) {
dismissViewControllerAnimated(true, completion: nil)
}
@IBAction func savePlayerDetail(segue:UIStoryboardSegue) {
dismissViewControllerAnimated(true, completion: nil)
}
這兩個方法在調用時都會解除這個控制器。後面你會改寫`savePlayerDetail`,讓它名副其實地履行本身的職責。
最後回到Interface Builder,把Cancel按鈕和Done按鈕鏈接到相應的action方法上。按住control從欄按鈕拖到視圖控制器上面的出口(exit)對象上,而後從彈出的選單中選擇正確的action名稱。
記住取消方法的方法名,建立回退轉場時,App中的全部回退方法(形如`@IBAction func methodname(segue:UIStoryboardSegue)`)都會在列表中顯示,因此命名方法時要多加註意,避免混淆。
運行App,點擊加號按鈕,而後測試Cancel和Done按鈕。僅僅幾行代碼就能夠實現如此功能。
靜態表項(Static Cell)
完成這部分後,添加玩家頁面會像這樣:
當 然這是一個分組表視圖(grouped table view),但沒必要爲該表建立數據源,也沒必要爲此編寫`cellForRowAtIndexPath`方法,你能夠直接在Interface Builder中完成設計。這個特性叫作靜態表項(static cell)。
選中Add Player場景的表視圖,在屬性檢查器中設Content爲Static Cells,把Style由Plain改爲Grouped,併爲表視圖設置兩個分段(section)。
修改Sections屬性值時,編輯器會複製已有的分段。(你也能夠在左側的文檔大綱中選擇特定分段並複製。)
最終頁面每一個分段應該只有一行,請在面板或文檔大綱中選中並刪除多餘的表項。
在文檔大綱中選擇最上面的表視圖分段,在屬性選擇器中設Header字段值爲Player Name。
向該分段內拖入一個新的Text Field(文本字段),橫向拉長並移除邊框,使文本字段控件融入周圍環境。設字體爲 _System 17.0_ ,勾掉Adjust to Fit選項。
接 下來咱們要用Xcode的Assistant Editor(輔助編輯器)功能爲該文本字段在`PlayerDetailsViewController`中建立一個outlet。在 Storyboard中,點擊工具欄上的按鈕(圖標是兩個套在一塊兒的圓圈)打開輔助編輯器,應該會自動打開 PlayerDetailsViewController.swift(若是沒有,在右側的跳轉欄中選擇相應文件)。
選擇新建的文本字段, 按住control拖到swift文件的類定義下面。在彈出框中將新outlet命名爲nameTextField並點擊Connect。在點擊 Connect後Xcode會在PlayersDetailViewController類中添加屬性並在Storyboard中創建鏈接:
爲表項上的視圖建立outlet對於原型表項來講可能會遇到問題,這在上一部分的教程中提到過,不過靜態表項就沒必要擔憂了,由於每一個靜態表項都只會有惟一的實例,把子視圖與視圖控制器的outlet鏈接徹底沒問題。
把第二分段的靜態表項的Style設爲Right Detail,這會套用一個標準表項樣式,雙擊左側的label,把文本改成Game,而後爲該表項設定Disclosure Indicator(展開方向標)附件。
仿 照剛纔的Name文本字段,爲右面的label("Detail"的那個)建立outlet並命名爲detailLabel,該表項上的label都是常 規`UILabel`對象。在創建鏈接前選擇Detail文本字段時可能須要屢次點擊,請確保選擇的是label而不是整個表項。完成後如圖:
添加玩家頁面的最終設計效果如圖:
目前在Storyboard中設計的頁面尺寸都符合iPhone 5的4英寸屏幕,高度爲568點。固然你的App應當在不一樣的屏幕尺寸下正常工做,你能夠在Storyboard中預覽全部的尺寸。
在工具欄上點開輔助編輯器,選擇跳轉欄中的Preview。點擊輔助編輯器左下角的加號添加新的預覽尺寸,若是想刪除一個屏幕尺寸,選中並按delete鍵便可。
一個簡單的評分App不須要什麼花哨的東西,只是使用表視圖控制器,頁面自動縮放以填滿屏幕空間。當你想爲不一樣的屏幕尺寸適配佈局時,你須要使用Auto Layout和Size Classes。
構建並運行App,你會注意到添加玩家頁面依然是空白!
表視圖控制器在使用靜態表項時不須要數據源,而以前你用Xcode模板建立的`PlayerDetailsViewController`類中依然有部分數據源相關代碼,靜態表項所以沒法正常工做,因此靜態內容沒有顯示出來。咱們這就來解決問題!
打開PlayerDetailsViewController.swift文件,刪除這一條代碼往下的全部內容(注意不要刪掉類本身的括號):
// MARK: - Table view data source
如今,自從加入這個類之後Xcode顯示的那幾條警告(warning)也應該消失了。
運行App,檢查使用靜態表項的新頁面。徹底沒有寫代碼,其實剛纔還刪了一段代碼!
還 要了解一點:靜態表項只在`UITableViewController`中有效,雖然Interface Builder容許你在常規`UIViewController`中的表視圖對象裏添加靜態表項,運行時不會發揮做用,緣由是 `UITableViewController`中額外實現了一些用來處理靜態表項數據源的操做。在項目中誤用的話Xcode甚至會拒絕編譯,輸出報錯信 息:「Illegal Configuration: Static table views are only valid when embedded in UITableViewController instances」。
另外一方面,原型表項在常規視圖內的表視圖中能夠正常工做,但在nib中就沒戲了。目前來說,使用原型表項或靜態表項就必須使用Storyboard。
你也有可能想在一個表視圖中混合使用靜態表項和常規的動態表項,很遺憾的是目前的SDK對此支持欠佳。若是你的App有這種需求,請參考蘋果開發者官方論壇上的相關帖子尋求可行方案。
注:若是構建的頁面上包含的靜態表項多到沒法在可視範圍內所有展現,你能夠在Interface Builder中直接利用滾動手勢查看,這個功能可能不容易發現,但確實管用。
不過總的來講該寫代碼的地方只能靠代碼,甚至靜態表項的表視圖也是如此。前面在把文本字段拖進第一個表項的時候,你可能發現尺寸不大合適,文本字段周圍有一點白邊,並且用戶看不到文本字段的實際範圍,若是正好點在邊框上,沒有彈出鍵盤,用戶會感到困惑。
爲避免這種狀況,你應該讓那一行任意位置接受的點擊均可以喚出鍵盤。要這樣作很容易,打開PlayerDetailsViewController.swift並以下添加
tableView(_:didSelectRowAtIndexPath:)`方法:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if indexPath.section == 0 {
nameTextField.becomeFirstResponder()
}
}
代碼的意思是若是用戶點按第一個表項,App應該激活相應文本字段。該分段只有一個表項,你只需使用分段的索引。設文本字段爲第一響應者會自動喚出鍵盤。這只是一小處用戶體驗優化,但就是這樣一個小細節能夠給用戶省去一點煩惱。
小訣竅:添加delegate委託方法或重寫視圖控制器方法時,直接輸入方法名開頭的幾個字母(前面不加func),便可在自動補全列表中選擇正確的方法。
另外,還應該在Storyboard的屬性檢查器中把相應表項的Selection Style設爲None(本來是Default),不然用戶點按文本字段周圍的邊框時該行會高亮。
好啦,添加玩家頁面設計完成。如今咱們要實現功能。
爲添加玩家頁面實現功能
如今先無論Game這行,只輸入玩家名稱。
當用戶點擊Cancel按鈕時,頁面關閉,用戶剛剛輸入的數據隨之做廢。這部分功能直接用回退轉場已經實現好了。
而當用戶點擊Done時,你應該建立一個新的Player對象,參照用戶輸入填充屬性後更新玩家列表。
轉場即將發生時,`prepareForSegue(:sender:)`會被調用。你能夠重寫這個方法,在退出視圖以前將數據保存到一個新的Player對象中。
注:不要擅自調用`prepareForSegue`方法,這是UIKit通知你一個轉場剛剛被觸發的消息。
在PlayerDetailsViewController.swift中,先在類上添加一條屬性:
var player:Player!
這條語句並不會將屬性實例化,但其中的感嘆號把該變量定義爲隱式解包可選量(implicitly unwrapped optional),意思是該變量必須被實例化,並且你肯定它在被使用前必定有值。
接下來在PlayerDetailsViewController.swift中添加如下方法:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SavePlayerDetail" {
player = Player(name: self.nameTextField.text, game: "Chess", rating: 1)
}
}
prepareForSegue(_:sender:)`方法判斷轉場的標識符是否爲`SavePlayerDetail`,當且僅 當斷定結果爲真時,建立一個新的Player實例,其中game和rating均取默認值。若是此時運行,App會崩潰,由於不存在標識符 `SavePlayerDetail`,player不會被實例化,結合前面的隱式解包可選量定義,引起運行時錯誤。
小提示:若是App出現詭異的崩潰問題,並且代碼看起來彷佛並沒有邏輯錯誤,那麼多是在代碼中刪除過對象或修改過對象名,以至Storyboard引用對象出錯。
在Main.storyboard中,在文檔大綱裏找到Add Player場景,選擇鏈接到`savePlayerDetail`這個action的回退轉場,將其標識符改成`SavePlayerDetail`:
而後選擇鏈接到`cancelToPlayersViewController`的回退轉場,將其標識符改成`CancelPlayerDetail`。以供`prepareForSegue(_:sender:)`方法判斷標識符。
轉到PlayersViewController類,以下修改回退轉場方法`savePlayerDetail(segue:)`:
@IBAction func savePlayerDetail(segue:UIStoryboardSegue) {
let playerDetailsViewController = segue.sourceViewController as PlayerDetailsViewController
//add the new player to the players array
players.append(playerDetailsViewController.player)
//update the tableView
let indexPath = NSIndexPath(forRow: players.count-1, inSection: 0)
tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
//hide the detail view controller
dismissViewControllerAnimated(true, completion: nil)
}
這會經過傳入方法的轉場引用獲取一個指向`PlayerDetailsViewController`的引用,並藉此向數據源中使用的Player數組添加新的Player對象,而後通知表視圖在末尾新增了一行,由於表視圖和數據源應當保持同步。
你可能會直接調用`tableView.reloadData()`,但仍是爲新行插入的操做加入動畫效果比較好。`UITableViewRowAnimation.Automatic`會以插入新行的位置自動選用合適的動畫,十分方便。
試試看,如今應該能夠向列表中加入新玩家了!
性能
現 在Storyboard已經有好幾個視圖控制器了,你或許會擔憂性能問題,不過一次載入整個Storyboard並非什麼苦活,Storyboard不 會當即實例化全部的視圖控制器,當即載入的只有初始視圖控制器。而因爲這裏的初始視圖控制器是一個分頁欄控制器,包含的兩個視圖控制器也會被載入(第一個 分頁標籤的Players場景和第二個分頁標籤的場景)。
其餘視圖控制器只有在轉場過去的時候纔會被實例化。而當關閉視圖控制器的時候,它們會當即被釋放,因此內存中只有活躍使用的視圖控制器,就好像分別使用nib同樣。
實踐是檢驗真理的惟一標準,在PlayerDetailsViewController類中添加構造器(initializer)和析構器(deinitializer):
required init(coder aDecoder: NSCoder) {
println("init PlayerDetailsViewController")
super.init(coder: aDecoder)
}
deinit {
println("deinit PlayerDetailsViewController")
}
你剛剛重寫了`init(coder:)`和`deinit`方法,讓它們向Xcode調試面板輸出信息。如今運行App,打開添加玩家頁面,你會發現視圖控制器只有在被打開的時候纔會分配。
關閉添加玩家頁面的時候,不管是點擊Cancel仍是Done都會看到deinit析構器的`println()`輸出。若是再次打開這個頁面,你還會看到`init(coder:)`的輸出,這樣你應該相信這個事實了:視圖控制器是按需加載的,就像手動載入nib同樣。
注: 若是你之前用過nib,那麼你應該會很熟悉構造器`init(coder:)`,這部分機制延續到了Storyboard中:使用的方法依然是 `init(coder:)`,`awakeFromNib()`和`viewDidLoad()`。Storyboard能夠當作附帶了過渡信息和關聯 信息的一系列nib的集合,而Storyboard內的視圖和視圖控制器使用與nib相同的方式編碼並解析。
遊戲選擇頁面
在添加玩家頁面中點選Game行應該打開一個新頁面並讓用戶從列表中選擇一個遊戲,這意味着下一步要加入另一個表視圖控制器,不過此次的頁面不是模態顯示,而是壓入導航棧。
向 Storyboard中拖入一個新的表視圖控制器,在添加玩家頁面中選擇Game表項(確保選中的是整個表項,而不是其中的label),而後按住 control拖到新建的表視圖控制器,在二者之間建立轉場。在彈出的選單中選擇轉場類型爲Push,而後在屬性檢查器中把轉場的Identifier標 識符設爲PickGame。
雙擊導航欄,將新場景命名爲Choose Game。設原型表項的Style爲Basic(基本),設重用標識符爲GameCell,如圖:
在 項目中使用Cocoa Touch Class模板新建一個Swift文件,命名爲GamePickerViewController,繼承UITableViewController。回 到Storyboard中將遊戲選擇頁面的Custom Class設爲`GamePickerViewController`。
如今爲新頁面添加數據。在GamePickerViewController.swift中,在開頭添加games屬性,而後重寫viewDidLoad函數,像這樣:
var games:[String]!
override func viewDidLoad() {
super.viewDidLoad()
games = ["Angry Birds",
"Chess",
"Russian Roulette",
"Spin the Bottle",
"Texas Hold'em Poker",
"Tic-Tac-Toe"]
}
你剛剛新增了一個叫作`games`的字符串數組,並在`viewDidLoad()`中用寫定的內容填充數組。
而後以下替換數據源方法:
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return games.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("GameCell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = games[indexPath.row]
return cell
}
上述代碼將`games`數組設爲數據源並替換表項的textLabel中的字符串值。
只要數據源準備就緒就應該能正常工做。運行App,點選Game行,新的遊戲選擇頁面會滑入屏幕。如今點擊各項不會有什麼效果,但因爲該頁面呈如今導航棧上,你能夠直接點擊返回按鈕,返回原來的添加玩家頁面。
不用寫代碼就能夠喚出新頁面,是否是很贊?只要按住control從靜態表項拖到新場景,寫的代碼只有填充表視圖的內容,並且通常來說比原地設計好的列表要靈活些(由於games數組更方便修改)。
固然新頁面要返回數據纔有用,爲此你要添加一個新的回退轉場。
在GamePickerViewController類的上面添加持有選中的遊戲的名稱和索引的屬性:
var selectedGame:String? = nil
var selectedGameIndex:Int? = nil
而後修改`cellForRowAtIndexPath:`:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("GameCell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = games[indexPath.row]
if indexPath.row == selectedGameIndex {
cell.accessoryType = .Checkmark
} else {
cell.accessoryType = .None
}
return cell
}
這會在當前所選遊戲對應的表項附上選中標記(對號),這對用戶體驗來講不可或缺。
接着添加`tableview(tableview:didSelectRowAtIndexPath:)`方法:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
//Other row is selected - need to deselect it
if let index = selectedGameIndex {
let cell = tableView.cellForRowAtIndexPath(NSIndexPath(forRow: index, inSection: 0))
cell?.accessoryType = .None
}
selectedGameIndex = indexPath.row
selectedGame = games[indexPath.row]
//update the checkmark for the current row
let cell = tableView.cellForRowAtIndexPath(indexPath)
cell?.accessoryType = .Checkmark
}
這段代碼首先會取消選擇剛剛點選的行,外觀會從灰色高亮變回常規的白色,而後移除對號,並在剛剛點選的行上附加選中標記。
運行App,測試是否正常。點選一個遊戲名,相應行會附上選中標記,點選另外一個遊戲名,選中標記也隨之移動。
按要求來講點選某行以後應該關閉該頁面,不過如今並無自動返回,由於還沒有綁定回退轉場。
在PlayerDetailsViewController.swift的類上面添加一個持有被選遊戲的屬性,以便以後在Player對象中保存。令其默認值爲"Chess",這樣一來新玩家總會有一個選定的遊戲。
var game:String = "Chess"
一樣在該文件中改寫`viewDidLoad()`以在靜態表項中游戲名稱:
override func viewDidLoad() {
super.viewDidLoad()
detailLabel.text = game
}
添加回退轉場方法:
@IBAction func selectedGame(segue:UIStoryboardSegue) {
let gamePickerViewController = segue.sourceViewController as GamePickerViewController
if let selectedGame = gamePickerViewController.selectedGame {
detailLabel.text = selectedGame
game = selectedGame
}
self.navigationController?.popViewControllerAnimated(true)
}
上述代碼會在用戶從選擇遊戲場景選中一個遊戲後執行。該方法按照選中的遊戲更新頁面上的label和game屬性,而後將GamePickerViewController彈出導航棧。
在Main.storyboard中按住control從表項拖到Exit出口對象,而後從彈出列表中選擇`selectedGame:`。
設該回退轉場標識符爲SaveSelectedGame。
運行App試試看,建立新玩家,點選Game行並選擇一個遊戲。
不 幸的是,這個回退轉場方法是在`tableView(_:didSelectRowAtIndexPath:)`方法前執行的,因此 `selectedGameIndex`並未及時更新。幸運的是你能夠重寫`prepareForSegue(_:sender:)`方法,在轉場以前完 成更新操做。
在GamePickerViewController中添加`prepareForSegue(segue:)`方法:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SaveSelectedGame" {
let cell = sender as UITableViewCell
let indexPath = tableView.indexPathForCell(cell)
selectedGameIndex = indexPath?.row
if let index = selectedGameIndex {
selectedGame = games[index]
}
}
}
`prepareForSegue(_:sender:)`的sender參數是引起轉場的對象,在這裏對應選中的遊戲表項,因此你能夠利用表項的indexPath來在games數組中肯定選中的遊戲並在轉場發生以前更新`selectedGame`。
如今運行App,選擇遊戲後玩家的遊戲信息會隨之更新了。
接下來改寫PlayerDetailsViewController的prepareForSegue方法來返回選中的遊戲,而不是寫定的"Chess"。這樣一來,完成添加玩家的操做後,Players場景中會顯示玩家實際選擇的遊戲。
在PlayerDetailsViewController.swift中以下改寫`prepareForSegue(_:sender:)`方法:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SavePlayerDetail" {
player = Player(name: nameTextField.text, game:game, rating: 1)
}
}
完成添加玩家頁面並點擊Done後,玩家列表會更新正確的遊戲信息。
還有一點,當你選擇一個遊戲,返回添加玩家頁面,而後嘗試從新選擇遊戲的時候,以前選定的遊戲應該顯示選中標記。解決方法是在轉場時把PlayerDetailsViewController中保存的選中的遊戲傳給GamePickerViewController。
仍是在PlayerDetailsViewController.swift中,於`prepareForSegue(segue:,sender:)`方法的末尾添加如下代碼:
if segue.identifier == "PickGame" {
let gamePickerViewController = segue.destinationViewController as GamePickerViewController
gamePickerViewController.selectedGame = game
}
注意:如今有兩條檢查`segue.identifier`的 `if`語句。SavePlayerDetail是返回玩家列表的回退轉場,PickGame是前往遊戲選擇頁面的入棧轉場。添加的代碼會在 GamePickerViewController的視圖加載以前更新其中的`selectedGame`。
打開GamePickerViewController.swift並在`viewDidLoad()`末尾添加如下代碼:
if let game = selectedGame {
selectedGameIndex = find(games, game)!
}
這兩行代碼獲取從 PlayerDetailsViewController傳進的selectedGame並將其轉換成正確的索引。`find()`函數會在games數 組中查找匹配selectedGame的String,而後返回匹配元素的索引,賦值給selectedGameIndex,這個索引用來在對應表項上設 置選中標記。
好。如今選擇遊戲頁面功能實現完成!
何去何從?
這是整個教程的示例項目,包含上述全部源代碼。
可喜可賀,如今你已經瞭解Storyboard編輯器的基本用法,可以建立包含多個視圖控制器並能經過轉場在場景之間切換的App!在一處集中管理多個視圖控制器和互相的關聯,讓總體把握App的樣子更加容易。
你也看到了自定義表視圖和表項有多麼容易。有了靜態表項,不用實現全部的數據源方法也能夠構建一些界面。
若是想深刻了解Storyboard,請參閱咱們的書籍iOS 8教程,其中涵蓋了最新的通用Storyboard(Universal Storyboard)。