透過 delegate or data source 實現 App 功能的步驟說明

開發 iOS App 時,我們時常透過 delegate or data source,定義某個 protocol 的相關 function 實現功能。相關的動作可以簡單分為三個步驟:

  • 定義型別 A 遵從 protocol。
  • 在型別 A 裡定義和某個功能有關的 protocol function。
  • 指定 data source or delegate 是型別 A 生成的東西。

只要熟練以上三個步驟,即可靈活運用 iOS SDK 裡各種 delegate 和 data source,實現我們想要的功能。接下來我們就以 UITextViewDelegate & QLPreviewControllerDataSource 的例子說明吧。

例子 1: 彼得潘因為小時候李白的詩背不出來被老師打,所以不喜歡李白,因此決定讓使用者無法在 App 的 text view 輸入李白。

為了實現此功能,一般我們會聯想是否有 function 能在使用者輸入每個字時觸發,然後在此 function 控制輸入的文字。經由 google 大神的幫忙,我們查到使用者輸入文字時, text view 將找 delegate 幫忙,觸發 protocol UITextViewDelegate 的 function textView(_:shouldChangeTextIn:replacementText:),因此我們可透過它控制使用者是否能輸入李白。接下來我們就照剛剛提到的三步驟實現吧。

1 讓 ViewController 遵從 protocol UITextViewDelegate。

我們時常用 view controller 當 delegate or data source,為了讓以下畫面的 controller 成為 text view 的 delegate,我們讓 class ViewController 遵從 protocol UITextViewDelegate。

class ViewController: UIViewController, UITextViewDelegate

遵從 protocol 也有另一種寫法,利用 extension 讓 ViewController 遵從 UITextViewDelegate,此方法可讓程式切得比較乾淨,讓 class ViewController { } 裡的程式碼不會太多。

extension ViewController: UITextViewDelegate {

}

2 定義 protocol UITextViewDelegate 的 function textView(_:shouldChangeTextIn:replacementText:)

此 function 在 protocol 的宣告如下。

optional func textView(_ textView: UITextView, 
shouldChangeTextIn range: NSRange,
replacementText text: String) -> Bool

從以下連結的說明文字,我們明白此 function 將在使用者輸入或刪除文字時觸發,回傳 true 或 false 將控制文字是否能順利輸入或刪除。

了解此 function 的用途後,我們在 function 裡判斷加入使用者新輸入的文字 text 後,newText 是否包含可惡的李白,若有則回傳 false,不讓它輸入,其它則回傳 true。

func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
var result = true
if let originalText = textView.text,
let range = Range(range, in: originalText) {
let newText = originalText.replacingCharacters(in: range, with: text)
if newText.contains("李白") {
result = false
}
}
return result
}

3 將 controller 指定為 text view 的 delegate。

我們可在 storyboard 從 text view 連到 view controller,然後將 controller 設為 text view 的 delegate。

想從程式指定 delegate 也可以。我們可連結 text view 的 outlet,然後在 class ViewController 的 viewDidLoad 設定。

class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet var lyricsTextView: UITextView!

override func viewDidLoad() {
super.viewDidLoad()
lyricsTextView.delegate = self
}

結果

要輸入白時,因為會跟前面的字合成李白,所以不行 !

想當李壞倒是可以。

例子 2: 利用 QLPreviewController 顯示 PDF。

QLPreviewController 可以預覽 pdf,word,圖片等檔案,不過必須找 data source 幫忙,透過protocol QLPreviewControllerDataSource 的 function numberOfPreviewItems(in:) & previewController(_:previewItemAt:) 設定顯示的內容。

1 加入預覽的檔案。

為了學習 iOS App 開發,我們決定好好閱讀 Stanford 的 iOS 課程投影片,以下我們先將 pdf 檔 Lecture-1-Slides.pdf 加入專案。

2 讓 ViewController 遵從 protocol QLPreviewControllerDataSource。

protocol QLPreviewControllerDataSource 裡有些一定要定義的 function,沒定義會出現紅色錯誤,does not conform to protocol。

此時我們只要點選 Fix,Xcode 即可幫我們輸入。

3 定義 protocol QLPreviewControllerDataSource 的 function numberOfPreviewItems(in:) & previewController(_:previewItemAt:)

這兩個 function 控制 QLPreviewController 顯示的檔案數量和內容,相關說明可參考以下連結:

(1) 定義 function function numberOfPreviewItems(in:) 設定預覽的檔案數量。

func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
return 1
}

我們只要預覽一份 pdf 檔,所以回傳 1。

(2) 定義 function previewController(_:previewItemAt:) 設定預覽的檔案。

func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
if let url = Bundle.main.url(forResource: "Lecture-1-Slides", withExtension: "pdf") {
return url as QLPreviewItem
} else {
fatalError()
}

將 pdf 檔的 URL 回傳,表示此 pdf 檔為預覽的檔案。因為 URL 型別本來就遵從 protocol QLPreviewItem,所以我們可以利用 as 轉型回傳。(因為轉型一定成功,所以寫 as,而不是 as!)

對於 URL 遵從 protocol QLPreviewItem 有興趣的朋友,可參考以下連結的說明。

4 顯示 QLPreviewController, 將 view controller 指定為 QLPreviewController 的 dataSource。

@IBAction func showPdf(_ sender: Any) {
let controller = QLPreviewController()
controller.dataSource = self
present(controller, animated: true, completion: nil)
}

結果

--

--

彼得潘的 Swift iOS App 開發問題解答集
彼得潘的 Swift iOS App 開發問題解答集

Published in 彼得潘的 Swift iOS App 開發問題解答集

彼得潘和學生們在開發 Swift iOS App 路上曾經解決的問題集

彼得潘的 iOS App Neverland
彼得潘的 iOS App Neverland

Written by 彼得潘的 iOS App Neverland

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com