• iOS 开发者关于URL操作会遇见的常见问题汇总
  • 发布于 11小时前
  • 8 热度
    0 评论
前言
昨天在写一个网络请求的时候,又被 Swift 中的 URL 操作给坑了一下。相信很多 iOS 开发者都遇到过类似的问题:URL 字符串转换时需要强制解包,查询参数提取起来特别麻烦,文件路径处理总是出错。URL 操作在 iOS 开发中真的是无处不在。从网络请求到本地文件访问,从图片加载到深度链接处理,几乎每个功能都离不开 URL。今天就来聊聊 Swift 中 URL 操作的那些常见场景和最佳实践。

基础 URL 操作,告别强制解包
最基本的 URL 创建,相信大家都写过这样的代码:
let url = URL(string: "https://www.duidaima.com")!
这个强制解包看起来就很不优雅,而且在代码里到处都是感叹号。有个简单的扩展可以解决这个问题:
extension URL {
    init(_ string: StaticString) {
        self.init(string: "\(string)")!
    }
}
let unwrappedURL = URL("https://www.duidaima.com")
这样就干净多了,不用满屏幕的感叹号。不过提醒一下,不建议这样使用,这样做本质上不安全,因为 URL 可能为空。

URL 转字符串,比你想象的简单
有时候需要把 URL 转回字符串,用 absoluteString 属性就行:
print(unwrappedURL.absoluteString) // 输出: https://www.apple.com
构建相对 URL,API 开发必备技能
在做 API 封装的时候,经常需要基于基础 URL 构建不同的端点:
let category = "swift"
let baseURL = URL(string: "https://www.apple.com")!
let blogURL = URL(string: category, relativeTo: baseURL)!
print(blogURL.absoluteString) // 输出: https://www.apple.com/swift
这种方式比字符串拼接要安全得多,不用担心路径分隔符的问题。

提取 URL 组件,这些属性很有用
URL 的各个部分都可以单独提取出来:
let twitterURL = URL(string: "https://twitter.com/twannl/photo.png")!
print(twitterURL.host!) // 输出: twitter.com
print(twitterURL.scheme!) // 输出: https
print(twitterURL.path) // 输出: /twannl/photo.png
print(twitterURL.pathExtension) // 输出: png
print(twitterURL.lastPathComponent) // 输出: photo.png
查询参数处理,URLComponents 是神器
处理带查询参数的 URL 时,URLComponents 比直接操作字符串要好用太多:
let avatarURL = "https://twitter.com/twannl/photo.png?width=200&height=200"
let components = URLComponents(string: avatarURL)!
print(components.query!) // width=200&height=200
print(components.queryItems!) // [width=200, height=200]
但这样获取特定参数值还是很麻烦,可以写个扩展:
extension Collection where Element == URLQueryItem {
    subscript(_ name: String) -> String? {
        first(where: { $0.name == name })?.value
    }
}

let width = components.queryItems!["width"]
let height = components.queryItems!["height"]
构建带参数的 URL,字典转查询参数
API 请求经常需要动态构建查询参数:
let parameters = [
    "width": 500,
    "height": 500
]

var avatarURLComponents = URLComponents(string: "https://twitter.com/twannl/photo.png")!
avatarURLComponents.queryItems = parameters.map { (key, value) in
    URLQueryItem(name: key, value: String(value))
}
print(avatarURLComponents.url!) 
// 输出: https://twitter.com/twannl/photo.png?width=500&height=500
为了让代码更简洁,可以写个 Array 的扩展:
extension Array where Element == URLQueryItem {
    init<T: LosslessStringConvertible>(_ dictionary: [String: T]) {
        self = dictionary.map { (key, value) in
            URLQueryItem(name: key, value: String(value))
        }
    }
}

// 使用起来就简单多了
avatarURLComponents.queryItems = .init(parameters)
文件 URL 操作,本地文件处理必备
处理本地文件时,需要区分远程 URL 和文件 URL:
let remoteURL = URL(string: "https://www.twitter.com/avatar.jpg")!
let fileURL = URL(string: "file:///users/antoine/avatar.jpg")!

print(remoteURL.isFileURL) // false
print(fileURL.isFileURL) // true
获取文件名和扩展名也很简单:
print(fileURL.pathExtension) // jpg
print(fileURL.deletingPathExtension().lastPathComponent) // avatar
实际开发中的应用场景
这些 URL 操作在实际项目中非常实用:
网络请求封装:用 URLComponents 构建复杂的 API 请求图片缓存:根据 URL 生成缓存 key文件管理:处理 Document 目录下的文件路径深度链接:解析 App 间跳转的 URL scheme

常见坑点提醒
URL 编码问题:包含中文或特殊字符的 URL 记得编码
查询参数顺序:URLComponents 可能会改变参数顺序

文件路径分隔符:不同平台的路径分隔符不同,用 URL 处理更安全


写在最后
URL 操作虽然看起来简单,但细节很多。掌握了这些技巧,能让你的代码更健壮,也能避免很多潜在的 bug。
你在 Swift URL 操作中踩过哪些坑?在评论区分享下你的经验吧!
用户评论