Data.subdatain :)结果为EXC_BAD_INSTRUCTION

问题描述

尝试检索Data对象的子数据时,应用程序崩溃并发出以下错误

线程1:EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 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,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,5]\n"

要在尝试删除数据索引之前检查其数据索引是否包含特定范围,可以使用模式匹配运算符:

var data = Data([0,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上实现自己的模式匹配运算符:

extension Range {
    static func ~=(lhs: Self,rhs: ClosedRange<Bound>) -> Bool {
        lhs.contains(rhs.lowerBound) && lhs.contains(rhs.upperBound)
    }
}

用法:

var data = Data([0,5])
let range = 0...5
if data.indices ~= range {
    let subdata = data.remove(range)
    print(Array(data),5]\n"
} else {
    print("invalid subrange")
}
,

该错误是由removeFirst函数引起的。该文档明确指出:

调用此方法可能会使此集合的所有保存索引无效。在使用任何可以更改其长度的操作更改集合后,请勿依赖先前存储的索引值。

似乎正是导致我的错误的原因。我已将removeFirst替换为remove(at:),现在可以使用了。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...