dictionary(fromTXTRecord:)
的输入来自网络,可能来自应用程序外部,甚至来自设备。但是,Apple的docs说:
...如果txtData不能表示为NSDictionary对象,则失败。
断言失败会使程序员(我)无法处理错误,这对处理外部数据的方法来说似乎不合逻辑。
如果我在Mac上的终端中运行它:
dns-sd -R 'My Service Name' _myservice._tcp local 4567 asdf asdf
我的应用程序,在iPhone上运行,崩溃。
dictionary(fromTXTRecord:)
期望TXT记录数据(asdf asdf
)为key=val
形式。如果像上面一样,一个单词不包含任何=
,那么该方法将无法解析它并使断言失败。
除了根本不使用该方法并实现我自己的解析之外,我认为没办法解决这个问题,这感觉不对。
我错过了什么吗?
答案 0 :(得分:2)
这是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
}
答案 1 :(得分:1)
我仍然希望我能在这里找到一些东西,但与此同时,我最终检查数据的正确性,然后才调用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版本,改进,更正。
答案 2 :(得分:1)
我刚刚使用Swift 3遇到过这个问题。在我的情况下,问题只发生在我使用NetService.dictionary(fromTXTRecord:)
但是当我切换到Objective-C并调用NSNetService dictionaryFromTXTRecord:
时没有发生。当Objective-C调用遇到没有等号的条目时,它会创建一个包含数据的键,并将其推送到具有NSNull
值的字典中。从我可以告诉Swift版本然后枚举该字典并在它看到NSNull
时抛出一个拟合。我的解决方案是添加一个Objective-C文件和一个调用dictionaryFromTXTRecord:
的实用程序函数,并在将它们交还给我的Swift代码之前清理结果。