【Swift】Data型の使い方!String型への変換方法とバイトの意味
この記事からわかること
- SwiftのData型とは?
- Data型をString(文字列)型に変換する方法
- バイト数を取得するには?
- Dataの一部をを取得するsubdata(in:)とは?
- バイトやビットに安全にアクセスをするwithUnsafeBytesとは?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Xcode:15.0.1
- iOS:17.0
- Swift:5.9
- macOS:Sonoma 14.1
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:)
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
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 0:ASCIIコード 72
Byte 1:ASCIIコード 101
Byte 2:ASCIIコード 108
Byte 3:ASCIIコード 108
Byte 4:ASCIIコード 111
Byte 5:ASCIIコード 32
Byte 6:ASCIIコード 87
Byte 7:ASCIIコード 111
Byte 8:ASCIIコード 114
Byte 9:ASCIIコード 108
Byte 10:ASCIIコード 100
Byte 11:ASCIIコード 33
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。