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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With