Quick options: a language problem or something is wrong?

I do what I consider to be a very simple task. I am trying to get a value from a dictionary if a key exists. I do this for a key pair in a dictionary, and then create an object if they all exist (basically decoding a JSON object). I am new to the language, but it seems to me that it should work, but does not:

class func fromDict(d: [String : AnyObject]!) -> Todo? { let title = d["title"]? as? String // etc... } 

This gives me an error: Operand of postfix ? should have optional type; type is (String, AnyObject) Operand of postfix ? should have optional type; type is (String, AnyObject)

HOWEVER, if I do this, it works:

 class func fromDict(d: [String : AnyObject]!) -> Todo? { let maybeTitle = d["title"]? let title = maybeTitle as? String // etc... } 

This seems like a basic substitution, but some language nuance may be missing. Can anyone shed some light on this?

+6
source share
2 answers

Recommended Template

 if let maybeTitle = d["title"] as? String { // do something with maybeTitle } else { // abort object creation } 

Perhaps this is really a nuance issue. Form array[subscript]? ambiguous because this may mean that the entire dictionary ( <String:AnyObject> ) is optional, while you probably mean the result ( String ). In the above template, you are using the fact that the Dictionary intended to suggest that access to some key results leads to an optional type.

After experimenting and noticing what ? after as is equally ambiguous, moreover, here is my solution:

 var dictionary = ["one":"1", "two":"2"] // or var dictionary = ["one":1, "two":2] var message = "" if let three = dictionary["three"] as Any? { message = "\(three)" } else { message = "No three available." } message // "No three available." 

This will work with all objects without a Swift object, including Swift Strings, numbers, etc. Thanks to Victor for reminding me that String not an object in Swift . +

If you know the type of values, you can replace Any? to the corresponding optional type, for example String?

+3
source

There are a few things here.

1) ? in d["title"]? misused. If you are trying to expand d["title"] , use ! but be careful because it will crash if title not a valid key in your dictionary. ( ? used for an additional chain, as if you were trying to call a method on an optional variable or to access a property. In this case, the access just did nothing if the optional ones were nil ). It doesn't seem like you're trying to expand d["title"] , so leave a value ? . Access to the dictionary always returns an optional value, because the key may not exist.

2) If you were to fix this:

 let maybeTitle = d["title"] as? String 

The error message changes to: Error: '(String, AnyObject)' does not convert to 'String'

The problem here is that String not an object. You need to specify NSString .

 let maybeTitle = d["title"] as? NSString 

Will this cause maybeTitle be an NSString? . If d["title"] does not exist or if the type is really NSNumber instead of NSString , then optional will be nil , but the application will not crash.

3) Your expression:

 let title = maybeTitle as? String 

does not expand the optional variable as you would like. The correct form:

 if let title = maybeTitle as? String { // title is unwrapped and now has type String } 

So, all together:

 if let title = d["title"] as? NSString { // If we get here we know "title" is a valid key in the dictionary, and // we got the type right. title has now been unwrapped and is ready to use } 

title will be of type NSString , which is stored in the dictionary because it contains objects. You can do everything with NSString , which you can do with String , but if you need title be String , you can do this:

 if var title:String = d["title"] as? NSString { title += " by Poe" } 

and if your dictionary has NSNumber :

 if var age:Int = d["age"] as? NSNumber { age += 1 } 
+2
source

Source: https://habr.com/ru/post/974675/


All Articles