我正在重写Swift中的Objective-C类来感受语言。在Objective-C中,我的课程包括以下方法:
- (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"]];
}
经过编译器的一些试验和错误后,我设法重写它:
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)
}
但是,这仍然在最后一行给出了一个错误:“找不到接受提供的参数的init
的重载。”init
的方法签名是
init(actionName: String, payload: Dictionary<String, NSObject>, timestamp: NSDate)
所以我认为问题在于我试图传递NSDictionary
而不是Dictionary<String, NSObject>
。如何在这两种不完全等效的类型之间进行转换?我是否应该将NSDictionary
用于必须与其他Objective-C组件交互的所有代码?
答案 0 :(得分:14)
将您的字典解码为Dictionary<String, NSObject>
,而不是NSDictionary
。
let payload = aDecoder.decodeObjectOfClass(NSDictionary.self, forKey: "payload") as! Dictionary<String, NSObject>
由于您使用Cocoa Touch进行序列化和反序列化,因此它们被序列化为NSDictionary
,但您可以根据WWDC 2014 Intermediary Swift Dictionary<,> >和 Advanced Swift 视频。
你也可以解码为NSDictionary
,然后显式地转换对象:
self.init(actionName: actionName, payload: payload as! Dictionary<String, NSObject>, timestamp: timestamp)
基本上,你在这里玩协方差/逆变。
答案 1 :(得分:1)
你确定这是init的正确声明吗?参数顺序与您在Objective-C代码中调用的顺序不同。
因此,如果您需要精确的重新实现,最后一次调用应该是self.init(actionName: actionName, timestamp: timestamp, payload: payload)
。使用错误的参数顺序调用初始化程序将导致您收到的错误消息。