我目前正在將一個大型專案從 Objective-C 更新到 Swift,但我對如何模仿某些邏輯感到困惑。基本上我們有一個帶有協議的類,它定義了幾個函式來將任何類轉換為自身的 JSON 表示。
該協議如下所示:
#define kJsonSupport @"_jsonCompatible"
#define kJsonClass @"_jsonClass"
@protocol JsonProtocol <NSObject>
- (NSDictionary*)convertToJSON;
- (id)initWithJSON:(NSDictionary* json);
@end
我已經把它改編成這樣的 Swift
let JSON_SUPPORT = "_jsonCompatible"
let JSON_CLASS = "_jsonClass"
protocol JsonProtocol
{
func convertToJSON() -> NSDictionary
init(json: NSDictionary)
}
ObjC 類中的一個函式為符合協議的 NSDictionary 中的每個物件運行 convertToJSON 函式,另一個執行相反的操作,使用 init 函式創建物件的實體。輸出字典還包含兩個鍵,一個表示所討論的字典支持此協議 ( kJsonSupport: BOOL),另一個包含物件從 ( kJsonClass: NSString)轉換而來的類的 NSString 表示。reverse 函式然后使用這兩者來確定物件從哪個類轉換為從給定字典初始化一個新實體。
所有的類對于函式本身都是匿名的。我們所知道的是每個類都符合協議,因此我們可以在其上呼叫自定義的 init 函式。
這是它在 ObjC 中的樣子:
Class rootClass = NSClassFromString(obj[kJsonClass]);
if([rootClass conformsToProtocol:@protocol(JsonProtocol)])
{
Class<JsonProtocol> jsonableClass = (Class<JsonProtocol>)rootClass;
[arr addObject:[[((Class)jsonableClass) alloc] initWithJSON:obj]];
}
但是,我不確定如何在 Swift 中實作這種行為。
這是我最好的嘗試。我使用 Swiftify 嘗試幫助我到達那里,但編譯器也不滿意:
let rootClass : AnyClass? = NSClassFromString(obj[JSON_CLASS] as! String)
if let _rootJsonClass = rootClass as? JsonProtocol
{
weak var jsonClass = _rootJsonClass as? AnyClass & JsonProtocol
arr.add(jsonClass.init(json: obj))
}
我在weak var線路和arr.add線路上都遇到了幾個錯誤,例如:
非協議、非型別別“AnyClass”(又名“AnyObject.Type”)不能在受協議約束的型別中使用
'init' 是該型別的成員;使用 'type(of: ...)' 來初始化一個相同動態型別的新物件
引數型別“NSDictionary”不符合預期型別“JsonProtocol”
呼叫中的無關引數標簽“json:”
有什么方法可以讓我使用自定義協議 init 函式從符合協議的未知類實體化?
uj5u.com熱心網友回復:
你可能想在未來重新考慮這段代碼,遵循更雨燕般的圖案,但它不是那個復雜的轉換,我敢肯定,你有很多的依賴行為以同樣的方式現有的代碼。
最重要的是所有的物件都必須是@objc類。它們不能是結構體,并且它們必須是 NSObject 的子類。這是您希望將其更改為基于 Codable 的更 Swifty 解決方案的主要原因。
您還需要明確命名您的型別。Swift 將模塊名稱添加到其型別名稱中,這往往會破壞這種動態系統。如果你有一個 type Person,你會想要宣告它:
@objc(Person) // <=== This is the important part
class Person: NSObject {
required init(json: NSDictionary) { ... }
}
extension Person: JsonProtocol {
func convertToJSON() -> NSDictionary { ... }
}
這可以確保類的名稱是Person(就像在 ObjC 中一樣)而不是MyGreatApp.Person(在 Swift 中通常是這樣)。
有了這個,在 Swift 中,這段代碼會這樣寫:
if let className = obj[JSON_CLASS] as? String,
let jsonClass = NSClassFromString(className) as? JsonProtocol.Type {
arr.add(jsonClass.init(json: obj))
}
您缺少的關鍵部分是as? JsonProtocol.Type. 這提供了與 conformsToProtocol:plus 演員類似的功能。在.Type表明這是一個元型別檢查Person.self,而不是在一個正常的型別檢查Person。有關更多資訊,請參閱Swift 語言參考中的元型別型別。
請注意,原始的 ObjC 代碼有點危險。在-initWithJSON 必須回傳一個物件。它不能回傳nil,否則此代碼將在addObject呼叫時崩潰。這意味著實作JsonProtocol要求物件構造一些東西,即使它傳遞的 JSON 是無效的。Swift 會強制執行此操作,但 ObjC 不會,因此您應該仔細考慮如果輸入損壞會發生什么。init如果您可以使用當前代碼使其作業,我很想將其更改為可失敗或拋出初始化程式。
我還建議用字典和陣列替換 NSDictionary 和 NSArray。這應該相當簡單,無需重新設計代碼。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/396575.html
