Как преобразовать NSDictionary в Swift Dictionary <String, NSObject>?
Я переписываю класс Objective-C в Swift, чтобы понять язык. В 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?
Ответы
Ответ 1
Расшифруйте свой словарь как Dictionary<String, NSObject>
вместо NSDictionary
.
let payload = aDecoder.decodeObjectOfClass(NSDictionary.self, forKey: "payload") as! Dictionary<String, NSObject>
Поскольку вы используете Cocoa Нажмите, чтобы сериализовать и десериализовать, они сериализуются как NSDictionary
, но вы можете передать его в Swift Dictionary<,>
, в соответствии с видеороликами SWDC 2014 Intermediary Swift и Advanced Swift.
Вы также можете декодировать как NSDictionary
, а затем явно применить объект следующим образом:
self.init(actionName: actionName, payload: payload as! Dictionary<String, NSObject>, timestamp: timestamp)
В принципе, вы играете здесь с ковариацией/контравариантностью.
Ответ 2
Вы уверены, что это правильное объявление для init? Порядок аргументов отличается от того, который вы вызываете в коде Objective-C.
Итак, если вам нужна точная повторная реализация, последний вызов должен быть self.init(actionName: actionName, timestamp: timestamp, payload: payload)
. Вызов инициализатора с неправильным порядком аргументов приведет к точному сообщению об ошибке, которое вы получаете.