✂️

Data - 指定したサイズに分割し取得

2022/02/21に公開

敬意

Dataに指定した特定のバイナリデータを分割取得する必要があり
調べたところ、Objective-Cでの例は存在しましたが
Swiftでの記事がなかったため、こちらに残します。(Objective-Cをやったことある人からしたら、簡単に変換できるかと思いますが悪しからず。)

実装

extension Data {
    func splitData(size: Int) -> [Self] {
        
        var dataRange = NSRange(location: .zero, length: size)
        let dataSize = self.count
        let dataSplitCount = dataSize / size
        
        var dataArray: [Self] = []
        
        for _ in .zero ..< dataSplitCount {
            guard let range = Range(dataRange) else { return [] }
            dataArray.append(self.subdata(in: range))
            dataRange.location += size
        }
	let remainder = dataSize % size
        guard remainder != .zero else { return dataArray }
        
        dataRange.length = remainder
        guard let range = Range(dataRange) else { return [] }
        dataArray.append(self.subdata(in: range))
	
        return dataArray
    }
}

説明

var dataRange = NSRange(location: .zero, length: size)
let dataSize = self.count
let dataSplitCount = dataSize / size

1: まず、指定したサイズのNSRangeインスタンスを生成
2: 分割する元のDataSizeを指定
3: 2で指定したDataSize / 分割するSize

var dataArray: [Self] = []

for _ in .zero ..< dataSplitCount {
    guard let range = Range(dataRange) else { return [] }
    dataArray.append(self.subdata(in: range))
    dataRange.location += size
}

4: for文で、指定した分割Size分処理を実施
5: NSRangeインスタンスをRangeに変換
6: 指定した範囲のDataを配列に格納
7: 次の処理実施前に、範囲開始地点を変更する

let remainder = dataSize % size
guard remainder != .zero else { return dataArray }
        
dataRange.length = remainder
guard let range = Range(dataRange) else { return [] }
dataArray.append(self.subdata(in: range))

return dataArray

8: まず、剰余があるか確認し、ない場合は6で格納した配列を返却
9: 剰余がある場合は、配列の最後尾に追加し、配列を返却

※使用例

let datada = Data(bytes: [0x00, 0x01, 0x02, 0x10, 0x1B, 0xA1])
print(datada.splitData(size: 2)) // [2 bytes, 2 bytes, 2 bytes]

print(datada.splitData(size: 4)) // [4 bytes, 2 bytes]

参考

https://gist.github.com/hirokim/7750baf50b9726520b03

Discussion