Why does implicitly unwrapped optional not unwrap in dictionary of type [String : Any]

后端 未结 4 611
灰色年华
灰色年华 2020-12-06 15:09

If I have an implicitly unwrapped optional declared in my class which I then reference in a Dictionary of type [String : Any], it doesn\'t get unwr

相关标签:
4条回答
  • 2020-12-06 15:14

    Under the rules set out by SE-0054, IUOs are only force unwrapped in contexts that demand their unwrapped type. In your case, the IUO doesn't need to be force unwrapped in order to be coerced to Any (as Any can represent any value), so it isn't.

    This behaviour is discussed in more detail in these Q&As:

    • Swift 3 incorrect string interpolation with implicitly unwrapped Optionals
    • Implicitly unwrapped optional assign in Xcode 8

    The fact that you end up with an ImplicitlyUnwrappedOptional value in your dictionary is legacy behaviour that has been removed in the latest Swift snapshots, in the future you will end up with an Optional value instead (as IUO is no longer a type).

    One important thing to note here however (that I'm sure will trip up people) is that the printing of IUOs got changed in 4.1.

    In Swift 4.0.3, your example prints like this:

    var aString: String! = "hello"
    var params : [String : Any] = [
      "myString" : aString
    ]
    print(params)
    // This prints ["myString": hello]
    

    giving you the illusion that the IUO was force unwrapped when coerced to Any. This however is just how IUOs were printed in Swift 4.0.3 – if they had a value, then they would print as that value, otherwise they would print as nil:

    var aString: String! = nil
    var params : [String : Any] = [
      "myString" : aString
    ]
    print(params)
    // This prints ["myString": nil]
    

    The reason why this changed in Swift 4.1 is that ImplicitlyUnwrappedOptional's conformance to Custom(Debug)StringConvertible was removed in this commit in order to make progress towards removing the type itself. So now ImplicitlyUnwrappedOptional values get printed using Swift's default printing mechanism (using reflection).

    So, in a dictionary, you get the IUO's default debugDescription, which looks like this:

    let aString: String! = "hello"
    let params : [String : Any] = [
      "myString" : aString
    ]
    print(params)
    // This prints ["myString": Swift.ImplicitlyUnwrappedOptional<Swift.String>.some("hello")]
    

    If you had printed it on its own, you would get its default description, which looks like this:

    let aString: String! = "hello"
    print(aString) // some("hello")
    

    This is because in Swift 4.1, the ImplicitlyUnwrappedOptional type is implemented in the same way as Optional, an enumeration with two cases:

    public enum ImplicitlyUnwrappedOptional<Wrapped> : ExpressibleByNilLiteral {
      // The compiler has special knowledge of the existence of
      // `ImplicitlyUnwrappedOptional<Wrapped>`, but always interacts with it using
      // the library intrinsics below.
    
      /// The absence of a value. Typically written using the nil literal, `nil`.
      case none
    
      /// The presence of a value, stored as `Wrapped`.
      case some(Wrapped)
    
      // ...
    }
    

    For an IUO with a payload value, Swift's default reflection will therefore print it as the case some containing the wrapped value.

    But this is only temporary; the IUO type is currently (in Swift 4.1) deprecated, however it will be removed in Swift 4.2. The compiler was internally using the IUO type in quite a few places, which took quite a bit of work to remove. Therefore in 4.2 you'll have actual Optional values in your dictionary, which will print like Optional("hello").

    0 讨论(0)
  • 2020-12-06 15:16

    When you define a dictionary of type

    let dictionary = [String:Any]()
    

    you can put anything in this dictionary

    like

     dictionary["name"] = "xyz"
    

    and

     dictionary["code"] = 123
    

    while in

    let dictionary = [String:String]()
    

    you can only put an only string value

    that's why you have to unwrap value when you are accessing the value because it can be anyting

    0 讨论(0)
  • 2020-12-06 15:22

    Change this line:

    var params : [String : Any] = ["myString" : aString]
    

    to:

    var params : [String : String] = ["myString" : aString]
    
    0 讨论(0)
  • 2020-12-06 15:22
    • Any can represent an instance of any type at all, including function types and optional types.
    • AnyObject can represent an instance of any class type.

    And your aString is an instance object which should not be use to declare in property Area, if you put that line in any function/instance function()then it will work perfectly, because it will be your instance type then.

    In One word, you can not declare instance type in property area in Swift.

    override func viewDidLoad() {
       let params : [String : Any] = ["myString": aString]
    }
    

    Even in Property Area, You can not do like following:

    var aString: String! = "String"
    var abc = aString
    

    You have to abc = aString do in any Method() to get work.

    Hope it will help you.

    0 讨论(0)
提交回复
热议问题