Data.subdata(in:) 结果为 EXC_BAD_INSTRUCTION
Data.subdata(in:) results in EXC_BAD_INSTRUCTION
在尝试检索 Data
对象的子数据时,应用程序崩溃并发出以下错误:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
下面是代码。这是一个 Data
扩展。希望有人能解释为什么会崩溃。
public extension Data {
/// Removes and returns the range of data at the specified position.
/// - Parameter range: The range to remove. `range` must be valid
/// for the collection and should not exceed the collection's end index.
/// - Returns: The removed data.
mutating func remove(at range: Range<Data.Index>) -> Self {
precondition(range.lowerBound >= 0, "Range invalid, lower bound cannot be below 0")
precondition(range.upperBound < self.count, "Range invalid, upper bound exceeds data size")
let removal = subdata(in: range) // <- Error occurs here
removeSubrange(range)
return removal
}
}
编辑 - 添加调用函数:
此扩展是从以下函数调用的:
func temporary(data: inout Data) -> Data {
let _ = data.removeFirst()
return data.remove(range: 0 ..< 3)
}
依次调用如下:
var data = Data([0,1,2,3,4,5])
let subdata = temporary(data: &data)
您没有提供足够的信息让我们知道崩溃的原因。我知道你的方法有问题的一件事是你的先决条件。您将无法通过范围来删除集合中的所有元素。除此之外,您应该实现一个通用方法,该方法采用 RangeExpression 而不是 Range。这就是我实现这种方法的方式:
extension Data {
/// Removes and returns the range of data at the specified position.
/// - Parameter range: The range to remove. `range` must be valid
/// for the collection and should not exceed the collection's end index.
/// - Returns: The removed data.
mutating func remove<R>(_ range: R) -> Data where R: RangeExpression, Index == R.Bound {
defer { removeSubrange(range) }
return subdata(in: range.relative(to: self))
}
}
用法:
var data = Data([0,1,2,3,4,5])
let subdata = data.remove(0..<6)
print(Array(data), Array(subdata)) // "[] [0, 1, 2, 3, 4, 5]\n"
要在尝试删除之前检查您的数据索引是否包含特定范围,您可以使用 pattern-matching 运算符:
var data = Data([0,1,2,3,4,5])
let range = 0..<7
if data.indices ~= range {
let subdata = data.remove(range)
print(Array(data), Array(subdata))
} else {
print("invalid subrange") // "invalid subrange\n"
}
如果你想对 ClosedRange 做同样的事情,你需要在 Range:
上实现你自己的 pattern-matching 运算符
extension Range {
static func ~=(lhs: Self, rhs: ClosedRange<Bound>) -> Bool {
lhs.contains(rhs.lowerBound) && lhs.contains(rhs.upperBound)
}
}
用法:
var data = Data([0,1,2,3,4,5])
let range = 0...5
if data.indices ~= range {
let subdata = data.remove(range)
print(Array(data), Array(subdata)) // "[] [0, 1, 2, 3, 4, 5]\n"
} else {
print("invalid subrange")
}
错误是由removeFirst
函数引起的。文档明确指出:
Calling this method may invalidate all saved indices of this collection. Do not rely on a previously stored index value after altering a collection with any operation that can change its length.
看来这正是导致我出错的原因。我已将 removeFirst
替换为 remove(at:)
,现在可以使用了。
在尝试检索 Data
对象的子数据时,应用程序崩溃并发出以下错误:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
下面是代码。这是一个 Data
扩展。希望有人能解释为什么会崩溃。
public extension Data {
/// Removes and returns the range of data at the specified position.
/// - Parameter range: The range to remove. `range` must be valid
/// for the collection and should not exceed the collection's end index.
/// - Returns: The removed data.
mutating func remove(at range: Range<Data.Index>) -> Self {
precondition(range.lowerBound >= 0, "Range invalid, lower bound cannot be below 0")
precondition(range.upperBound < self.count, "Range invalid, upper bound exceeds data size")
let removal = subdata(in: range) // <- Error occurs here
removeSubrange(range)
return removal
}
}
编辑 - 添加调用函数:
此扩展是从以下函数调用的:
func temporary(data: inout Data) -> Data {
let _ = data.removeFirst()
return data.remove(range: 0 ..< 3)
}
依次调用如下:
var data = Data([0,1,2,3,4,5])
let subdata = temporary(data: &data)
您没有提供足够的信息让我们知道崩溃的原因。我知道你的方法有问题的一件事是你的先决条件。您将无法通过范围来删除集合中的所有元素。除此之外,您应该实现一个通用方法,该方法采用 RangeExpression 而不是 Range。这就是我实现这种方法的方式:
extension Data {
/// Removes and returns the range of data at the specified position.
/// - Parameter range: The range to remove. `range` must be valid
/// for the collection and should not exceed the collection's end index.
/// - Returns: The removed data.
mutating func remove<R>(_ range: R) -> Data where R: RangeExpression, Index == R.Bound {
defer { removeSubrange(range) }
return subdata(in: range.relative(to: self))
}
}
用法:
var data = Data([0,1,2,3,4,5])
let subdata = data.remove(0..<6)
print(Array(data), Array(subdata)) // "[] [0, 1, 2, 3, 4, 5]\n"
要在尝试删除之前检查您的数据索引是否包含特定范围,您可以使用 pattern-matching 运算符:
var data = Data([0,1,2,3,4,5])
let range = 0..<7
if data.indices ~= range {
let subdata = data.remove(range)
print(Array(data), Array(subdata))
} else {
print("invalid subrange") // "invalid subrange\n"
}
如果你想对 ClosedRange 做同样的事情,你需要在 Range:
上实现你自己的 pattern-matching 运算符extension Range {
static func ~=(lhs: Self, rhs: ClosedRange<Bound>) -> Bool {
lhs.contains(rhs.lowerBound) && lhs.contains(rhs.upperBound)
}
}
用法:
var data = Data([0,1,2,3,4,5])
let range = 0...5
if data.indices ~= range {
let subdata = data.remove(range)
print(Array(data), Array(subdata)) // "[] [0, 1, 2, 3, 4, 5]\n"
} else {
print("invalid subrange")
}
错误是由removeFirst
函数引起的。文档明确指出:
Calling this method may invalidate all saved indices of this collection. Do not rely on a previously stored index value after altering a collection with any operation that can change its length.
看来这正是导致我出错的原因。我已将 removeFirst
替换为 remove(at:)
,现在可以使用了。