標籤:ios8 swift segue prepareforsegue performseguewithiden
上一話我們對Demo的選擇介面做了自動布局的相關處理,現在開始串連多個MVC的操作。首先我們需要其他工程中的檔案,那麼讓我們開啟另一個app。點擊下面這個檔案
然後拖動我們需要的檔案到新的工程目錄下:
注意勾選第一行,不然只是做了引用,如果你不小心刪除了目標目錄的話,你就找不到這些檔案了,所以還是推薦做複製,這樣會把檔案複製到我們自己的工程目錄下。
那麼storyboard中的內容怎麼辦呢,我們只需要在原工程的storyboard中選中控制器然後複製,粘貼到新工程的storyboard中即可。
我注意到一個問題,當我複製粘貼過來的時候控制器中的臉沒有了。看起來需要一些觸發的小動作。我們來到FaceView中做一些小修改然後回退再儲存就好了。
看,現在出來了。現在把這兩個MVC添加到分欄控制器中,別忘了把左側的小箭頭移到分欄控制器中,具體做法我們之前已經介紹過了,這裡就不囉嗦了,直接看結果:
我們在ip6 plus上運行一下,如果是豎屏你會看到:
跟其他尺寸的iphone一樣,即便你左右滑動也不會出現笑臉,但是如果你橫屏的話會看到:
這和ipad上的效果是相同的,我們之前講過ip6 plus比較特殊,雖然螢幕小但是清晰度很高,在橫屏模式下和ipad是一樣的,關於自動布局的東西以後會細講。
在我們繼續下面的工作前需要修改storyboard以適應iphone,之前講過我們在master上Embed in一個導航控制器,現在在iphone6上運行你會看到初始介面變成:
點擊返回就可以回到選擇介面,如果你在導覽列上加了一個標題,storyboard中會出現警告,原因是我們新加的導覽列會擋住之前的label,依舊update frame就好了。現在我們把master和detail關聯起來。我們使用segue,之前講過了拖拽按鈕到小人臉的控制器上然後選擇show detail,三個按鈕都做重複的動作,三個segue分別命名為sad 、happy、meh(即不開心也不難過)。
現在你在iphone上運行可以看到點擊按鈕頁面發生跳轉了,說明segue生效了,但是小人臉的表情並沒有發生變化,因為我們還沒有準備segue,回憶一下之前講的。
回到PsychologistViewController的代碼中,我們在這個代碼中所需要做的就是為segue做準備。
import UIKitclass PsychologistViewController: UIViewController { override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { if let hvc = segue.destinationViewController as? HappinessViewController,let identifier = segue.identifier{ switch identifier{ case "sad":hvc.happiness = 0 case "happy":hvc.happiness = 100 default:hvc.happiness = 50 } } }}
請注意我這裡if let(可選綁定)的寫法,這是Swift 1.2版本的新寫法,避免了有很多if let{}嵌套的情況。看起來一切都很美好?那麼運行一下點擊一個按鈕,你會發現程式崩潰了。中控台提示在解包一個可選型的時候發現了空值。錯誤定位到了updateUI這裡:
你會看到faceView是空值。回顧一下之前的代碼,我們剛才修改了happiness的值,來看看happiness的屬性觀察器:
var happiness:Int = 75 {//0代表傷心,100代表開心 didSet{ happiness = max(min(happiness, 100), 0) println("happiness = \(happiness)") updateUI() } }
你會發現這裡調用了updateUI方法,而這個方法中的faceView是用IBOutlet定義的!
這就是我們之前講過的,outlet在segue的時候還沒有初始化。
那麼如何解決這個問題呢?幸運的是當我們想要修改模型的值時會更新頁面的內容,如果這個時候頁面的outlet沒有值的話,只要忽略就好了。很簡單的做法,我們把可能為空白的值放入可選鏈中:
func updateUI(){ faceView?.setNeedsDisplay() }
意思是如果faceView為空白,那麼後面的都不會被執行。只需要這麼一個簡單的問號,再次運行你會發現得到了我們想要的效果。現在我們給detail部分也增加一個導航控制器,並且標題根據點擊按鈕的值得不同來設定。依舊Embed In一個。
然後在updateUI這個方法中增加一行:
func updateUI(){ faceView?.setNeedsDisplay() title = "\(happiness)" }
我們之前講的控制器中有屬性傳達給它的導航控制器,然後控制器負責繪製,運行看看,你會發現標題是不會出現的:
這也是我們之前講的,當你增加了一個導航控制器後,所有的segue都指向了導航控制器,而不再是detail本身了:
那麼如何修改呢?
import UIKitclass PsychologistViewController: UIViewController { override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { var destination = segue.destinationViewController as? UIViewController if let navCon = destination as? UINavigationController{ destination = navCon.visibleViewController } if let hvc = destination as? HappinessViewController,let identifier = segue.identifier{ switch identifier{ case "sad":hvc.happiness = 0 case "happy":hvc.happiness = 100 default:hvc.happiness = 50 } } }}
這裡我們做了一個判斷,當我們不確定某個控制器是否在導航控制器中的時候,我們可以應用這種寫法。如果有導航控制器那麼取出控制器中的最上面的控制器也就是Demo中的HappinessViewController,把它賦給destination,如果沒有就把segue中儲存的目標控制器賦給destination。現在可以運行了:
之前的segue都是我們通過storyboard中實現的,現在讓我們來試試如何通過代碼來實現,我們新加一個按鈕取名Noting!然後通過頁面間的拖動來產生segue。我們選中master控制器上方的黃色按鈕
拖拽到detail的導航控制器中鬆手選擇show detail。取名為nothing,然後我們開啟聯合視圖拖動nothing按鈕到控制器代碼中產生一個action,action代碼如下:
@IBAction func nothing(sender: UIButton) { performSegueWithIdentifier("nothing", sender: nil) }
可以看到我們讓sender為nil代表點擊這個按鈕什麼都沒做,但是它依舊會執行到prepareForSegue方法,此時我們在prepareForSegue方法中增加一個case:
case "nothing":hvc.happiness = 25
運行你會發現nothing按鈕依舊起作用了。
那麼我們為什麼要在代碼中使用segue呢,你可能在按鈕被點擊之後需要根據一些狀態來判斷使用哪個segue,這是在代碼中使用segue的經典理由。
【我們都愛Paul Hegarty】斯坦福IOS8公開課個人筆記23 多MVC模式Demo的實現