How do I convert an NSDictionary to a Swift Dictionary<String, NSObject>?

匿名 (未验证) 提交于 2019-12-03 02:29:01

问题:

I am rewriting an Objective-C class in Swift to get a feel for the language. In Objective-C my class included the following method:

- (id) initWithCoder:(NSCoder *)aDecoder {     return [self initWithActionName:[aDecoder decodeObjectOfClass:[NSString class] forKey:@"actionName"]                             payload:[aDecoder decodeObjectOfClass:[NSDictionary class] forKey:@"payload"]                           timestamp:[aDecoder decodeObjectOfClass:[NSDate class] forKey:@"timestamp"]]; } 

After some trial and error with the compiler, I managed to rewrite it like this:

convenience init(aDecoder: NSCoder) {     let actionName = aDecoder.decodeObjectOfClass(NSString.self, forKey: "actionName") as NSString     let payload = aDecoder.decodeObjectOfClass(NSDictionary.self, forKey: "payload") as NSDictionary     let timestamp = aDecoder.decodeObjectOfClass(NSDate.self, forKey: "timestamp") as NSDate     self.init(actionName: actionName, payload: payload, timestamp: timestamp) } 

However, this still gives me an error on the last line: “Could not find an overload for init that accepts the supplied arguments.” The method signature of init is

init(actionName: String, payload: Dictionary<String, NSObject>, timestamp: NSDate) 

so I assume the problem is that I am trying to pass an NSDictionary instead of a Dictionary<String, NSObject>. How can I convert between these two not-quite-equivalent types? Should I just be using NSDictionary for all of the code that has to interact with other Objective-C components?

回答1:

Decode your dictionary as Dictionary<String, NSObject> instead of NSDictionary.

let payload = aDecoder.decodeObjectOfClass(NSDictionary.self, forKey: "payload") as! Dictionary<String, NSObject> 

Since you are using Cocoa Touch to serialize and deserialize, they are serialized as NSDictionary, but you can cast it to a Swift Dictionary<,>, as per WWDC 2014 Intermediary Swift and Advanced Swift videos.

You can also decode as NSDictionary and then explicitly cast the object like so:

self.init(actionName: actionName, payload: payload as! Dictionary<String, NSObject>, timestamp: timestamp) 

Basically, you are playing here with covariance/contravariance.



回答2:

Are you sure that that's the correct declaration for init? The argument order is different than the one you're calling in your Objective-C code.

So, if you want a precise reimplementation, the last call should probably be self.init(actionName: actionName, timestamp: timestamp, payload: payload). Calling the initializer with the wrong order of arguments would result in exactly the error message you're getting.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!