์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- ํด๋ฆฐ์ํคํ ์ณ
- deferred deeplink
- swift ์์ผํต์
- swift ๋ฐ์ดํธ ๋ฒํผ
- ๋ฅ๋งํฌ
- IOS์ฑ๊ฐ๋ฐ
- iOS ์ํคํ ์ณ
- ์์กด์ฑ ์ฃผ์
- 2024ํ๊ณ
- universal link
- SOCKET
- binary data to struct
- clean architecture
- swift bytebuffer
- ByteBuffer
- ์ ๋๋ฒ์ ๋งํฌ
- ์ฌ์ด๋ํ๋ก์ ํธ
- RxSwift
- ios binary data
- ์ฑ๊ฐ๋ฐ์
- Dependency Injection
- swift-nio
- ์ฑ์ถ์
- DeepLink
- swift ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ
- mvvm
- swift ์์ผ ๋ฐ์ดํฐ
- ํฌํธํด๋ฆฌ์ค
- ios๊ฐ๋ฐ
- SWIFT
- Today
- Total
hyunn
Binary Data๋ฅผ Swift ๊ตฌ์กฐ์ฒด๋ก ๋ณํํ๊ธฐ (feat. ByteBuffer, swift-nio) ๋ณธ๋ฌธ
Binary Data๋ฅผ Swift ๊ตฌ์กฐ์ฒด๋ก ๋ณํํ๊ธฐ (feat. ByteBuffer, swift-nio)
hyunn383 2024. 7. 27. 18:08๋ชฉ์ฐจ
๐ Binary Data๋ก ์๋ฒ์ ํต์ (feat. ์์ผ ํต์ )
๐ Byte Buffer๋?
๐ Swift์์ ByteBuffer๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ ์ฝ๊ธฐ (๊ธฐ๋ณธ ์๋ฃํ)
๐ ByteBuffer๋ฅผ ์ฌ์ฉํด์ Swift ๊ตฌ์กฐ์ฒด(Struct)๋ก ๋ณํํ๊ธฐ
๐ Binary Data๋ก ์๋ฒ์ ํต์ (feat. ์์ผ ํต์ )
์ต๊ทผ์ ์ฑํ ๊ธฐ๋ฅ์ ๊ฐ๋ฐํ๋ฉด์, ์์ผ(Socket) ํต์ ์ ๊ตฌํํ๊ฒ ๋์๋ค.
(์์ผ ํต์ ์ ๋ํด์๋ ์ฑํ ๊ธฐ๋ฅ ๊ฐ๋ฐ์ด ๋๋ ํ ํฌ์คํ ํ๋๋ก ํ๊ฒ ๋ค.)
์ด๋ฒ์ ์์ผ ํต์ ์ ๊ตฌํํ๋ฉด์, ํน์ด์ ์ ์๋ฒ์ ํต์ ํ ๋ ์ฃผ๊ณ ๋ฐ๋ ๋ฐ์ดํฐ ํ์์ด Binary Data์๋ค๋ ์ ์ด๋ค.
๋ฌผ๋ก , ์์ผ ํต์ ๋ json ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์๋ ๋๋ค.
ํ์ง๋ง, ์์ผ ํต์ ์ ๊ฒฝ์ฐ Binary Data๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋๊ฒ ๋ ์ ํฉํ๋ค๊ณ ํ๋ค.
์ด์ ๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์๊ฒ ์ง๋ง ๋๊ฐ์ง๋ง ์ ๊ฒ ๋ค.
1. ํจ์จ์ ์ธ ๋ฐ์ดํฐ ํฌ๊ธฐ
- ์ฐ์ json์ ๋ฌธ์์ด์ด๋ค. json ๋ฌธ์์ด์ ์ค์ ๋ก ์๋ฒ์ ์ ์ก๋ ๋๋ ๋ฐ์ดํธ๋ก ์ธ์ฝ๋ฉ ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ค์ data๋ง byte๋ก ๋ณด๋ด๋๊ฒ ๋ณด๋ค, key๊ฐ์ ํฌํจํ ๋ชจ๋ data ๋ฌธ์์ด์ byte๋ก ์ธ์ฝ๋ฉํ๋ฉด ์ฉ๋์ด ๋ ํด ์ ๋ฐ์ ์๋ค.
2. ๋ ๋น ๋ฅธ ์๋์ ์ฑ๋ฅ
- Binary data๋ ์ปดํจํฐ๊ฐ ์ง์ ์ฝ๊ณ ์ธ ์ ์๋ ์์ ํํ์ด๋ฏ๋ก, ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๋ ๋ฐ ๋ ๋น ๋ฅผ ์ ์๋ค.
- ๊ทธ์ ๋ฐํด, JSON ๋ฐ์ดํฐ๋ ๋ฌธ์์ด๋ก ํํ๋๊ธฐ ๋๋ฌธ์, ์ ์กํ๊ธฐ ์ ์ ๋ฌธ์์ด๋ก ๋ณํํ๊ฑฐ๋, ์์ ํ ๋ฌธ์์ด์ ํ์ฑํด์ผ ํ๋ค. ์ด ๊ณผ์ ์ ์ถ๊ฐ์ ์ธ CPU์ ๋ฉ๋ชจ๋ฆฌ ์์์ ์๋ชจํ๋ฉฐ, ์ ์ก ์๋๋ฅผ ์ ํ์ํฌ ์ ์๋ค.
๐ Byte Buffer๋?
Byte
๋ฐ์ดํธ(Byte)๋ ๋์งํธ ์ ๋ณด์ ๋จ์ ์ค ํ๋๋ก, 8๋นํธ๋ก ๊ตฌ์ฑ๋๋ค. ์ปดํจํฐ์ ์ ๋ณด ํต์ ๋ถ์ผ์์ ๋๋ฆฌ ์ฌ์ฉ๋๋ ๊ธฐ๋ณธ์ ์ธ ๋ฐ์ดํฐ ๋จ์๋ก, ๋ฌธ์, ์ซ์, ์ด๋ฏธ์ง, ์ฌ์ด๋ ๋ฑ์ ๋ค์ํ ์ข ๋ฅ์ ๋ฐ์ดํฐ๋ฅผ ํํํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
Buffer
๋ฒํผ(Buffer)๋ ๋ฐ์ดํฐ๋ฅผ ์์๋ก ์ ์ฅํ๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์๋ฏธํ๋ค. ๋ฒํผ๋ ์ฃผ๋ก ์๋ก ๋ค๋ฅธ ์๋๋ก ์๋ํ๋ ์์คํ ๊ตฌ์ฑ ์์ ๊ฐ์ ๋ฐ์ดํฐ ์ ์ก์ ์กฐ์ ํ๊ณ , ๋ฐ์ดํฐ๋ฅผ ์์ ์ ์ฅํ๊ฑฐ๋ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
ByteBuffer
ByteBuffer๋ Java์์ ์ ๊ณตํ๋ ํน์ ํด๋์ค์ด์ง๋ง, "๋ฐ์ดํธ ๋ฒํผ"๋ผ๋ ๊ฐ๋ ์์ฒด๋ Java์๋ง ๊ตญํ๋์ง ์๊ณ , ๋ค์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ์์คํ ์์ ์ฌ์ฉ๋๋ ์ผ๋ฐ์ ์ธ ๊ฐ๋ ์ด๋ค. ๋ฐ์ดํธ ๋ฒํผ๋ ๋ฐ์ดํธ ๋จ์์ ๋ฐ์ดํฐ๋ฅผ ์์๋ก ์ ์ฅํ๊ณ ์ฒ๋ฆฌํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์๋ฏธํ๋ค.
๐ Swift์์ ByteBuffer๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ ์ฝ๊ธฐ (๊ธฐ๋ณธ ์๋ฃํ)
์ฐ์ , ByteBuffer ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด Swift-nio ๋ผ๋ ํจํค์ง๋ฅผ ์ค์นํด์ค์ผํ๋ค.
(cocoapods๋ฅผ ์ง์ ์ํ๋, spm์ผ๋ก ์ค์นํด์ผํ๋ค.)
https://github.com/apple/swift-nio
swift-nio๋ ์ ๋ง ๋ฐฉ๋ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. ์ ๋ง ๋ง์๊ฑธ ์ง์ํ์ง๋ง, ByteBuffer๋ฅผ ์ฝ๊ณ ์ธ ์ ์๋ ๊ธฐ๋ฅ๋ง ์ฌ์ฉํ์๋ค.
import NIO
// MARK: - ์๋ฒ์์ ์๋ต ๋ฐ์ ๋ฐ์ดํฐ
// WebSocket์ผ๋ก data๋ฅผ receiveํ ๋ ๋ฐ์ดํฐ ํ์
์ Data ํ์
์ผ๋ก ๋ค์ด์จ๋ค.
let data: Data
// MARK: - Data to byteBuffer
// ByteBuffer๋ SwiftNIO ํจํค์ง์์ ์ ๊ณตํด์ฃผ๋ ๊ฐ์ฒด์ด๋ค.
var byteBuffer: ByteBuffer = ByteBuffer(data: data)
// MARK - ๋ฐ์ดํธ ๋ฒํผ ์ฝ๊ธฐ
// ๋ฐ์ดํธ ๋ฒํผ๋ฅผ ์์์๋ถํฐ ์ฝ๊ฒ ๋๋ค.
// ๋ฐ์ดํธ ๋ฒํผ์ ์ฒซ ๋ฐ์ดํฐ๋ก Integer๊ฐ ๋ค์ด์จ๋ค๊ณ ๊ฐ์ ํ๊ณ , ์ฐ์ Integer๋ฅผ ์ฝ์ด๋ณด์.
// MARK: - byteBuffer to INT32 - Mid-Little
let int32 = byteBuffer.readInteger(endianness: .little, as: Int32.self)
// Int๋ก ๋ฐ๊พธ๊ธฐ
let int = Int(int32!)
// MARK: - ๋ค์ ๋ฐ์ดํธ ๋ฒํผ ์ฝ๊ธฐ
// ๋ฐ์ดํธ ๋ฒํผ๋ฅผ ๋ ์ฝ๊ฒ ๋๋ฉด ์์ ์ฝ์ Integer ๋ค์ ๋ถ๋ถ๋ถํฐ ์ฝ๊ฒ ๋๋ค.
// ๋ค์ ๋ฐ์ดํฐ๋ String์ด ๋ค์ด์จ๋ค๊ณ ๊ฐ์ ํ๊ณ , String์ ์ฝ์ด๋ณด์.
// MARK: - String์ ์ฝ์ผ๋ ค๋ฉด ์ฐ์ String์ ๊ธธ์ด์ธ Integer๋ถํฐ ์ฝ์ด์ผํ๋ค.
let strLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
// MARK: - byteBuffer to Ascii
let str = byteBuffer.readString(length: Int(strLength!), encoding: .ascii)
// MARK: - ํ๊ธ๋ ์ฝ์๊ฑฐ๋ฉด utf8๋ก ์ธ์ฝ๋ฉํ๊ธฐ
let str = byteBuffer.readString(length: Int(strLength!), encoding: .utf8)
๐ ์ฌ๊ธฐ์ ์ ๊น! readInteger() ์ endianness์ as ์์ฑ์ ๋ญ๊น?
์ด๊ฑฐ.. ์ค์ํ๊ฑฐ๋ค!
์๋ํ๋ฉด ์ด ์์ฑ์ ์ด๋ป๊ฒ ์ค์ ํ๋์ง์ ๋ฐ๋ผ ๋ค๋ฅธ ๋ฐ์ดํฐ๊ฐ ์ถ๋ ฅ๋๋ค...
Endianness - ๋ฐ์ดํธ ์์
์๋์ ์์ฑ์ ๋ฉ๋ชจ๋ฆฌ ๋ด์์ ๋ฐ์ดํฐ์ ๋ฐ์ดํธ๊ฐ ์ด๋ป๊ฒ ๋ฐฐ์ด๋๋์ง๋ฅผ ์ ์ํ๋ค.
1. ๋น ์๋์ (Big-endian):
๊ฐ์ฅ ์ค์ํ ๋ฐ์ดํธ(๊ฐ์ฅ ๋์ ๋ฐ์ดํธ)๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ๋ฎ์ ์ฃผ์์ ์ ์ฅ๋๋ค. ์ฆ, ๋ฐ์ดํฐ์ ์ฒซ ๋ฒ์งธ ๋ฐ์ดํธ๊ฐ ๊ฐ์ฅ ๋จผ์ ์ ์ฅ๋๋ค.
2. ๋ฆฌํ ์๋์ (Little-endian):
๊ฐ์ฅ ์ค์ํ ๋ฐ์ดํธ๊ฐ ๋ฉ๋ชจ๋ฆฌ์ ๋์ ์ฃผ์์ ์ ์ฅ๋๋ค. ์ฆ, ๋ฐ์ดํฐ์ ๋ง์ง๋ง ๋ฐ์ดํธ๊ฐ ๊ฐ์ฅ ๋จผ์ ์ ์ฅ๋๋ค.
As - ํ๋ณํ
As ์์ฑ์ readInteger() ๋ฉ์๋๊ฐ ์ฝ์ ๋ฐ์ดํฐ๋ฅผ ํน์ ํ์์ผ๋ก ๋ณํํ ๋ ์ฌ์ฉ๋๋ค. ๋ฐ์ดํฐ๊ฐ ์ฝํ ๋, ์ด๋ป๊ฒ ํด์๋ ์ง๋ฅผ ๊ฒฐ์ ํ ์ ์๋ ์ต์ ์ด๋ค.
๋ด๊ฐ ์๋ต๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ด๋ค ์์ฑ์ผ๋ก ๋ณํํด์ผ๋ ์ง ๋ชจ๋ฅธ๋ค๋ฉด, (๋๋ ์๋ ค์ฃผ๋ ์ฌ๋์ด ์์ด์ ๋ชฐ๋๋ค...)
์๋ต ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์์์ ์ฐ์ด๋ณด๊ณ , ์ฐํ ๋ฐ์ดํฐ๋ฅผ ์ปจ๋ฒํฐ์์ ๋๋ ค๋ณด๊ณ ๋ง๋ ์์ฑ์ ์ฐพ๋๋ค!!
https://www.scadacore.com/tools/programming-calculators/online-hex-converter/
๋ด๊ฐ ์ฌ์ฉํ ์ปจ๋ฒํฐ์ด๋ค.
์ Hex Converter๋๊ณ ? Hex String์ Binary Data๋ฅผ ์ฌ๋์ด ๋ณด๊ธฐ ์ข๊ฒ ๋ณํํ ๊ฒ์ด๋ค.
๋๋ ์๋ต์ผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์์ ์ฐ์ผ๋ฉด [01 00 00 00] ์ด ๋์๋ค.
์ด๊ฑด binary data๋ฅผ ์ฌ๋์ด ๋ณด๊ธฐ ์ข๊ฒ ๋ณํํด๋์ Hex String์ด์๊ณ , ๋ฐ๋ผ์ Hex String Converter ๋ฅผ ์ฌ์ฉํ์๋ค.
๋๋ ๋ณํํ์๋ ๊ฐ์ด 1์ด์ฌ์ผ ํ๋ค.
1์ ์ฐพ์๋ณด๋ฉด, Int32 - Little Endian (DCBA) ์ UINT16 - Little Endian (BA) ๊ฐ ์๋ค.
์ด์ค์์ ๋๋ Int32 - Little Endian์ผ๋ก ๋ณํํ๊ณ , ๋ฐ์ดํฐ๋ฅผ ์ ์ฝ์ด์ฌ ์ ์์๋ค.
let int32 = byteBuffer.readInteger(endianness: .little, as: Int32.self)
๐ ByteBuffer๋ฅผ ์ฌ์ฉํด์ Swift ๊ตฌ์กฐ์ฒด(Struct)๋ก ๋ณํํ๊ธฐ
struct BaseResponse<T> {
var res: Int?
var code: Int?
var data: T?
}
struct ChattingRooms {
var chattingRooms: [ChattingRoom]?
}
struct ChattingRoom {
var id: String?
var name: String?
var groupId: String?
var channelId: String?
var imageUrl: String?
var lastChat: String?
var lastChatTimeStamp: Int?
var unreadMessageCount: Int?
}
์๋ต๋ฐ์ Binary Data๋ฅผ Swift๋ก ์ฝ๊ธฐ ํธํ๊ฒ ์์ ๊ฐ์ ๊ตฌ์กฐ์ฒด(Struct)๋ก ๋ณํํด๋ณด์!
let res = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let code = byteBuffer.readInteger(endianness: .little, as: Int32.self)
// MARK: - data๋ object Array๋ก ๋ค์ด์ค๊ธฐ ๋๋ฌธ์ ์ฐ์ , length๋ถํฐ ๊ตฌํ๋ค.
let objectArrayLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
var data: [ChattingRoom] = []
// MARK: - ๋ฐฐ์ด ๊ธธ์ด๋งํผ object๋ฅผ ์ฝ๋๋ค.
if let objectArrayLength = objectArrayLength {
for _ in 0..<objectArrayLength {
if let object = readObject(byteBuffer: byteBuffer) {
data.append(object)
}
}
}
// MARK: - ์ต์ข
๊ตฌ์กฐ์ฒด(Struct)
let response: BaseResponse<ChattingRooms> = BaseResponse(res: Int(res!), code: Int(code!), data: ChattingRooms(chattingRooms: data))
print(response)
// MARK: - object๋ฅผ ์ฝ์ด ChattingRoom ๊ตฌ์กฐ์ฒด๋ก ๋ณํ
private func readObject(byteBuffer: ByteBuffer) -> ChattingRoom {
var byteBuffer = byteBuffer
let idLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let id = byteBuffer.readString(length: Int(idLength!), encoding: .ascii)
let nameLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let name = byteBuffer.readString(length: Int(nameLength!), encoding: .utf8)
let groupIdLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let groupId = byteBuffer.readString(length: Int(groupIdLength!), encoding: .ascii)
let channelIdLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let channelId = byteBuffer.readString(length: Int(channelIdLength!), encoding: .ascii)
let imageUrlLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let imageUrl = byteBuffer.readString(length: Int(imageUrlLength!), encoding: .ascii)
let lastChatLength = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let lastChat = byteBuffer.readString(length: Int(lastChatLength!), encoding: .utf8)
let lastChatTimeStamp = byteBuffer.readInteger(endianness: .little, as: Int32.self)
let unreadMessageCount = byteBuffer.readInteger(endianness: .little, as: Int32.self)
return ChattingRoom(id: id, name: name, groupId: groupId, channelId: channelId, imageUrl: imageUrl, lastChat: lastChat, lastChatTimeStamp: Int(lastChatTimeStamp!), unreadMessageCount: Int(unreadMessageCount!))
}