swift type 如何將類類型作為函數參數傳遞




swift泛型 (3)

你正在用錯誤的方式接近它:在Swift中,與Objective-C不同,類有特定的類型,甚至有一個繼承層次結構(也就是說,如果B類從A繼承,那麼B.Type也從A.Type繼承):

class A {}
class B: A {}
class C {}

// B inherits from A
let object: A = B()

// B.Type also inherits from A.Type
let type: A.Type = B.self

// Error: 'C' is not a subtype of 'A'
let type2: A.Type = C.self

這就是為什麼你不應該使用AnyClass ,除非你真的想允許任何類。 在這種情況下,正確的類型是T.Type ,因為它表示了T.Type參數和閉包參數之間的關係。

實際上,使用它而不是AnyClass允許編譯器正確地推斷方法調用中的類型:

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: T.Type, completionHandler handler: ((T) -> ())) {
    // The compiler correctly infers that T is the class of the instances of returningClass
    handler(returningClass())
}

現在有一個構建T的實例傳遞給handler :如果你現在嘗試運行代碼,編譯器會抱怨T不能用()構造。 理所當然的是: T必須被明確地限制為要求它實現一個特定的初始化器。

這可以通過如下協議來完成:

protocol Initable {
    init()
}

class CityInfo : NSObject, Initable {
    var cityName: String?
    var regionCode: String?
    var regionName: String?

    // Nothing to change here, CityInfo already implements init()
}

那麼你只需invokeService的通用約束從<T>更改為<T: Initable>

小費

如果您遇到奇怪的錯誤,如“無法將表達式的類型'()'轉換為鍵入'字符串'”,將方法調用的每個參數移動到它自己的變量通常都是有用的。 它有助於縮小導致錯誤的代碼並發現類型推斷問題:

let service = "test"
let params = ["test" : "test"]
let returningClass = CityInfo.self

CastDAO.invokeService(service, withParams: params, returningClass: returningClass) { cityInfo in /*...*/

}

現在有兩種可能性:錯誤轉移到其中一個變量(這意味著錯誤的部分在那裡),或者你得到一個神秘的消息,如“無法將表達式的類型()轉換為類型($T6) -> ($T6) -> $T5 “。

後一個錯誤的原因是編譯器無法推斷出你寫的內容。 在這種情況下,問題在於T僅用於閉包的參數,並且您傳遞的閉包並不表示任何特定的類型,因此編譯器不知道要推斷的類型。 通過改變returnedClass的類型來包含T你可以給編譯器一種確定泛型參數的方法。

我有一個通用函數調用Web服務並將JSON響應序列化回對象。

class func invokeService<T>(service: String, withParams params: Dictionary<String, String>, returningClass: AnyClass, completionHandler handler: ((T) -> ())) {

            /* Construct the URL, call the service and parse the response */
}

我試圖完成的就是這個Java代碼的等價物

public <T> T invokeService(final String serviceURLSuffix, final Map<String, String> params,
                               final Class<T> classTypeToReturn) {
}
  • 我正在嘗試完成的方法簽名是否正確?
  • 更具體地說,是指定AnyClass作為參數類型是否正確?
  • 當調用方法時,我傳遞MyObject.self作為returningClass值,但是我得到一個編譯錯誤“無法將表達式的類型'()'轉換為鍵入'String'”
CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: CityInfo.self) { cityInfo in /*...*/

}

編輯:

我嘗試使用object_getClass ,正如holex所述,但現在我得到:

錯誤:“類型'CityInfo.Type'不符合協議'AnyObject'”

需要做什麼才能符合協議?

class CityInfo : NSObject {

    var cityName: String?
    var regionCode: String?
    var regionName: String?
}

使用obj-getclass

CastDAO.invokeService("test", withParams: ["test" : "test"], returningClass: obj-getclass(self)) { cityInfo in /*...*/

}

假設self是城市信息對象。


你可以通過這種方式獲得AnyObject的類:

Swift 3.x

let myClass: AnyClass = type(of: self)

Swift 2.x

let myClass: AnyClass = object_getClass(self)

如果你願意的話,你可以稍後將它作為參數傳遞。





type-inference