Swift使用guard let从字典取值后URL仍需解包问题排查
问题根源
你遇到的编译错误是双重可选类型没有完全解包导致的,和guard语句本身无关,具体逻辑如下:
URL(string:)是可失败构造器,返回值为URL?类型,因此你定义的urls字典被推导为[String: URL?]类型,它的value本身就是可选值。- 字典通过key取值的返回值本身也是可选类型(key不存在时返回nil),因此
urls["en"]的实际类型是URL??,也就是嵌套了两层的可选类型。 - 你写的
guard let url = urls["en"] else { return }只解包了第一层可选,只确认了字典中存在en这个key,解包得到的url还是URL?类型,仍然包含一层可选,自然无法传入要求非可选URL参数的dataTaskPublisher(for:)方法。
解决方案
这里提供3种常用的解决方式,你可以根据自己的场景选择:
- 方式1:取值时同时解包两层可选
只需要修改guard语句,同时完成两层可选的解包即可:// 简洁的两层解包写法 guard let url = urls["en"]?? else { return } // 也可以用更易读的分步解包写法 // guard let optionalUrl = urls["en"], let url = optionalUrl else { return } - 方式2:定义字典时就将value转为非可选(推荐)
你用到的几个URL都是固定的合法字符串,完全可以在定义时就确认URL有效,避免后续每次取值都要多层解包:
如果你的项目最低支持iOS 16+,还可以用系统内置的let urls = [ "en" : URL(string: "https://wordsbyfarber.com/ws/top")!, "de" : URL(string: "https://wortefarbers.de/ws/top")!, "ru" : URL(string: "https://slova.de/ws/top")! ]#URL宏,编译期就会校验URL合法性,比强制解包更安全:
这两种写法定义的字典类型都是let urls = [ "en" : #URL("https://wordsbyfarber.com/ws/top"), "de" : #URL("https://wortefarbers.de/ws/top"), "ru" : #URL("https://slova.de/ws/top") ][String: URL],后续取值只需要解包一层即可正常使用。 - 方式3:转换字典去除可选value
如果你不确定URL构造是否一定成功,可以用compactMapValues过滤掉构造失败的nil值,把字典转为[String: URL]类型:let urls: [String: URL] = [ "en" : URL(string: "https://wordsbyfarber.com/ws/top"), "de" : URL(string: "https://wortefarbers.de/ws/top"), "ru" : URL(string: "https://slova.de/ws/top") ].compactMapValues { $0 }
内容的提问来源于stack exchange,提问作者Alexander Farber
相关产品推荐
相关产品推荐

