Swift中的URL
所属分类:ios | 发布于 2024-02-13
URL在外面构建的应用程序中无处不在,通常URL有两类。
1、本地文件URL,我们使用URL绑定路径引用本地文件。
2、远程URL,使用URL从指定的API的路径获取数据,或获取图像并显示。
URL基本操作
将字符串值转化为URL
let url = URL(string: "https://www.google.com")!
这种初始化方法的缺点是,生成的URL是一个可选值,在使用的时候需要强制解包。创建一个简单的扩展,通过使用自定义初始值来帮我们实现自动解包。
extension URL {
init(_ string: StaticString) {
self.init(string: "\(string)")!
}
}
var unwrappedURL = URL("https://www.google.com")
URL转String
可以使用URL的absoluteString属性把URL转换成String
print(unwrappedURL.absoluteString) // Prints: https://www.google.com
使用相对URL
在Swift中构建API时经常使用的一种场景是通过使用基本URL来构建连接。
例如,我们可以构建一个博客文章类别页面,如下
let category = "ios"
let baseURL = URL(string: "https://wenge365.com")!
let blogURL = URL(string: category, relativeTo: baseURL)!
print(blogURL) // Prints: swift -- https://wenge365.com
print(blogURL.absoluteString) // Prints: https://wenge365.com/ios
同时,如果URL本身是相对的,我们可以获得某个链接的基础URL
let absoluteURL = URL(string: "https://wenge365.com")!
let relativeURL = URL(string: "ios", relativeTo: baseURL)!
print(absoluteURL.baseURL) // Prints: nil
print(relativeURL.baseURL!) // Prints: https://wenge365.com
打印host和scheme
let swiftLeeURL = URL(string: "https://wenge365.com")!
print(absoluteURL.host!) // Prints: wenge365.com
print(absoluteURL.scheme!) // Prints: https
URL Components组件
链接基本上是由几个组件组成的。我们之前已经在印刷声明中看到了一些内容,但还有更多的内容需要涵盖:
let twitterAvatarURL = URL(string: "https://twitter.com/twannl/photo.png?width=200&height=200")!
print(twitterAvatarURL.path) // Prints: /twannl/photo.png
print(twitterAvatarURL.pathComponents) // Prints: ["/", "twannl", "photo.png"]
print(twitterAvatarURL.pathExtension) // Prints: png
print(twitterAvatarURL.lastPathComponent) // Prints: photo.png
获取查询参数
上面的twitter链接中有width和height两个参数,我们需要获取这两个参数以便于按正确的比例显示头像。
可以使用URLComponents来初始化链接。它返回一个新的属性集合,可以将其视为一个URL解析器,它让我们能访问参数项:
let components = URLComponents(string: "https://twitter.com/twannl/photo.png?width=200&height=200")!
print(components.query!) // width=200&height=200
print(components.queryItems!) // [width=200, height=200]
我们可以通过遍历查询项数组来直接访问值:
let width = components.queryItems!.first(where: { queryItem -> Bool in
queryItem.name == "width"
})!.value!
let height = components.queryItems!.first(where: { queryItem -> Bool in
queryItem.name == "height"
})!.value!
let imageSize = CGSize(width: Int(width)!, height: Int(height)!)
print(imageSize) // Prints: (200.0, 200.0)
但是,上面的代码使用了大量的unwrap,显得臃肿,代码可读性不高。因此我们可以使用自定义下标扩展,使代码看起来更好
extension Collection where Element == URLQueryItem {
subscript(_ name: String) -> String? {
first(where: { $0.name == name })?.value
}
}
let imageWidth = Int(components.queryItems!["width"]!)!
let imageHeight = Int(components.queryItems!["height"]!)!
let size = CGSize(width: imageWidth, height: imageHeight)
构建一个带参数的URL
有一个需求时从字典中构建一个带请求参数的URL,例如:
let parameters = [
"width": 500,
"height": 500
]
var avatarURLComponents = URLComponents(string: "https://twitter.com/twannl/photo.png")!
avatarURLComponents.queryItems = parameters.map({ (key, value) -> URLQueryItem in
URLQueryItem(name: key, value: String(value))
})
print(avatarURLComponents.url!) // Prints: https://twitter.com/twannl/photo.png?width=500&height=500
编写一个扩展,该扩展更容易地讲字典转换为查询项数组:
extension Array where Element == URLQueryItem {
init<T: LosslessStringConvertible>(_ dictionary: [String: T]) {
self = dictionary.map({ (key, value) -> Element in
URLQueryItem(name: key, value: String(value))
})
}
}
let pagingParameters = [
"offset": 2,
"limit": 50
]
var twitterFeedURLComponents = URLComponents(string: "https://twitter.com/feed")!
twitterFeedURLComponents.queryItems = .init(pagingParameters)
print(twitterFeedURLComponents.url!) // Prints: https://twitter.com/feed?offset=2&limit=50
文件URL
使用isFileURL属性可以区分远程URL和本地URL
var remoteFileURL = URL(string: "https://www.twitter.com/avatar.jpg")!
var fileURL = URL(string: "file:///users/antoine/avatar.jpg")!
print(remoteFileURL.isFileURL) // Prints: false
print(fileURL.isFileURL) // Prints: true
isFileURL属性只有在URL scheme为file:时才返回true。
获取本地文件URL扩展
print(fileURL.pathExtension) // Prints: jpg
获取本地文件的文件名(不包含扩展)
要从文件URL中获取文件名,我们可以使用lastPathComponent并通过删除文件扩展名来提取文件名:
print(fileURL.deletingPathExtension().lastPathComponent) // Prints: avatar