URLSession.shared.dataTaskPublisher - 如何将收到的值转换为字符串?
URLSession.shared.dataTaskPublisher - how to convert received value to string?
作为 Swift 新手,我正在尝试使用以下代码下载和解析 CSV 文件:
URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.sink { completion in
} receiveValue: { csvWords in
let lines = csvWords.split(separator: "\n")
for line in lines {
let columns = line.split(separator: ",")
for column in columns {
print("column: \(column)")
}
}
但是我得到语法错误:
Cannot convert value of type 'String' to expected argument type 'Data.Element' (aka 'UInt8')
请帮助我了解发生了什么。
receiveValue返回的是什么值,不就是远程文件内容为字符串吗?
更新:
这是缺少的方法
func handleOutput(output: URLSession.DataTaskPublisher.Output) throws -> Data {
guard
// as? means "this might be nil"
let response = output.response as? HTTPURLResponse,
response.statusCode >= 200,
response.statusCode < 300
else {
throw URLError(.badServerResponse)
}
return output.data
}
从您的错误消息来看,handleOutput
似乎正在发布 Data
。如果你想调用字符串函数,你可以将其映射到 String
,例如
var cancellable: AnyCancellable?
func foo(_ url: URL) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.compactMap { String(data: [=10=], encoding: .utf8) }
.sink { completion in
...
} receiveValue: { string in
...
}
}
或者,如果您愿意,可以在无法将其转换为字符串时抛出错误:
var cancellable: AnyCancellable?
func foo(_ url: URL) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.tryMap { data -> String in
guard let string = String(data: data, encoding: .utf8) else {
throw URLError(.badServerResponse)
}
return string
}
.sink { completion in
...
} receiveValue: { string in
...
}
}
在您修改后的问题中,您分享了 handleOutput
。您只需更改它即可为您生成 String
:
func handleOutput(output: URLSession.DataTaskPublisher.Output) throws -> String {
guard
let response = output.response as? HTTPURLResponse,
200 ..< 300 ~= response.statusCode,
let string = String(data: output.data, encoding: .utf8)
else {
throw URLError(.badServerResponse)
}
return string
}
然后你就不需要额外的 compactMap
/tryMap
:
func foo(_ url: URL) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.sink { completion in
...
} receiveValue: { string in
...
}
}
作为 Swift 新手,我正在尝试使用以下代码下载和解析 CSV 文件:
URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.sink { completion in
} receiveValue: { csvWords in
let lines = csvWords.split(separator: "\n")
for line in lines {
let columns = line.split(separator: ",")
for column in columns {
print("column: \(column)")
}
}
但是我得到语法错误:
Cannot convert value of type 'String' to expected argument type 'Data.Element' (aka 'UInt8')
请帮助我了解发生了什么。
receiveValue返回的是什么值,不就是远程文件内容为字符串吗?
更新:
这是缺少的方法
func handleOutput(output: URLSession.DataTaskPublisher.Output) throws -> Data {
guard
// as? means "this might be nil"
let response = output.response as? HTTPURLResponse,
response.statusCode >= 200,
response.statusCode < 300
else {
throw URLError(.badServerResponse)
}
return output.data
}
从您的错误消息来看,handleOutput
似乎正在发布 Data
。如果你想调用字符串函数,你可以将其映射到 String
,例如
var cancellable: AnyCancellable?
func foo(_ url: URL) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.compactMap { String(data: [=10=], encoding: .utf8) }
.sink { completion in
...
} receiveValue: { string in
...
}
}
或者,如果您愿意,可以在无法将其转换为字符串时抛出错误:
var cancellable: AnyCancellable?
func foo(_ url: URL) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.tryMap { data -> String in
guard let string = String(data: data, encoding: .utf8) else {
throw URLError(.badServerResponse)
}
return string
}
.sink { completion in
...
} receiveValue: { string in
...
}
}
在您修改后的问题中,您分享了 handleOutput
。您只需更改它即可为您生成 String
:
func handleOutput(output: URLSession.DataTaskPublisher.Output) throws -> String {
guard
let response = output.response as? HTTPURLResponse,
200 ..< 300 ~= response.statusCode,
let string = String(data: output.data, encoding: .utf8)
else {
throw URLError(.badServerResponse)
}
return string
}
然后你就不需要额外的 compactMap
/tryMap
:
func foo(_ url: URL) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.sink { completion in
...
} receiveValue: { string in
...
}
}