代替案 #1:.pointee
のプロパティを使用UnsafePointer
以下のQ&Aに記載の通り
たとえば、Swift 2.2で使用できます
UnsafePointer<UInt16>(bytes).memory
UInt8
2 バイト配列をUInt16
値 (ホスト バイト オーダー)に変換します。
現在、Swift 3.0-dev.memory
は に置き換えられてい.pointee
ます。上記とこの変更を適用すると、同様に を使用して 4 バイト配列UnsafePointer<UInt32>(bytes).pointee
の表現にアクセスできますが、表現は変換にホストのバイト順を使用することに注意してください。可能であれば (必要に応じて) これを整数のビッグ エンディアン表現に変換するには、次の Q&A で説明されているように、各整数型で使用できるプロパティを使用できます。UInt32
UInt8
.bigEndian
これは Swift 3.0-dev でも有効であるため、getUInt32BE(...)
次のようにメソッドを構築できます。
extension Collection where Iterator.Element == UInt8 {
public func getUInt32BE(at: Index.Distance) -> UInt32? {
let from = startIndex.advanced(by: at, limit: endIndex)
let to = from.advanced(by: 4, limit: endIndex)
guard case let bytes = Array(self[from..<to])
where bytes.count == 4 else { return nil }
return UnsafePointer<UInt32>(bytes).pointee.bigEndian
}
}
代替案 #2: ビット シフトを使用する
または、次を使用するのではなく、ビットシフトを使用して上記の修正バージョンを使用します(質問の試みに似ています)UnsafePointer<..>
:
extension Collection where Iterator.Element == UInt8 {
public func getUInt32BE(at: Index.Distance) -> UInt32? {
let from = startIndex.advanced(by: at, limit: endIndex)
let to = from.advanced(by: 4, limit: endIndex)
guard case let bytesSlice = self[from..<to]
where from.distance(to: to) == 4 else { return nil }
return bytesSlice.reduce(0) { (tot, val) -> UInt32 in
tot << 8 + UInt32(val as! UInt8)
}
}
}
val
from Iterator.Element
to を強制的にキャストすることにより、コンパイラを支援する必要があることに注意してください(これは、拡張の句UInt8
により、成功することが保証されています; )。where
Iterator.Element == UInt8
使用例
上記の 2 つの選択肢のいずれかの使用例:
/* example usage */
let bytes: [UInt8] = [
0, // 0b 0000 0000
255, // 0b 1111 1111
0, // 0b 0000 0000
104, // 0b 0110 1000
76] // 0b 0100 1100
/* byteArr[1..<5], big-endian:
0b 1111 1111 0000 0000 0110 1000 0100 1100 */
let u32verify = 0b11111111000000000110100001001100
print(u32verify) // 4278216780
if let u32val = bytes.getUInt32BE(1) {
print(u32val) // 4278216780, OK
}
プロトコルの詳細についてはCollection
(上記のエラーの理由は、Index.Distance
このプロトコルの関連するタイプを使用してサブアレイを構築していないためです)、例を参照してください