gpt4 book ai didi

swift - 为什么我的数据初始化器没有产生预期的结果?

转载 作者:搜寻专家 更新时间:2023-11-01 05:34:33 25 4
gpt4 key购买 nike

我扩展了 swift 的数据类型,这样我就可以从字符串数组中初始化一个实例,然后恢复这些字符串。我有两个版本的初始值设定项;其中一个按预期工作,另一个不工作。我在这里寻求帮助以了解非工作版本的情况。这是扩展(其中我注释掉了一个或另一个初始化器,然后运行测试代码)

public extension Data {

var encoding: String.Encoding { return .utf8 }

// This version works
public init(with: [String]) {
let data = NSMutableData()
with.forEach {
data.append($0.data(using: String.Encoding.utf8)!)
data.append([0], length: 1)
}
self = data as Data
}

// This version does not work
public init(with: [String]) {
self.init()
with.forEach {
self.append($0.data(using: String.Encoding.utf8)!)
self.append(0)
}
}

public func toStringArray() -> [String] {
var decodedStrings = [String]()

var stringTerminatorPositions = [Int]()

var currentPosition = 0
self.enumerateBytes() {
buffer, count, stop in
print("Enumeration count = \(count)")
for i in 0 ..< count {
if buffer[i] == 0 {
stringTerminatorPositions.append(currentPosition)
}
currentPosition += 1
}
}

var stringStartPosition = 0
for stringTerminatorPosition in stringTerminatorPositions {
let encodedString = self.subdata(in: stringStartPosition ..< stringTerminatorPosition)
if let decodedString = String(data: encodedString, encoding: encoding) {
decodedStrings.append(decodedString)
}
stringStartPosition = stringTerminatorPosition + 1
}

return decodedStrings
}
}

测试代码如下:

    let strings = ["one", "two", "three", "four"]
let encoded = Data(with: strings)
let decoded = encoded.toStringArray()
print("\(encoded as NSData) => \(decoded)")

这是使用工作初始化程序时的输出:

Enumeration count = 19

<6f6e6500 74776f00 74687265 6500666f 757200> => ["one", "two", "three", "four"]

这是使用非工作初始化程序时的输出:

Enumeration count = 0

<6f6e6500 74776f00 74687265 6500666f 757200> => []

请注意以下事项:

  1. 在这两种情况下,编码字符串的打印输出是相同的
  2. 然而,toStringArray 方法中枚举计数的打印表明存在一些不同之处。

最佳答案

您的初始化程序没有任何问题 – 问题在于您对 enumerateBytes 的使用:

self.enumerateBytes() {
buffer, count, stop in

print("Enumeration count = \(count)")
for i in 0 ..< count {
if buffer[i] == 0 {
stringTerminatorPositions.append(currentPosition)
}
currentPosition += 1
}
}

您在这里所说的count 不是不是计数——它是给定区域起始字节的字节索引。事实上,当使用后备 NSData 存储时,它会为您提供字节区域的长度 is a bug (将在下一个 Swift 版本中修复)。

要获取字节区域的计数,您只需说 buffer.count – 或者假设 UnsafeBufferPointer 是一个 Sequence,你也可以说:

var currentPosition = 0
self.enumerateBytes { buffer, byteIndex, stop in

for byte in buffer {
if byte == 0 {
stringTerminatorPositions.append(currentPosition)
}
currentPosition += 1
}
}

或者更简单:

self.enumerateBytes { buffer, byteIndex, stop in

for (offset, byte) in buffer.enumerated() where byte == 0 {
stringTerminatorPositions.append(byteIndex + offset)
}
}

尽管 这个 实现目前不适用于 NSData 支持的 Data 实例,直到错误被修复,因为 byteIndex 会错误地给出区域的长度。

但是考虑到您在稍后的实现中调用 subdata(in:),它将把每个字符串的给定字节复制到一个新的缓冲区中——我真的看不出使用的优势enumerateBytes 在这里。您可以通过仅使用 withUnsafeBytes 来简化您的实现,以便为您提供对数据的连续 View :

public func cStringsToArray(encoding: String.Encoding = .utf8) -> [String] {

return withUnsafeBytes { (ptr: UnsafePointer<Int8>) in

var strings = [String]()
var previous = ptr

for offset in 0 ..< count {

let current = ptr + offset

if current != previous && current.pointee == 0 {
// if we cannot decode the string, append a unicode replacement character
// feel free to handle this another way.
strings.append(String(cString: previous, encoding: encoding) ?? "\u{FFFD}")
previous = current + 1
}
}

return strings
}
}

关于swift - 为什么我的数据初始化器没有产生预期的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43857866/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com