遵從 protocol 問題: does not conform to protocol NSObjectProtocol

開發 iOS App 時,我們時常需要讓自訂的型別遵從 iOS SDK 的 protocol,比方我們自訂的 view controller 為了在表格 cell 點選時執行某段程式,需要遵從 protocol UITableViewDataDelegate。

class MovieViewController: UIViewController, UITableViewDelegate {   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {   }}

但如果我們使用沒有繼承任何人的類別遵從 protocol UITableViewDataDelegate 時,卻會產生莫名其妙的錯誤。

class MovieTableViewDelegate: UITableViewDelegate {  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {  }}

錯誤訊息提到 Cannot declare conformance to ‘NSObjectProtocol’ in Swift。但是我們明明是遵從 UITableViewDataDelegate,不是 NSObjectProtocol 呀。

非也。你還不夠了解 UITableViewDataDelegate,就像彼得潘不懂虎克船長一樣。其實它遵從著 UIScrollViewDelegate,而 UIScrollViewDelegate 遵從著 NSObjectProtocol,所以我們遵從 UITableViewDataDelegate 時,也要負責將 UIScrollViewDelegate & NSObjectProtocol 的功能實現。

protocol UITableViewDelegate : UIScrollViewDelegateprotocol UIScrollViewDelegate : NSObjectProtocol

問題應該不大,Xcode 現在有貼心的 Fix 按鈕,只要點選 Fix,它會幫我們補上需要定義的 protocol 功能。

但是事實不然。如上圖所示,Xcode 幫我們加了一堆來自 NSObjectProtocol 的 function,而且我們毫無頭緒,不知道該在這些 function 裡寫什麼。

其實我們不需要一個個辛苦地實現 NSObjectProtocol 的功能,有一個更簡單的方法,我們只要讓自訂的類別繼承 NSObject。

class MovieTableViewDelegate: NSObject, UITableViewDelegate {   func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {   }}

NSObject 怎麼會如此厲害呢 ? 答案就藏在它的身世裡。原來它早已遵從 NSObjectProtocol,因此它已經幫我們定義 NSObjectProtocol 的功能。這也是為何當我們的類別繼承 iOS SDK 內建類別再遵從 UITableViewDataDelegate 時不會有問題,因為所有的 iOS SDK 內建類別都繼承自 NSObject。

class NSObject : NSObjectProtocol

另外在遵從 iOS SDK 的 protocol 時,還有個小地方要注意。我們只能使用 class 型別,像以下 struct 定義的型別就無法。

Non-class type 'MovieTableViewDelegate' cannot conform to class protocol 'UITableViewDelegate'

錯誤訊息提到 struct 是 Non-class type,無法遵從 class protocol。iOS SDK 裡的 protocol 都是 class protocol,註定只能被 class 型別遵從。

--

--

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

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