NSData转为Data Swift 3。

7
var dataFile: NSData = NSMutableData.init(data: wav.subdataWithRange(NSRange.init(location: currentByte, length: wavDataSize)))

如何将这段代码转换为使用 Swift 3 中的 Data?或者如何将 NSRange 解析为 Range


请查看此链接:https://developer.apple.com/reference/foundation/data - Janmenjaya
3个回答

11

Data分成较小的Data实例

假设

这个答案是 Swift 3 和 4 版本中与问题代码等效的。它将产生相同的结果dataFile,假设输入值相同: wav, currentBytewavDataSize,假设周围的代码没有更改。

我并不假设变量wavdataFilecurrentBytewavDataSize的含义。为了避免变量名暗示未在问题中声明的东西,我将使用以下名称: sourceDatasubdatarangeStartBytesubdataLength。我假设(未在问题中显示)周围的代码将确保rangeStartBytesubdataLength处于有效范围内,以避免错误。

 

将NSRange转换为Range<Int>

问题中的 Swift 2 实现使用由起点和长度定义的NSRange,如下所示:

NSRange.init(location: rangeStartByte, length: subdataLength)

我提出的 Swift 3 & 4 实现方式创建了一个等价的 Range<Int>,由起始点和结束点定义如下:

rangeStartByte ..< (rangeStartByte + subdataLength)

我将一个使用类似代码分块上传照片的Swift 2.2应用程序转换成了Swift 3。在转换过程中,我们忽略了这个细节,使用了Swift 2实现的长度来代替Swift 3和4实现的终点。这导致了一个难以解决的缺陷。第一次迭代成功了,但后续迭代失败了。

另一个答案描述了我刚才所描述问题的解决方案。它使用Swift 2范围的subdataLength作为Swift 3和4范围的终点。在当前字节为0且subdataLength小于NSData实例的长度的特殊情况下,这将产生相同的结果(这就是为什么在我描述的问题中第一次迭代成功的原因)。这个假设没有在问题中明确说明,并且为其他人提供了一个不太灵活的解决方案。

 

Swift 3和4的等效版本

var subdata = sourceData.subdata(in: rangeStartByte ..< (rangeStartByte + subdataLength))

Swift 2.2

(问题中的代码,使用更新后的变量名称)

var subdata: NSData = NSMutableData.init(data: sourceData.subdataWithRange(NSRange.init(location: rangeStartByte, length: subdataLength)))

 

可运行示例代码

我在代码演示环境中提供了可以运行的示例代码,演示了如何使用这行代码将一个Data实例分成更小的Data实例。源Data实例是从字符串"ABCDEFGHIJKL"创建的。该实例被分割成长度为5的更小的Data实例。

Swift 3 & 4的上下文

import UIKit

var sourceString = "ABCDEFGHIJKL"
let sourceData = sourceString.data(using: String.Encoding.utf8)!  // sourceData is equivalent to "wav" from question

var rangeStartByte = 0  // rangeStartByte is equivalent to "currentByte" from question
let maxSubdataLength = 5
let dataLength = sourceString.lengthOfBytes(using: String.Encoding.utf8)
precondition(maxSubdataLength <= dataLength, "maxSubdataLength must be <= to dataLength")

while rangeStartByte < dataLength {
    // subdataLength is equivalent to "wavDataSize" from question
    let subdataLength = min(maxSubdataLength, dataLength - rangeStartByte)

    // subdata is equivalent to "dataFile" from question
    let subdata = Data(sourceData.subdata(in: rangeStartByte ..< (rangeStartByte + subdataLength)))

    let subdataString = String(data: subdata, encoding: String.Encoding.utf8) ?? ""
    print("'\(subdataString)'")
    rangeStartByte += subdataLength
}

结果是:

'ABCDE'
'FGHIJ'
'KL'

附上背景的Swift 2.2

import UIKit

var sourceString = "ABCDEFGHIJKL"
let sourceData = sourceString.dataUsingEncoding(NSUTF8StringEncoding)!  // sourceData is equivalent to "wav" from question

var rangeStartByte = 0  // rangeStartByte is equivalent to "currentByte" from question
let maxSubdataLength = 5
let dataLength = sourceString.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)
precondition(maxSubdataLength <= dataLength, "maxSubdataLength must be <= to dataLength")

while rangeStartByte < dataLength {
    // subdataLength is equivalent to "wavDataSize" from question
    let subdataLength = min(maxSubdataLength, dataLength - rangeStartByte)

    // subdata is equivalent to "dataFile" from question
    let subdata: NSData = NSMutableData.init(data: sourceData.subdataWithRange(NSRange.init(location: rangeStartByte, length: subdataLength)))

    let subdataString = String(data: subdata, encoding: NSUTF8StringEncoding) ?? ""
    print("'\(subdataString)'")
    rangeStartByte += subdataLength
}

结果为:

'ABCDE'
'FGHIJ'
'KL'

使用NSRange的Swift 3和4

pedrouan的回答如下所示:

var subdata: Data = Data(sourceData.subdata(with: NSRange(location: rangeStartByte, length: subdataLength)))

最初我无法使其编译,因此我忽略了它。现在我意识到,如果将sourceData声明或转换为NSData而不是Data,它就可以工作。

如果您想在上面的“Swift 3&4 with context”示例代码中运行此方法,请使用此代码替换该示例中相应的代码:

// subdata is equivalent to "dataFile" from question
let sourceNSData = sourceData as NSData
let subdata = sourceNSData.subdata(with: NSRange(location: rangeStartByte, length: subdataLength))

我尽可能地避免使用"NS"类,比如NSRange,所以我更喜欢使用Swift Range的解决方案。


你的代码崩溃了,出现了以下错误:*** Terminating app due to uncaught exception 'NSRangeException',这是由于范围超过了数据长度所致。 - Max Potapov
@MaxPotapov,我的答案中的代码在给定相同的源数据、currentByte和wavDataSize的情况下产生与问题中的代码相同的结果。这包括超出范围的错误。我认为我们对问题有不同的假设。我更新了我的答案以包括我的假设。我认为我的答案是有效的,并且将对许多遇到我遇到的相同情况的开发人员有所帮助。你的答案也会根据输入而崩溃,但它会在与问题中的代码不同的输入组合上崩溃。它是不等价的。 - Mobile Dan

2

Swift 3.0中的一些“小”变化

var dataFile: Data = Data(wav.subdata(with: NSRange(location: currentByte, length: wavDataSize)))

1
在 Swift 3 中,您的代码将像这样:


var dataFile = sourceData.subdata(in: currentByte..<currentByte+wavDataSize)

在 Playground 中检查了你的链接并出现了异常。请查看我的回答中的评论。 - Max Potapov
这个答案并不等同于问题中的代码对于所有currentByte和wavDataSize的组合。只有当currentByte为0且wavDataSize<=源数据长度时才是等效的。这不是一个声明过的假设。你指出我的答案在你没有预料到的情况下崩溃了。这很可能是因为问题之外的假设。我更新了我的答案以反映我的假设。它对于所有currentByte和wavDataSize的组合都等同于问题代码,包括由于越界错误而导致崩溃的情况。如果我错了,请纠正我。谢谢。 - Mobile Dan
@Peacemoon,我认��你和我对问题的解释方式更通用。请看我回答中添加的解释。谢谢。 - Mobile Dan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接