안전하지 않은 버퍼 포인터
연속된 메모리를 효율적으로 처리합니다.
안전하지 않은 버퍼 포인터은(는) CoddyKit의 무료 Swift Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Swift Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
버퍼 포인터란 무엇인가
하나의 형식 지정 포인터는 한 번에 하나의 요소를 가리킵니다. UnsafeBufferPointer<T>는 시작 포인터와 개수를 감싸며, Collection을 따르는 연속된 메모리 블록을 제한된 범위로 볼 수 있게 합니다.
따라서 원시 메모리에서도 익숙한 컬렉션 인터페이스를 사용해 순회하고, 첨자로 접근하고, 매핑하고, reduce를 수행할 수 있습니다.
// A buffer pointer = base address + element count
// UnsafeBufferPointer<Int>(start: ptr, count: 5)읽기 전용 버퍼와 변경 가능한 버퍼
단일 포인터와 마찬가지로 버퍼도 두 가지 형태가 있습니다. 읽기 전용 순회에는 UnsafeBufferPointer<T>를 사용하고, 요소를 대입해야 할 때는 UnsafeMutableBufferPointer<T>를 사용합니다.
let p = UnsafeMutablePointer<Int>.allocate(capacity: 4)
p.initialize(repeating: 0, count: 4)
let buf = UnsafeMutableBufferPointer(start: p, count: 4)
buf[0] = 11
print(buf[0]) // 11컬렉션처럼 순회하기
버퍼 포인터는 Collection이므로 for 반복문으로 모든 요소를 순서대로 순회할 수 있습니다. 수동으로 인덱스를 계산할 필요도 없고 반복문 자체에서 하나 더 세거나 덜 세는 오류가 발생할 위험도 없습니다. 다만 지정한 범위는 여전히 직접 책임져야 합니다.
let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 3)
_ = buf.initialize(from: [10, 20, 30])
for value in buf { print(value) } // 10, 20, 30컬렉션 알고리즘을 자유롭게 사용하기
map, filter, reduce, enumerated, indices는 모두 버퍼 포인터에서 작동합니다. 따라서 할당을 발생시키지 않으면서도 고수준 코드로 원시 메모리를 처리할 수 있습니다.
let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 4)
_ = buf.initialize(from: [1, 2, 3, 4])
let total = buf.reduce(0, +) // 10
let evens = buf.filter { $0 % 2 == 0 } // [2, 4]
print(total, evens)변경 가능한 버퍼 할당하기
UnsafeMutableBufferPointer<T>.allocate(capacity:)는 메모리 블록을 예약하고 한 단계로 버퍼를 반환합니다. 그래도 읽기 전에 initialize해야 하며, 작업이 끝나면 deallocate해야 합니다.
let buf = UnsafeMutableBufferPointer<Int>.allocate(capacity: 5)
buf.initialize(repeating: 0)
defer {
buf.deinitialize()
buf.deallocate()
}경계가 자동으로 검사되지는 않습니다
0..<count 안에서 첨자로 접근하는 것은 안전합니다. 하지만 버퍼는 제공한 개수가 올바른지 알 수 없습니다. 실제 할당보다 큰 개수로 버퍼를 만들면 읽기가 끝을 넘어 정의되지 않은 메모리 영역으로 진행됩니다.
개수는 항상 직접 만든 동일한 할당에서 계산하십시오.
let p = UnsafeMutablePointer<Int>.allocate(capacity: 3)
p.initialize(repeating: 0, count: 3)
// CORRECT: count matches capacity
let good = UnsafeBufferPointer(start: p, count: 3)
// WRONG: count: 10 would read past the block
print(good.count)빈 버퍼
count: 0인 버퍼도 유효하며 nil인 기준 주소를 가질 수 있습니다. 항상 isEmpty를 확인하거나 반복문이 실행되지 않는다는 점을 이용하고, baseAddress를 강제로 언래핑하지 마십시오.
let empty = UnsafeBufferPointer<Int>(start: nil, count: 0)
print(empty.isEmpty) // true
print(empty.count) // 0
for _ in empty { print("never runs") }배열에서 withUnsafeBufferPointer 사용하기
버퍼를 얻는 가장 안전한 방법은 기존 Array에서 withUnsafeBufferPointer를 사용하는 것입니다. 스위프트는 저장 공간이 연속되어 있고 클로저가 실행되는 동안 유효하다는 것을 보장하므로, 수동으로 할당할 필요가 전혀 없습니다.
let numbers = [4, 8, 15, 16, 23]
let maxValue = numbers.withUnsafeBufferPointer { buf -> Int in
var m = buf[0]
for v in buf where v > m { m = v }
return m
}
print(maxValue) // 23배열 저장 공간 변경하기
withUnsafeMutableBufferPointer를 사용하면 배열의 저장 공간에 직접 쓸 수 있습니다. 이는 ARC와 경계 검사가 추가하는 오버헤드를 줄여야 하는 성능 중심의 제자리 변환에서 가끔 사용됩니다.
var data = [1, 2, 3, 4]
data.withUnsafeMutableBufferPointer { buf in
for i in buf.indices { buf[i] *= 10 }
}
print(data) // [10, 20, 30, 40]C 인터페이스에 baseAddress 사용하기
포인터와 길이를 받는 C 함수를 호출할 때는 buffer.baseAddress와 buffer.count를 전달하십시오. 기준 주소는 빈 버퍼에서만 nil이 되므로 해당 경우를 처리해야 합니다.
let bytes: [UInt8] = [0xDE, 0xAD, 0xBE, 0xEF]
bytes.withUnsafeBufferPointer { buf in
if let base = buf.baseAddress {
// c_function(base, buf.count)
print("start:", base, "len:", buf.count)
}
}버퍼 포인터를 사용해야 하는 경우
메모리 영역에 연속적이고 형식 안전한 컬렉션 방식으로 접근해야 할 때 버퍼 포인터를 사용하십시오. 예를 들어 C 배열을 연결하거나, 이진 형식을 분석하거나, 자주 실행되는 반복문에서 오버헤드를 줄일 때 유용합니다. 가능하면 수동 할당보다 with... 클로저 형식을 우선하십시오.
// Counting set bits across a byte buffer
let data: [UInt8] = [0b1011, 0b0110, 0b1111]
let bits = data.withUnsafeBufferPointer { buf in
buf.reduce(0) { $0 + $1.nonzeroBitCount }
}
print(bits) // 3 + 2 + 4 = 9빠른 확인
버퍼 포인터가 단일 포인터에 무엇을 더해 주는지 떠올려 보십시오.
복습
버퍼 포인터는 연속된 영역을 범위가 제한된 컬렉션으로 감쌉니다.
UnsafeBufferPointer/UnsafeMutableBufferPointer= 기준 주소 + 개수입니다.- 원시 메모리에서
map,filter,reduce와for반복을 사용할 수 있습니다. - 스위프트가 유효성과 수명을 관리하도록 배열에서는
withUnsafeBufferPointer를 우선 사용하십시오. - 제공한 개수는 신뢰되므로 실제 할당에서 계산해야 합니다.
자주 묻는 질문
“안전하지 않은 버퍼 포인터” 강의는 무료인가요?
네 — “안전하지 않은 버퍼 포인터” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Swift Academy 강의 전체를 잠금 해제할 수 있습니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“안전하지 않은 버퍼 포인터”에서 뭘 배우나요?
연속된 메모리를 효율적으로 처리합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Swift Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Swift Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.
“안전하지 않은 버퍼 포인터” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Swift Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Swift Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.