Swift 中 Selector 方法的訪問許可權控制問題

發表於2015-10-13

Swift中Selector方法的訪問許可權控制問題

今天用Swift寫了個檢視,在檢視上加個手勢,如下所示:

執行了下程式,然後崩潰了。崩潰日誌如下:

而我已經在SwipeCardView類中定義了beginDragged:方法,如下所示:

由於我並不想將beginDragged:方法暴露出去,所以將其定義為一個private方法。方法的定義一切正常,手勢的Selector方法也設定正常,卻報了未找到方法的異常。那問題可能就應該在訪問許可權問題上了。

我們知道Selector是Objective-C的產物,它用於在執行時作為一個鍵值去找到對應方法的實現。一個Objective-C的方法是由objc_method結束體定義的,其宣告如下:

這就要求selector引用的方法必須對ObjC執行時是可見的。而Swift是靜態語言,雖然繼承自NSObject的類預設對ObjC執行時是可見的,但如果方法是由private關鍵字修飾的,則方法預設情況下對ObjC執行時並不是可見的,所以就導致了以上的異常:執行時並沒找到SwipeCardView類的beginDragged:方法。

所以,我們必須將private修飾的方法暴露給執行時。正確的做法是在 private 前面加上 @objc 關鍵字,這樣就OK了。

另外需要注意的是,如果我們的類是純Swift類,而不是繼承自NSObject,則不管方法是private還是internal或public,如果要用在Selector中,都需要加上@objc修飾符。

參考

  1. SELECTOR
  2. @selector() in Swift?

 

零碎

Swift中列舉項設定相同的值

在Objective-C及C語言中,在列舉中我們可以設定兩個列舉項的值相等,如下所示:

在上例中,我們讓列舉項TypeDefault的值等於TypeIn。

而在Swift中,要求列舉項的rawValue是唯一的,如果像下面這樣寫,則編譯器會報錯:

那如果我們希望上面列舉中Default的值與In的值一樣,那應該怎麼做呢?這時候就需要充分利用Swift中enum的特性了。我們知道,Swift中的enum與結構體、類一樣,可以為其定義屬性和方法,所以我們可以如下處理:

我們將Default定義為Type的一個靜態只讀屬性,這個屬性與列舉的其它列舉項的呼叫方式是一樣的,可以如下呼叫:

參考

  1. Swift enum multiple cases with the same value

Swift中如何實現IBOutletCollection

在使用IB做介面開發時,我們經常需要將介面上的元素連線到我們的程式碼中。IBOutlet和IBAction就是專門用來做這事的兩個關鍵字。另外在Objective-C還提供了一個偽關鍵字IBOutletCollection,它的實際作用是將介面上的一組相同的控制元件連線到一個陣列中。具體可以參考iOS知識小集 第一期(2015.05.10)中的IBOutletCollection一節。

在Swift中,同樣提供了@IBOutlet和@IBAction實現Objective-C中對應的功能,不過卻沒提供@IBOutletCollection來將一組相同控制元件連線到一個陣列中。那如果我們想實現類似的功能,需要怎麼處理呢?

實際上,我們在IB中選中一組相同的控制元件,然後將其連到到程式碼中時,會生成一個IBOutlet修飾的控制元件陣列,類似於如下程式碼:

這就是Swift中類IBOutletCollection的處理。如果需要往陣列中新增新建的對應的控制元件,則只需要在程式碼前面的小圓點與UI上的控制元件做個連線就OK了。而如果要想將控制元件從陣列中移除,則只需要將對應的連線關係移除就可以了。

參考

  1. iOS知識小集 第一期(2015.05.10)
  2. Swift – IBOutletCollection equivalent

相關文章