버퍼 포인터 이해하기

C에서 특정한 T타입의 배열은 메모리 상에서 연속적인 공간입니다. 이 때문에 정적 배열이든 동적 배열이든 배열을 액세스하는 것은 필연적으로 포인터와 관련됩니다. 반면 Swift의 배열에서 원소들은 반드시 이런 식으로 배치되지는 않습니다. C의 배열이 단지 원소값이 나란히 배치된 메모리 영역임에 비해 Swift의 배열은 struct로 구성되는 보다 복잡한 내부 구조를 가지고 있습니다.

이 때 T 타입이 차지하는 바이트 수가 고정되어 있으므로 배열의 시작번지와 인덱스 값을 알고 있다면 해당 인덱스에 위치한 값을 액세스할 수 있습니다. C에서 배열 이름은 암묵적으로 배열의 시작번지를 의미하므로, arr[i]로 표현되는 i 번째 원소의 값은 실제 컴파일러는 *(arr + i) 로 변환하여 접근합니다.

Swift에서도 UnsafePointer를 사용하여 포인터를 다룰 수 있는데, 이 때 범위(capacity, Pointee 타입의 메모리 사이즈 x 원소의 개수)내에는 동일타입을 구성하는 값들이 연속하여 배치되어 있습니다. 따라서 (ptr + i).pointee 와 같은 식으로 i 번째 원소에 대해 액세스가 가능합니다. 이것은 C의 접근방법과 매우 유사합니다. 하지만 이것은 단순한 메모리 연속체에서 특정 지점을 액세스하는 법일 뿐, Swift의 배열을 다루는 것과는 차이가 있습니다. Swift의 배열은 원소가 연속해있으면서 Sequence, Collection 프로토콜에 의한 여러가지 연산을 지원받습니다.

버퍼 포인터 이해하기 더보기

꼬리재귀 최적화와 트램폴린

꼬리재귀 최적화

꼬리재귀는 재귀의 특별한 한 형태인데, 재귀호출로 받은 결과값을 추가로 계산하거나 처리하지 않고 그대로 리턴하는 형태를 말한다. 예를 들어 1부터 n 까지의 합을 구하는 함수를 재귀로 구현했다고 하면 일반적으로 다음과 같은 꼴을 생각할 수 있다.


func sum1(n: Int) -> Int { if n < 1 { return 0 } return n + sum1(n - 1) }

이를 꼬리 재귀로 만들면 다음과 같다.

func sum2(n: Int, acc: Int = 0) -> Int {
  if n < 1 { return acc }
  return sum2(n-1, acc: acc + n)
}

꼬리재귀 최적화와 트램폴린 더보기

Objective-C 래퍼를 통해 Swift에서 SQLite3를 사용하는 법

이 글에서는 Objective-C로 SQLite3 데이터베이스에 액세스하는 API를 래핑한 간단한 클래스를 작성해보겠다. 사실 Objective-C로 SQLite3를 사용하는 것은 C API를 그대로 사용하면 되는 부분인데, 이렇게 래퍼를 만들면 브릿징헤더만 작성해주면 래퍼 클래스를 Swift에서 그대로 사용할 수 있게 되기 때문에 좀 더 쉽게 사용할 수 있다.

Swift에서 C헤더를 바로 반입할 수 있기 때문에 이 방식은 오히려 번거로울 수 있다. (특히 스펙이 약간만 변경되어도 Objective-C 클래스를 수정해야 한다.) 선택은 각자가 알아서 하시면 되겠다.

Objective-C 래퍼를 통해 Swift에서 SQLite3를 사용하는 법 더보기