多頁面App間的資料傳遞(2)

自從做了多頁面App間的資料傳遞(1)後

就一直想把修改與回傳的功能也加進去

但實在太困難惹~困擾了我好多天~一直解不出來

看了好幾次peter的講義~再反覆參考隔壁班同學的作業

上班一有空閒就纏著IOS工程師勇勇問問題

終於把這煩人的玩意給解決惹!!

主題是聖誕歌曲

首先先建立分別指派給三個頁面的class

SongViewController(第一頁)

DetailViewController(第二頁)

EditViewController(第三頁)

然後從SongViewController(第一頁)拉一條Controller to Controller

的segue(show)到DetailViewController(第二頁)

並幫此條segue的Identifier取名為goDetail

在SongViewController(第一頁)中放入5個按鈕時

同時設定它們的Restoration ID~五個按鈕依序為01234

接著在SongViewController(第一頁)中建立五個按鈕的IBOutlet連線

以及一條代表Controller to Controller的IBAction連線

@IBOutlet weak var song1Button: UIButton!
@IBOutlet weak var song2Button: UIButton!
@IBOutlet weak var song3Button: UIButton!
@IBOutlet weak var song4Button: UIButton!
@IBOutlet weak var song5Button: UIButton!
@IBAction func goDetail(_ sender: UIButton) {
self.performSegue(withIdentifier: "goDetail", sender: sender)

依舊在SongViewController(第一頁)中

宣告一個名為Song包含order~name~singer~lyrics四個屬性的struct

struct Song {
var order = 0
var name = ""
var singer = ""
var lyrics = ""
}

宣告一個存取歌曲歌名~歌手跟歌詞的陣列songData

var songData = [
Song(order: 0, name : "Last Christmas", singer : "Wham", lyrics : "Last Christmas\nI gave you my heart\nBut the very next day\nyou gave it away\nThis year to save me from tears\nI'll give it to someone special"),
Song(order: 1, name : "Santa Tell Me", singer : "Ariana Grande", lyrics : "Santa, tell me if you're really there?\nDon't make me fall in love again if he won't be here\nNext year\nSanta, tell me if he really cares?"),
Song(order: 2, name : "Mistletoe", singer : "Justin Bieber", lyrics : "With you,shawty with you\nWith you,shawty with you\nWith you,under the mistletoe"),
Song(order: 3, name : "Silent Night", singer : "Kelly Clarkson", lyrics : "Silent night, holy night!\nAll is calm, all is bright.\nRound yon Virgin,\nMother and Child.\nHoly infant so tender and mild,\nSleep in heavenly peace,\nSleep in heavenly peace"),
Song(order: 4, name : "Joy To The World", singer : "Pentatonix", lyrics : "Joy to the World , the Lord is come!\nLet earth receive her King;\nLet every heart prepare Him room,\nAnd Heaven and nature sing,\nAnd Heaven and nature sing,\nAnd Heaven, and Heaven,\nand nature sing.")
]

利用prepare傳值,一個把值準備好傳過去的概念

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let button = sender as! UIButton
//取得button的Restoration ID
let idx = Int(button.restorationIdentifier!) ?? 0
let controller = segue.destination as! DetailViewController
//從songData裡面取出當對應的歌曲傳到下一頁
controller.song = songData[idx]
}

來到DetailViewController(第二頁)

建立歌名~歌手跟歌詞三個label的連線

@IBOutlet weak var songLabel: UILabel!
@IBOutlet weak var singerLabel: UILabel!
@IBOutlet weak var lyricTextView: UITextView!

在viewDidLoad()中寫下

songLabel.text = song.name
singerLabel.text = song.singer
lyricTextView.text = song.lyrics

來顯示從SongViewController(第一頁)傳來的值

一樣利用prepare來把值傳給EditViewController(第三頁)

var song : Song = Song()
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let controller = segue.destination as! EditViewController
controller.song = song

別忘了要把DetailViewController(第二頁)右上角的「編輯」按鈕

拉一條segue(show)到EditViewController(第三頁)

現在來看看最後一頁吧!EditViewController

一樣拉出三個Textfield的IBOutlet連線

@IBOutlet weak var songLabel: UITextField!
@IBOutlet weak var singerLabel: UITextField!
@IBOutlet weak var lyricTextView: UITextView!

然後從右上角的「完成」按鈕~拉一條IBAction連線到程式區

當使用者編輯完~按下「完成」按鈕後

發送修改通知出去,這邊使用Notification的方法來傳值

@IBAction func finished(_ sender: Any) {
let notificationName = Notification.Name("songUpdated")
//取畫面上的值
song.name = songLabel.text!
song.singer = singerLabel.text!
song.lyrics = lyricTextView.text!
//發送通知
NotificationCenter.default.post(name: notificationName, object: nil, userInfo: ["song":self.song]) //傳一個名稱叫”song”的song值過去
//回到前一頁
self.navigationController?.popViewController(animated: true)
}

然後回到DetailViewController(第二頁)

在viewDidLoad()中寫下申請接受通知的code

當收到通知時~執行songUpdated這個方法

let notificationName = Notification.Name("songUpdated")
NotificationCenter.default.addObserver(self, selector: #selector(songUpdated(noti:)), name: notificationName, object: nil)
updateInfo()

然後寫出一個更新頁面資訊的函式updateInfo()

func updateInfo(){
songLabel.text = song.name
singerLabel.text = song.singer
lyricTextView.text = song.lyrics
}

以及當收到通知時要執行的函式songUpdated()

func songUpdated(noti:Notification) {
song = noti.userInfo!["song"] as! Song
updateInfo()
}

第一頁也是

在viewDidLoad()中申請接受通知

let notificationName = Notification.Name("songUpdated")
NotificationCenter.default.addObserver(self, selector: #selector(songUpdated(noti:)), name: notificationName, object: nil)

比照第二頁的作業

寫出一個更新頁面資訊的函式updateInfo()

func updateInfo(){
song1Button.setTitle(songData[0].name, for: UIControlState.normal)
song2Button.setTitle(songData[1].name, for: UIControlState.normal)
song3Button.setTitle(songData[2].name, for: UIControlState.normal)
song4Button.setTitle(songData[3].name, for: UIControlState.normal)
song5Button.setTitle(songData[4].name, for: UIControlState.normal)
}

以及當收到通知時要執行的函式songUpdated()

func songUpdated(noti:Notification) {
let song = noti.userInfo!["song"] as! Song
songData[song.order] = song
//比對修改的按鈕去更新
if song.order == 0{
song1Button.setTitle(song.name, for: UIControlState.normal)
}else if song.order == 1{
song2Button.setTitle(song.name, for: UIControlState.normal)
}else if song.order == 2{
song3Button.setTitle(song.name, for: UIControlState.normal)
}else if song.order == 3{
song4Button.setTitle(song.name, for: UIControlState.normal)
}else if song.order == 4{
song5Button.setTitle(song.name, for: UIControlState.normal)
}
}

如此便完成了

SongViewController(第一頁)
DetailViewController(第二頁)
EditViewController(第三頁)