NSNetService dictionaryFromTXTRecord не может подтвердить неверный ввод
Вход в dictionary(fromTXTRecord:)
приходит из сети, потенциально из-за пределов приложения или даже устройства. Тем не менее, документы Apple говорят:
... Сбой утверждения, если txtData не может быть представлен как объект NSDictionary.
Неудачное утверждение оставляет программиста (меня) без способа обработки ошибки, что кажется нелогичным для метода, который обрабатывает внешние данные.
Если я запускаю это в терминале на Mac:
dns-sd -R 'My Service Name' _myservice._tcp local 4567 asdf asdf
мое приложение, работающее на iPhone, вылетает.
dictionary(fromTXTRecord:)
ожидает данные записи TXT (asdf asdf
) Быть в key=val
форма. Если, как и выше, слово не содержит =
метод не сможет проанализировать его и не сможет подтвердить утверждение.
Я не вижу способа решить эту проблему, кроме как вообще не использовать этот метод и реализовать собственный синтаксический анализ, что кажется неправильным.
Я что-то пропустил?
3 ответа
Вот решение в Swift 4.2, предполагая, что запись TXT имеет только строки:
/// Decode the TXT record as a string dictionary, or [:] if the data is malformed
public func dictionary(fromTXTRecord txtData: Data) -> [String: String] {
var result = [String: String]()
var data = txtData
while !data.isEmpty {
// The first byte of each record is its length, so prefix that much data
let recordLength = Int(data.removeFirst())
guard data.count >= recordLength else { return [:] }
let recordData = data[..<(data.startIndex + recordLength)]
data = data.dropFirst(recordLength)
guard let record = String(bytes: recordData, encoding: .utf8) else { return [:] }
// The format of the entry is "key=value"
// (According to the reference implementation, = is optional if there is no value,
// and any equals signs after the first are part of the value.)
// `ommittingEmptySubsequences` is necessary otherwise an empty string will crash the next line
let keyValue = record.split(separator: "=", maxSplits: 1, omittingEmptySubsequences: false)
let key = String(keyValue[0])
// If there's no value, make the value the empty string
switch keyValue.count {
case 1:
result[key] = ""
case 2:
result[key] = String(keyValue[1])
default:
fatalError()
}
}
return result
}
Я просто столкнулся с этим с помощью Swift 3. В моем случае проблема возникла только тогда, когда я использовал NetService.dictionary(fromTXTRecord:)
но не произошло, когда я переключился на Objective-C и позвонил NSNetService dictionaryFromTXTRecord:
, Когда вызов Objective C встречает запись без знака равенства, он создает ключ, содержащий данные, и помещает его в словарь с NSNull
значение. Из того, что я могу сказать, версия Swift затем перечисляет этот словарь и подбрасывает, когда видит NSNull
, Моим решением было добавить файл Objective-C и служебную функцию, которая вызывает dictionaryFromTXTRecord:
и очищает результаты, прежде чем передать их обратно в мой код Swift.
Я все еще надеюсь, что здесь чего-то не хватает, но в то же время я закончил проверку данных на правильность и только потом вызвал собственный метод Apple.
Вот мой обходной путь:
func dictionaryFromTXTRecordData(data: NSData) -> [String:NSData] {
let buffer = UnsafeBufferPointer<UInt8>(start: UnsafePointer(data.bytes), count: data.length)
var pos = 0
while pos < buffer.count {
let len = Int(buffer[pos])
if len > (buffer.count - pos + 1) {
return [:]
}
let subdata = data.subdataWithRange(NSRange(location: pos + 1, length: len))
guard let substring = String(data: subdata, encoding: NSUTF8StringEncoding) else {
return [:]
}
if !substring.containsString("=") {
return [:]
}
pos = pos + len + 1
}
return NSNetService.dictionaryFromTXTRecordData(data)
}
Я использую Swift 2 здесь. Все материалы приветствуются. Версии Swift 3, версии Objective-C, улучшения, исправления.