#ios #swift #string #csv #combine
Вопрос:
Будучи новичком в 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)")
}
}
однако я получаю синтаксическую ошибку:
Не удается преобразовать значение типа «Строка» в данные типа «ожидаемый аргумент».Элемент» (он же «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
}
Комментарии:
1. Показать
handleOutput
. Иначе как мы узнаем, что такое csvWords??? Но нет, то, что поступает из сети, является данными до тех пор, пока вы не преобразуете их в строку.2. Хорошо, я добавил
handleOutput
к своему вопросу извинения за то, что пропустил3. Ага, вот и ты. Ты возвращаешься
return output.data
. Это данные. Так вот что проходит по трубопроводу в раковину.4. Нет никакого «должен». Лично я бы просто сделал именно то, что советует Robs answer: добавьте оператора компактной карты. В любом случае, то, что вы здесь делаете, сильно перегружает раковину; раковина не должна обрабатывать, а только получать.
5. Да! Вот как бы я это сделал. Но многое зависит от того, какие значения вы хотите получить в конце конвейера.
Ответ №1:
Судя по вашему сообщению об ошибке, handleOutput
похоже, что это публикация Data
. Если вы хотите вызывать строковые функции, вы должны сопоставить это String
, например,
var cancellable: AnyCancellable?
func foo(_ url: URL) {
cancellable = URLSession.shared.dataTaskPublisher(for: url)
.tryMap(handleOutput)
.compactMap { String(data: $0, 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
...
}
}