18

This code worked before Swift 3. (Curse you Swift 3!)

Now it's showing this error against the Flurry.logEvent(eventName, withParameters: userData!) line:

Cannot convert value of type 'NSMutableDictionary' to expected argument type '[AnyHashable : Any]!'

Casting userData! to [AnyHashable : Any] produces this error:

Cannot convert value of type 'NSMutableDictionary' to type '[AnyHashable : Any]' in coercion

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])
    }
}

What's the right syntax for Swift 3?

Crashalot
  • 33,605
  • 61
  • 269
  • 439
  • `Flurry.logEvent` expects `[AnyHashable:Any]`? Can you show the full method definition? – Bista Sep 22 '16 at 04:30
  • I am going to share this answer with you: [http://stackoverflow.com/questions/33561539/cannot-convert-value-of-type-nsmutabledictionary-to-type-nsobject-anyobject](http://stackoverflow.com/questions/33561539/cannot-convert-value-of-type-nsmutabledictionary-to-type-nsobject-anyobject) – Marlon Ruiz Nov 08 '16 at 19:20

1 Answers1

23

If that Flurry.logEvent(_:withParameters:) takes [AnyHashable: Any], why don't you use it as your local 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 seed including SE-0139 and SE-0140 is out, so the list below is updated.

These are the Objective-C safe types, when set to a [AnyHashable: Any] dictionary (or set in a [Any] array, or simply passed to Any which is a non-null id in Objective-C) in which is passed to Objective-C world:

Swift 3.0.1/Xcode 8.1

  • Optional values including nil

nil is converted to NSNull, all non-nil Optionals are unwrapped.

(NSNull may not be what you want. Still be careful about nil-checking.)

  • All numeric types and Bool

Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, as well as Int, UInt, Double, Float, CGFloat and Bool. These are converted to NSNumber.

  • String

Converted to NSString.

  • Array, where Element is Objective-C safe

Converted to NSArray.

  • Dictionary, where Key and Value are Objective-C safe

Converted to NSDictionary.

  • Set, where Element is Objective-C safe

Converted to NSSet

  • NSObject descendent types

Not converted, used as is.

  • Value types which have counter-part reference types

See the list here.

  • Value types where NSValue has an initializer for

NSRange, CGPoint, CGVector, CGSize, CGRect, CGAffineTransform, UIEdgeInsets, UIOffset, CATransform3D, CMTime, CMTimeRange, CMTimeMapping, CLLocationCoordinate2D, MKCoordinateSpan, SCNVector3, SCNVector4, SCNMatrix4. These types are converted to NSValue. (NSRange was already convertible to NSValue in older Swifts, but not well-documented.)

Bad things (example)

Still some values may be converted to _SwiftValue even in Swift 3.0.1.

  • Swift only types such as (Swift-only)enum, struct, tuple...

(See this list.)

I haven't checked all wrapper enums and structs, but some of them (for example, Notification.Name to NSString) seem to be safely converted.


Swift 3.0.0/Xcode 8.0

  • Non-Optional numeric types and Bool

Int, UInt, Double, Float, CGFloat and Bool. These are converted to NSNumber.

  • Non-Optional String

Converted to NSString.

  • Non-Optional Array, where Element is Objective-C safe

Converted to NSArray.

  • Non-Optional Dictionary, where Key and Value are Objective-C safe

Converted to NSDictionary.

  • Non-Optional Set, where Element is Objective-C safe

Converted to NSSet

  • Non-Optional NSObject descendent types

Not converted, used as is.

  • Non-Optional value types which have counter-part reference types

See the list here. (The linked article is updated for Swift 3.0.1.)

Bad things (example)

These may be converted to _SwiftValue, which is completely useless and disastrous in Objective-C world.

  • Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64
  • Any Optional values including nil
  • Swift only types such as (Swift-only)enum, struct, tuple...
Community
  • 1
  • 1
OOPer
  • 47,149
  • 6
  • 107
  • 142
  • Oh this is much cleaner! – Crashalot Sep 22 '16 at 05:42
  • But why the [:] as the second operand? – Crashalot Sep 22 '16 at 05:46
  • @Crashalot, using nil-coalescing operator `??` is a concise way to give a default value for nil case. `?? [:]` in my code corresponds to your `if userData == nil {userData = NSMutableDictionary()}`. – OOPer Sep 22 '16 at 06:15
  • Right, so shouldn't both operands be [AnyHashable:Any]? – Crashalot Sep 22 '16 at 06:25
  • @Crashalot, yes, but the right hand side `[:]` is a literal, so Swift can easily infer and define the type as ` [AnyHashable:Any]`. – OOPer Sep 22 '16 at 06:29
  • Oh interesting ... so if you had [NSObject:AnyObject] as the left operand, [:] would get inferred as [NSObject:AnyObject]? – Crashalot Sep 22 '16 at 06:37
  • @Crashalot, you need to know one bad thing with using `[AnyHashable: Any]`. `Any` can literally consumes Any Swift types. If you mistakenly pass something which cannot be handled in Objective-C world, that something would cause disastrous effect. Use it with care, please. – OOPer Sep 22 '16 at 06:47
  • What are examples of things not handled in Obj-C world? – Crashalot Sep 22 '16 at 07:03
  • @Crashalot, that can be some amount. I'll update my answer. – OOPer Sep 22 '16 at 07:08