關於Swift頁面傳值的那些事

最近遇到很多需要在頁面間傳值的情況,而每種狀況也有不同的限制,因此根據不同情況,我需要找到新的方式來解決問題。

在開發過程中,我們總是會需要將data在不同頁面做傳遞,例如:將user點選table的資料傳遞到下一頁顯示;或是修改完成後回到上一頁時要顯示出來…。實作的方法有很多,這次針對單純本機端,且不利用存檔功能(Core data、User default等等)做分享。

一般來說,iOS App目前iPhone的segue方式是使用show和present modally。差別在於:若有拉navigation controller,使用show時,在第二頁的navigation bar上會有「back」按鍵,直接可以pop回上一頁。
而present modally則不會,因此能覆蓋著整個頁面。

上方為show ; 下方為present

那麼首先,若要傳資料到下一個頁面,常見的方法為:

利用prepare,在segue之前會先把data指派給對應的ViewController內的變數

如果要繼續往下一個頁面傳遞資料,使用同樣的方法即可。

那當我們要將資料往回傳遞時該怎麼做呢?
分享幾個自己的心得:

  1. 全域變數:使用簡單,任何地方都能使用,缺點是生命期極長。
  2. Singleton:
singleton

續2. 我自己的理解是利用class物件作為載體,且只會初始化一個實體,所以不必擔心重複建立。如此一來,只要使用MyDataToPass.shared.data即可直接取用。

3. unwindSegue:其實也是剛才提到的Segue方式,但可以返回之前的頁面。也就是利用prepare(for segue: UIStoryBoardSegue, sender: Any?),在segue前先指派資料給目的地的變數。詳細實作方法的教學不少,在此就不贅述。

4. 於第二頁指定一個變數,其參照到第一頁物件實體(像delegate):
在第二頁建立一個變數,型別為上一個ViewController的型別,並在第一頁prepare(for segue: UIStoryBoardSegue, sender: Any?)時,指定該變數為本頁。那麼在第二頁時,就可以對第一頁進行操作。

(母頁面Code) segue之前,指派好目的地的變數為自己
(子頁面Code)dismiss之前,把資料指派回母頁面

但是此寫法在架構上不優,因為子頁面可能會被多個母頁面利用(例如:我要在多個商品頁面下單,那麼每個商品頁面都可能會segue到「選擇數量、規格」的頁面),那麼子頁面就不應該寫特定類別的屬性與方法。因此更好的寫法是以下:

5. 利用protocol(interface)作為媒介,讓需要使用到子頁面的母頁面都遵從此protocol,因此不論什麼樣的頁面(ViewController、TableViewController等等),只要都能被指派給子頁面的delegate變數。

(母頁面Code)使母頁面遵從DismissBackDelegate,並自訂function,segue前指派子頁面的delegate(變數)為自己
(子頁面Code)dismiss前可以將dataToBeSent指派回母頁面

此方法在swift能使用closure之前經常被使用,這樣的概念很像用protocol包裝好所有Controller,而子頁面的變數型別為該protocol,因此所有遵從他的Controller都被能指派給該delegate變數(多型(polymorphism)觀念)。如此一來,不論有幾個母頁面,都能透過呼叫protocol所定義的方法來重複利用此子頁面了。

6. Callback function: 指派自訂的closure給子頁面的變數:

!請注意!因closure為reference type,使用closure須注意記憶體管理問題。本範例為解釋傳值需要,但已產生memory leak,相關議題可參考Swift ARC教學。

(母頁面Code)segue之前將自訂的closure指派給子頁面的變數
(子頁面Code)dismiss回來前執行自訂的closure

closure能在swift使用後,就不用透過protocol來包裝,直接就指派一個自訂的closure過去就行了。而closure內已經指定好self.myBackData,因此屆時被呼叫時,會直接將資料指派回來給他(myBackData)。

當然還有一些更進階的做法(參考文章中的Notification pattern、Reactive pattern,甚至更多)。
每種做法都有優缺點,取決於運用的時機與條件。

純分享心得,若觀念上有誤,還請不吝指正。

如果你喜歡我的文章,請幫我clap幾下,我會很感謝的!謝謝。

--

--