Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Cannot assign value of type 'String' to type 'AnyObject?'", Swift 3, Xcode 8 beta 6

Tags:

swift

A fairly simple piece of code

var dict: [String: AnyObject] = [:]
dict["key"] = "value"

generates the following compile-time error

Cannot assign value of type 'String' to type 'AnyObject?'

Simple type checks tell me that String is AnyObject

"value" is AnyObject // returns true

I could change AnyObject to Any and everything would work

var dict: [String: Any] = [:]
dict["key"] = "value"

but I want to understand why do I get the error? Is String no longer AnyObject? Or is this a bug?

like image 685
xinatanil Avatar asked Aug 19 '16 18:08

xinatanil


2 Answers

In b6, String no longer magically bridges to NSString. String is not a class; it's a struct. You need to do the bridging by hand:

dict["key"] = "value" as AnyObject

The fact that is still seems to be bridging is likely a bug and should be reported.

It goes without saying that [String: AnyObject] and [String: Any] should be used as little as possible in your code.

(Make sure to follow the link Hamish provides in the comments below.)

like image 53
Rob Napier Avatar answered Nov 19 '22 08:11

Rob Napier


I'll complement to @RobNapier's answer with some official sources.


The removal of the implicit bridging mechanisms was accepted in the following Swift evolution proposal, to be implemented for Swift 3

  • SE-0072: Fully eliminate implicit bridging conversions from Swift

Previously, implicit conversions were available from some Swift native types to associated Objective-C types (Swift types conforming to private protocol _ObjectiveCBridgeable, e.g. natively Int, String, )

For this reason, we decided to make a compromise. We would require explicit bridging casts when converting from a bridged Objective-C type to its associated Swift value type (E.g., NSString -> String), but not the other way around.

... [From SE-0072]

With Swift 3, such implicit conversion mechanisms will no longer be available.

With the introduction of Objective-C generics last year, along with all of the awesome improvements to API importing happening for Swift 3, I think it’s time that we take another look at completing this work.

...

I propose that we fully eliminate implicit bridging conversions in Swift 3. This would mean that some users might have to introduce more explicit casts in their code, but we would remove another special case from Swift's type system and be able to further simplify the compiler.

...

Code that previously relied on implicit conversions between Swift value types and their associated bridged Objective-C type will now require a manual coercion via an as cast.

Finally, the release notes for Xcode 8 beta 6 (login required) states that this proposal has now been implemented for beta 6:

New in Xcode 8 beta 6 - Swift Compiler: Swift Language

...

  • Bridging conversions are no longer implicit. The conversion from a Swift value type to its corresponding object can be forced with as. For example: string as NSString. Any Swift value can also be converted to its boxed id representation with as AnyObject. (SE-0072)

W.r.t. new "boxed id" allowing explicit conversion for any Swift value to AnyObject, see e.g. the following thread:

  • AnyObject not working in Xcode8 beta6?
like image 29
dfrib Avatar answered Nov 19 '22 09:11

dfrib