Swift 3: Невозможно преобразовать значение типа "NSMutableDictionary" в ожидаемый тип аргумента "[AnyHashable: Any]!"

Этот код работал до Swift 3. (Curse you Swift 3!)

Теперь он показывает эту ошибку в строке Flurry.logEvent(eventName, withParameters: userData!):

Невозможно преобразовать значение типа "NSMutableDictionary" в ожидаемое тип аргумента '[AnyHashable: Any]!'

Отбрасывание userData! в [AnyHashable : Any] вызывает эту ошибку:

Невозможно преобразовать значение типа "NSMutableDictionary" в тип '[AnyHashable: Any]' в принуждении

func logEvent(_ eventName: String, userData: NSMutableDictionary?) {
    // Use <userData> or create new one?
    var userData = userData
    if userData == nil {
        userData = NSMutableDictionary()
    }

    // Set base properties
    userData!.setObject(gUser.tofus.count, forKey: "Num Tofus" as NSCopying)
    userData!.setObject(gUser.getLifetimeTofus(), forKey: "Num Lifetime Tofus" as NSCopying)

    // Call Flurry
    DispatchQueue.main.async {
        Flurry.logEvent(eventName, withParameters: userData! as [AnyHashable:Any])
    }
}

Какой правильный синтаксис для Swift 3?

Ответы

Ответ 1

Если этот Flurry.logEvent(_:withParameters:) принимает [AnyHashable: Any], почему бы вам не использовать его в качестве локального userData?

func logEvent(_ eventName: String, userData: NSMutableDictionary?) {
    // Use <userData> or create new one?
    var userData = userData as NSDictionary? as? [AnyHashable: Any] ?? [:]

    // Set base properties
    userData["Num Tofus"] = gUser.tofus.count
    userData["Num Lifetime Tofus"] = gUser.getLifetimeTofus()

    // Call Flurry
    DispatchQueue.main.async {
        Flurry.logEvent(eventName, withParameters: userData)
    }
}

UPDATE

Xcode 8.1 Семя GM, включая SE-0139 и SE-0140, приведен ниже. обновляется.

Это Objective-C безопасные типы, если они установлены в словарь [AnyHashable: Any] (или заданы в массиве [Any] или просто переданы в Any), который является непустым id в Objective-C), в котором передается Objective-C мир:

Swift 3.0.1/Xcode 8.1

  • Дополнительные значения, включая nil

nil преобразуется в NSNull, все не-нильские опции разворачиваются.

(NSNull может быть не так, как вы хотите. Будьте осторожны с проверкой nil.)

  • Все числовые типы и Bool

Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, а также Int, UInt, Double, Float, CGFloat и Bool. Они преобразуются в NSNumber.

  • String

Преобразован в NSString.

  • Array, где Element Objective-C безопасно

Преобразован в NSArray.

  • Dictionary, где Key и Value Objective-C safe

Преобразован в NSDictionary.

  • Set, где Element Objective-C безопасно

Преобразован в NSSet

  • NSObject типы потомков

Не конвертируется, используется как есть.

  • Типы значений, имеющие ссылочные типы встречных частей

См. список здесь.

  • Типы значений, где NSValue имеет инициализатор для

NSRange CGPoint, CGVector, CGSize CGRect, CGAffineTransform, UIEdgeInsets, UIOffset, CATransform3D CMTime, CMTimeRange CMTimeMapping, CLLocationCoordinate2D, MKCoordinateSpan, SCNVector3 SCNVector4, SCNMatrix4. Эти типы преобразуются в NSValue. (NSRange уже был конвертирован в NSValue в старых Swifts, но не был хорошо документирован.)

Плохие вещи (пример)

Еще некоторые значения могут быть преобразованы в _SwiftValue даже в Swift 3.0.1.

  • Быстрые типы, такие как (только Swift-only) enum, struct, tuple...

(см. этот список.)

Я не проверял все обертки и структуры, но некоторые из них (например, Notification.Name to NSString), по-видимому, безопасно преобразованы.


Swift 3.0.0/Xcode 8.0

  • Необязательные числовые типы и Bool

Int, UInt, Double, Float, CGFloat и Bool. Они преобразуются в NSNumber.

  • Необязательный String

Преобразован в NSString.

  • Необязательный Array, где Element Objective-C safe

Преобразован в NSArray.

  • Необязательный Dictionary, где Key и Value Objective-C safe

Преобразован в NSDictionary.

  • Необязательный Set, где Element Objective-C безопасный

Преобразован в NSSet

  • Необязательные NSObject типы потомков

Не конвертируется, используется как есть.

  • Необязательные типы значений, имеющие ссылочные типы встречных частей

См. список здесь. (Связанная статья обновлена ​​для Swift 3.0.1.)

Плохие вещи (пример)

Они могут быть преобразованы в _SwiftValue, что совершенно бесполезно и катастрофично в мире Objective-C.

  • Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64
  • Любые дополнительные значения, включая nil
  • Быстрые типы, такие как (только Swift-only) enum, struct, tuple...