在這個節拍器的app中,嘗試使用protocol & delegate及singleton來讓不同的view controller溝通、獲取資訊。
Protocol & Delegate
這裡使用protocol和delegate的組合,讓兩個popover中的資料被選取後,mainVC可以做出相對應的變化和反應。
例如在節拍、音樂速度選取器的popover中轉動picker時,mainVC的按鈕也要同時將選取到的節拍數字、速度記號顯示在按鈕上,讓使用者有更好的體驗,同時也要改變節拍器的節奏音效。而音樂選取器的picker轉到不同的速度記號時,節拍器上顯示的BPM也要同時改變為相對應的速度值。
使用Protocol & Delegate的retain cycle問題
因為MainVC與TimeSigPickerVC(以及MainVC與TempoMArkingPickerVC)彼此reference會造成retain cycle的問題,因此需在var delegate前面加上weak keyword。
而protocol的後面也必須加上class keyword,限制protocol只能被reference type使用,因為retain cycle的問題只會發生在reference type,所以weak也是專門給reference type使用的。
少了class keyword,Xcode會跳出error:
‘weak’ must not be applied to non-class-bound ‘TimeSigVCDelegate’; consider adding a protocol conformance that has a class bound
Singleton
一開始打算將popover中得到的資料利用delegate傳回mainVC,但因為那些資料將會用在mainVC多個地方,而且再次點選跳進popover後也會需要使用那些資料來設定picker view選取到的內容,這樣傳來傳去太麻煩,索性運用static讓變數變成type property,這樣所有VC都能獲取、更改到同一個變數。
也讓enum TempoMarkings遵從protocol CaseIterable,就能利用allCases得到一個所有enum cases的array,再使用map得到所有cases的string型別的array,用來呈現在速度記號的picker view上。
[Swift]Metronome #2 Custom UIButton 自訂有兩層陰影的Button
[Swift]Metronome #3 Glowing Animation發光動畫效果
[Swift]Metronome #4 Popover 選取視窗, Google AdMob
References:
Delegate & Retain Cycle
Passing Data
Singleton
Array