Подтвердить что ты не робот

Как преобразовать 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?

4b9b3361

Ответ 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). Вызов инициализатора с неправильным порядком аргументов приведет к точному сообщению об ошибке, которое вы получаете.