【问题标题】:Swift 3: Cannot convert value of type 'NSMutableDictionary' to expected argument type '[AnyHashable : Any]!'Swift 3:无法将“NSMutableDictionary”类型的值转换为预期的参数类型“[AnyHashable:Any]!”
【发布时间】:2017-01-30 12:17:48
【问题描述】:

这段代码在 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])
    }
}

Swift 3 的正确语法是什么?

【问题讨论】:

标签: swift swift3


【解决方案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)
    }
}

更新

包含SE-0139SE-0140 的Xcode 8.1 GM 种子已发布,因此更新了以下列表。

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

斯威夫特 3.0.1/Xcode 8.1

  • 可选值,包括nil

nil 转换为 NSNull,所有非 nil 选项都被解包。

NSNull 可能不是你想要的。还是要小心 nil-checking。)

  • 所有数字类型和Bool

Int8UInt8Int16UInt16Int32UInt32Int64UInt64,以及 IntUIntDoubleFloatCGFloatBool。这些被转换为NSNumber

  • String

转换为NSString

  • Array,其中 Element 是 Objective-C 安全的

转换为NSArray

  • Dictionary,其中 KeyValue 是 Objective-C 安全的

转换为NSDictionary

  • Set,其中 Element 是 Objective-C 安全的

转换为NSSet

  • NSObject 后代类型

未转换,按原样使用。

  • 具有对应引用类型的值类型

查看列表here

  • NSValue 具有初始值设定项的值类型

NSRange, CGPoint, CGVector, CGSize, CGRect, CGAffineTransform, UIEdgeInsets, UIOffset, CATransform3D, CMTime, CMTimeRange, CMTimeMapping, CLLocationCoordinate2D, MKCoordinateSpan, SCNVector3, SCNVector4, SCNMatrix4。 这些类型转换为NSValueNSRange 在旧 Swift 中已经可以转换为 NSValue,但没有详细记录。)

坏事(例子)

即使在 Swift 3.0.1 中,仍有一些值可能会转换为 _SwiftValue

  • 仅限 Swift 的类型,例如(仅限 Swift)枚举、结构、元组...

(见this list。)

我没有检查所有包装枚举和结构,但其中一些(例如,Notification.NameNSString)似乎已安全转换。


Swift 3.0.0/Xcode 8.0

  • 非可选数字类型和Bool

IntUIntDoubleFloatCGFloatBool。这些被转换为NSNumber

  • 非可选String

转换为NSString

  • 非可选 Array,其中 Element 是 Objective-C 安全的

转换为NSArray

  • 非可选的Dictionary,其中KeyValue 是Objective-C 安全的

转换为NSDictionary

  • 非可选Set,其中Element 是Objective-C 安全的

转换为NSSet

  • 非可选 NSObject 后代类型

未转换,按原样使用。

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

查看列表here。 (链接的文章针对 Swift 3.0.1 进行了更新。)

坏事(例子)

这些可能会被转换成_SwiftValue,这在Objective-C世界中是完全没用的和灾难性的。

  • Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64
  • 任何可选值,包括nil
  • 仅限 Swift 的类型,例如(仅限 Swift)枚举、结构、元组...

【讨论】:

  • 哦,这样干净多了!
  • 但是为什么将 [:] 作为第二个操作数?
  • @Crashalot,使用 nil-coalescing 运算符 ?? 是为 nil 大小写提供默认值的简洁方法。我的代码中的?? [:] 对应于您的if userData == nil {userData = NSMutableDictionary()}
  • 对,那么两个操作数不应该都是 [AnyHashable:Any] 吗?
  • @Crashalot,是的,但是右边的 [:] 是一个字面量,所以 Swift 可以很容易地推断并将类型定义为 `[AnyHashable:Any]`。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-13
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多