Reputation: 16089
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?
Upvotes: 19
Views: 16694
Reputation: 57040
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.
Upvotes: 14
Reputation: 3133
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.
Upvotes: 1