【Swift】Data型の使い方!String型への変換方法とバイトの意味

【Swift】Data型の使い方!String型への変換方法とバイトの意味

この記事からわかること

  • SwiftDataとは?
  • Data型をString(文字列)型に変換する方法
  • バイト数取得するには?
  • Dataの一部をを取得するsubdata(in:)とは?
  • バイトやビットに安全にアクセスをするwithUnsafeBytesとは?

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

SwiftのData型とは?

Swiftのデータ型には文字列を表すString型や数値を表すInt型の他にData型というものがあります。これは連続したバイトの塊を表すための型になります。バイトとはコンピューターで扱うことのできる最小単位である「ビット(bit)」8個分をひとまとまりにした単位です。またバイトを表しやすくするために8進数や16進数がよく利用されます。

このようにData型は人間が読めるデータではなくコンピューターが識別しやすい状態のデータ(バイナリデータ)で値を保持しています。

Data型が実際によく使用されるのはファイルやクラウドからデータを取得・送信する際やBluetoothでデータのやり取りを行う時などです。SwiftでJSON形式でデータを扱うときなどにもData型は使用されます。

使い方

Data型をSwiftで使用する方法をまとめていきます。

インスタンスを生成

Data型はイニシャライザを使用して空のインスタンスを生成することが可能です。printなどで出力するとバイト数が表示されます。

let data = Data()
print(data)  // 0 bytes

バイト数を取得する

printした際は0 bytesのようにバイト数を確認することができますが、コード内でバイト数を取得したい場合はcountプロパティを参照します。

print(data.count)  // 0 

文字列からData型へ変換する

公式リファレンス:data(using:allowLossyConversion:)メソッド

func data(
    using encoding: String.Encoding,
    allowLossyConversion: Bool = false
) -> Data?

文字列(String型)をData型へ変換するにはdata(using:allowLossyConversion:)メソッドを使用します。変換は必ず成功するわけではなく、失敗した場合はnilが返ります(多分ほぼないですが)。引数usingにはUInt型で文字列エンコーディングを指定します。詳細はString.Encodingをご覧ください。

実際に文字列を変換する際には以下のように使用します。表示されるバイト数は一見文字数と一致しているように見えますが、これは必ずしも一致するわけではないので注意してください。UTF-8エンコーディングではASCII文字は1バイトで表現されますが、特殊文字や非ASCII文字は複数バイトで表現されることがあります。

let string = "Hello World!"

// 文字列からDataへの変換
if let data = string.data(using: .utf8) {
    print(data) // 12 bytes
}

ちなみに引数allowLossyConversion変換が成功しない場合の挙動を指定できます。初期値のfalseでは一部でも変換できない場合にnilを返しますが、trueにすると変換できない部分が一部であればそこが失われても変換を試みるようです。

Data型から文字列に変換する

公式リファレンス:String(data:, encoding:)

init?(
    data: Data,
    encoding: String.Encoding
)

Data型を文字列(String型)へ変換するにはString(data:, encoding:)イニシャライザを使用します。引数には対象のデータとエンコーディングを指定します。

let string = "Hello World!"

// 文字列からDataへの変換
if let data = string.data(using: .utf8) {
    print(data.count) // 12 bytes
    
    // Dataから文字列への変換
    if let decodedString = String(data: data, encoding: .utf8) {
        print(decodedString) // Hello World!
    }
}

Dataの一部を取得する:subdata(in:)

公式リファレンス:subdata(in:)メソッド

func subdata(in range: Range<Data.Index>) -> Data

Dataの一部のバイトを指定して取得するにはsubdata(in:)メソッドを使用します。引数inには取得したい範囲のバイトインデックスを指定します。例えば2バイト〜7バイトの範囲のみを取得するには以下のように記述します。

let string = "Hello World!"

if let data = string.data(using: .utf8) {
    let subdata = data.subdata(in: 2..<7)
    if let decodedString = String(data: subdata, encoding: .utf8) {
        print(decodedString) // llo W
    }
}

Data同士を連結する

Data型同士は+演算子を使用して連結することが可能です。

let string1 = "Hello"
let string2 = "World"

if let data1 = string1.data(using: .utf8),
   let data2 = string2.data(using: .utf8) {
    
    let data = data1 + data2
    if let decodedString = String(data: data, encoding: .utf8) {
        print(decodedString) // HelloWorld
    }
}

バイトやビットに安全にアクセス:withUnsafeBytes

公式リファレンス:withUnsafeBytesメソッド

func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R

Dataオブジェクト内のデータに安全にアクセスするためにはwithUnsafeBytesメソッドを使用します。以下のようにすることでアスキーコードを取得することが可能です。

if let data = "Hello World!".data(using: .utf8) {
    // withUnsafeBytesメソッドを使用してバイトデータにアクセス
    data.withUnsafeBytes { pointer in
        // バイトデータにアクセスする例
        for i in 0..<data.count {
            let byte = pointer[i]
            print("Byte \(i):ASCIIコード \(byte)")
        }
    }
}

出力結果は以下のようになります。

Byte 0ASCIIコード 72
Byte 1ASCIIコード 101
Byte 2ASCIIコード 108
Byte 3ASCIIコード 108
Byte 4ASCIIコード 111
Byte 5ASCIIコード 32
Byte 6ASCIIコード 87
Byte 7ASCIIコード 111
Byte 8ASCIIコード 114
Byte 9ASCIIコード 108
Byte 10ASCIIコード 100
Byte 11ASCIIコード 33

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article