Swift 3:无法将'NSMutableDictionary'类型的值转换为预期的参数类型'[AnyHashable:Any]!'

Cra*_*lot 18 swift swift3

这段代码在Swift 3之前运行.(诅咒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])
    }
}
Run Code Online (Sandbox Code Playgroud)

什么是Swift 3的正确语法?

OOP*_*Per 21

如果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)
    }
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

Xcode 8.1转基因种子包括SE-0139SE-0140已经出局,因此下面的列表会更新.

这些是Objective-C安全类型,当设置为[AnyHashable: Any]字典(或在[Any]数组中设置,或者简单地传递给Objective-C中Any的非null id)时,其中传递给Objective-C世界:

Swift 3.0.1/Xcode 8.1

  • 可选值包括 nil

nil转换为NSNull,所有非零选项都被打开.

(NSNull可能不是你想要的.还是要小心检查.)

  • 所有数字类型和Bool

Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64,以及 Int,UInt,Double,Float,CGFloatBool.这些转换为NSNumber.

  • String

转换为NSString.

  • Array,ElementObjective-C安全的地方

转换为NSArray.

  • Dictionary,Objective-C安全的地方KeyValue目标

转换为NSDictionary.

  • Set,ElementObjective-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只有类型(如Swift-only)enum,struct,tuple ......

(见这个清单.)

我没有检查所有包装器枚举和结构,但其中一些(例如,Notification.Nameto NSString)似乎是安全转换的.


Swift 3.0.0/Xcode 8.0

  • 非可选数字类型和 Bool

Int,UInt,Double,Float,CGFloatBool.这些转换为NSNumber.

  • 非可选 String

转换为NSString.

  • 非可选Array,ElementObjective-C安全

转换为NSArray.

  • 非可选Dictionary,Objective-C安全的地方KeyValue目标

转换为NSDictionary.

  • 非可选Set,ElementObjective-C安全

转换成 NSSet

  • 非可选NSObject后代类型

未转换,按原样使用.

  • 具有对位引用类型的非可选值类型

请参阅此处的列表.(链接的文章已针对Swift 3.0.1进行了更新.)

坏事(例子)

这些可以转换为_SwiftValue,在Objective-C世界中完全无用且灾难性的.

  • Int8,UInt8,Int16,UInt16,Int32,UInt32,Int64,UInt64
  • 任何可选值包括 nil
  • Swift只有类型(如Swift-only)enum,struct,tuple ......