Optional chaining with Swift strings -


with optional chaining, if have swift variable

var s: string? 

s might contain nil, or string wrapped in optional. so, tried length:

let count = s?.characters?.count ?? 0 

however, compiler wants this:

let count = s?.characters.count ?? 0 

my understanding of optional chaining that, once start using ?. in dotted expression, rest of properties made optional , typically accessed ?., not ..

so, dug little further , tried in playground:

var s: string? = "foo" print(s?.characters) // output: optional(swift.string.characterview(_core: swift._stringcore(_baseaddress: 0x00000001145e893f, _countandflags: 3, _owner: nil))) 

the result indicates s?.characters indeed optional instance, indicating s?.characters.count should illegal.

can me understand state of affairs?

when say:

my understanding of optional chaining that, once start using ?. in dotted expression, rest of properties made optional , typically accessed ?., not ..

i there.

it’s not properties made optional, it’s original call optional, looks other properties optional.

characters not optional property, , neither count, value calling on optional. if there value, characters , count properties return value; otherwise, nil returned. because of result of s?.characters.count returns int?.

if either of properties optional, need add ? it, but, in case, aren’t. don’t.


edited following comment

from comment:

i still find strange both s?.characters.count , (s?.characters)?.count compile, (s?.characters).count doesn't. why there difference between first , last expression?

i’ll try , answer here, there more room in comment field:

s?.characters.count 

if s nil, whole expression returns nil, otherwise int. return type int?.

(s?.characters).count // won’t compile 

breaking down: if s nil, (s?.characters) nil, can’t call count on it.

in order call count property on (s?.characters), expression needs optionally unwrapped, i.e. written as:

(s?.characters)?.count 

edited add further

the best can explaining this bit of playground code:

let s: string? = "hello"  s?.characters.count (s?.characters)?.count (s)?.characters.count ((s)?.characters)?.count  // s?.characters.count func method1(s: string?) -> int? {     guard let s = s else { return nil }      return s.characters.count }  // (s?.characters).count func method2(s: string?) -> int? {     guard let c = s?.characters else { return nil }      return c.count }  method1(s) method2(s) 

Comments