콘텐츠로 건너뛰기
Home » swift

swift

(Swift) 폰트의 포스트 스크립트 이름 확인 방법

CATextLayer에서 텍스트의 폰트를 지정해주려면, CTFontRef를 만들어서 넘겨주어야 한다. 이 값은 CTFont 나 CGFont 타입과 브릿징되기 때문에 CTFont를 만들어야 한다. 만약 시스템에 설치된 서드파티 폰트를 사용해서 CTFont 객체를 만들려면 해당 폰트의 포스트 스크립트 이름을 알고 있어야 한다. 즉 CATextLayer에서 커스텀 폰트를 사용하려면 해당 커스텀 폰트의 포스트스크립트 이름이 필요하다는 이야기이다. macOS에서는 간단하게 서체 관리자에서 해당 폰트를 선택하여 정보보기(cmd + i)를 통해 PostScript Name을 확인해서 이 값을 알 수 있다. 그런데 iOS에서는 서체 관리자가 없기 때문에 이 방법을 쓸 수 없다. 대신에 다음… 더 보기 »(Swift) 폰트의 포스트 스크립트 이름 확인 방법

Opaque 리턴타입(Swift 5.1)

이 블로그의 다른 글에서 Swift의 타입 지우기에 대해서 살펴본 바 있습니다. 특정한 연관 타입에 의존하지 않는 프로토콜은 그 자체로 타입처럼 취급될 수 있지만, 연관 타입에 의존하는 프로토콜은 일종의 제네렉과 비슷하기 때문에 구체적인 타입처럼 사용될 수 없습니다. 타입 지우기(Type Erasure)는 특정한 프로토콜을 따르는 Any 타입을 만들어서 프로토콜을 채택한 실제 타입을 감추고 프로토콜의 기능적 잇점은 누릴 수 있게 하는 기법입니다. 하지만 타입 지우기를 사용하려면 특정 타입을 감싸는 별도의 타입을 만들어야 하고, 성능상으로도 오버헤드가 발생하는 제약이 있습니다. Swift는 프로토콜을 실제 구체적인 타입으로 사용할… 더 보기 »Opaque 리턴타입(Swift 5.1)

Swift 프로퍼티의 옵저버에 대한 규칙

lazy 프로퍼티는 옵저버를 가질 수 없다. (단 최초 액세스 이후 변경하는 것은 가능하다.) computed 프로퍼티에 대해서는 옵저버를 설치하는 것이 의미가 없다. 단 상속받은 computed 프로퍼티에 대해서는 옵저버를 설치할 수 있다. 옵저버는 해당 클래스의 지정 이니셜라이저 내에서 값을 변경하는 경우에는 호출되지 않는다. 단, 상속받은 프로퍼티가 옵저버가 설치되어 있다면 부모의 지정 이니셜라이저 호출 후에 변경한다면, 부모의 옵저버가 호출될 것이다. 비슷하게 편의 이니셜라이저에서는 지정 이니셜라이저를 통해 초기화한 후, 프로퍼티값을 다시 변경하면 옵저버가 실행된다. lazy 프로퍼티와 옵저버 lazy 프로퍼티는 옵저버를 가질 수 없다. 위에서… 더 보기 »Swift 프로퍼티의 옵저버에 대한 규칙

Raw 포인터 사용에 대해

https://developer.apple.com/documentation/swift/unsaferawpointer

UnsafeRawPointer 타입은 자동 메모리 관리, 타입 안정성 및 메모리 정렬 보장이 되지 않는 원시 포인터 액세스를 제공합니다. 이 타입을 사용하려면 누수를 피하고, 할당된 메모리의 라이프 사이클을 직접 관리해야 하며, 그 외의 정의되지 않는 동작들을 회피해야 합니다. 수동으로 직접 관리하는 메모리 영역은 특정한 타입에 바운드되거나, 타입이 지정되지 않을 수도 있습니다. 메모리 영역에서 해당 영역이 특정 타입에 묶여있는지 여부와 무관하게 순수 바이트를 액세스하려할 때 UnsafeRawPointer 타입을 사용할 수 있습니다.

막 할당된 Raw 메모리는 타입화되지도 초기화되지도 않은 상태입니다. 이 메모리는 타입화된 연산을 사용하기 전에 반드시 초기화되어야 합니다. (초기화되려면 초기값을 가져야하고, 이는 타입화를 수반해야한다는 의미가 됩니다.) 초기화되지 않은 상태에서 특정 타입에 바인등하려면 bindMemory(to: count:)를 사용합니다. 이 메소드는 타입화된 포인터를 반환하며, 이후에는 해당 포인터를 사용해야 합니다.

더 보기 »Raw 포인터 사용에 대해

버퍼 포인터 이해하기

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 프로토콜에 의한 여러가지 연산을 지원받습니다.

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

Unmanaged 에 대해 – Swift

그 옛날(?) ARC가 없던 시절에 Objective-C 및 코어 파운데이션에서 객체에 대한 참조수 관리는 완전한 수동 방식에 의존하고 있다. 어떤 객체에 대한 retain(참조수를 늘리는 것) 동작은 반드시 그에 수반하는 release(참조수를 내리는 것) 동작을 필요로 했다. 그리고 이 짝이 제대로 맞지 않으면 객체는 필요한 시점에 사라지고 없거나, 반대로 메모리 누수가 발생했다. 그러던 중 자동 참조수 카운팅(ARC)이 도입되었는데, ARC 환경에서는 모든 retain/release/autorelease 콜이 컴파일러에 의해 코드에 자동으로 삽입되었다. 이는 전체적인 코드량의 감수는 물론 개발 난이도를 매우 낮춰주는 역할을 했다.

ARC가 도입된 이후 Objective-C 메소드에 의해 반환되는 모든 Objective-C 객체와 코어 파운데이션 객체의 메모리 관리는 자동으로 이루어졌다. 하지만 C 함수에 의해 리턴되는 코어 파운데이션 객체는 이러한 은혜를 받지 못했다. 따라서 여기에 속하는 객체들에 대해서는 여전히 CFRetain(), CFRelease()를 호출하거나, __bridge*로 시작하는 함수를 통해 Objecitve-C 객체로 브릿징해야 했다.

더 보기 »Unmanaged 에 대해 – Swift

포인터 관련 메모

타입화된 포인터

Swift는 C API와의 상호작용 혹은 고성능 자료구조의 구현등을 위해 포인터를 통한 메모리 액세스를 제한적으로 지원하고 있습니다. 기본적으로 Swift 타입 혹은 Swift 에서 인식할 수 있는 C 타입에 대한 포인터는 ‘타입화된(typed)’ 포인터라고 하며, UnsafePointer를 사용합니다. UnsafePointer는 제네릭 struct 타입으로 특정 Swift 타입에 대한 포인터로 기능합니다. UnsafePointer는 메모리 주소를 통한 액세스를 허용해주기는 하지만 값의 불변성을 보장하기 때문에 해당 포인터가 가리키는 값(pointee)를 변경하는 것을 허용하지 않습니다. 변수에 대한 포인터는 UnsafeMutablePointer를 별도로 사용합니다.

더 보기 »포인터 관련 메모

Swift – BlockOperation 사용하기

Operation(NSOperation)은 특정한 작업을 수행하기 위한 코드와 데이터를 감싸는 객체로 해당 작업을 동기/비동기로 필요한 시점에 실행하기 위한 용도로 사용한다. NSOperation은 OSX 10.5에서도입되었는데, 이 시점의 Objective-C에서는 클래스의 외부에서 코드를 주입할 수 있는 언어적인 장치가 존재하지 않았기 때문에, 이를 사용하려면 무조건 NSOperation의 서브클래스를 만들어야 하는 불편한 점이 있었다. 따라서 간단한 코드 조각을 실행하기 위해서 NSOperation을 사용하는 것은 꽤나 불편한 일이었다.

OSX 10.6(스노우레퍼드)부터 GCC/Clang을 기본 컴파일러로 사용하게 되었고 이때부터 코드블럭 기능이 지원되었다. 즉 별도의 서브클래스를 작성하지 않더라도 코드 블럭의 형태로, 마치 클로저처럼 코드와 코드가 캡쳐링하는 데이터를 주입하여 오퍼레이션 인스턴스를 만드는 것이 가능해졌다. 실질적으로 NSOperation을 그대로 사용해야할 이유는 현재로서는 찾아보기 힘들다.

더 보기 »Swift – BlockOperation 사용하기

복사/붙여넣기를 지원하는 Swift 타입 작성하기 2

복사/붙여넣기를 지원하는 타입을 작성할 때, 해당 타입은 반드시 직렬화 및 역직렬화가 가능해야 했다. 그런데 NSPasteboardReading 프로토콜은 지정 이니셜라이저를 포함하고 있기 때문에 클래스를 직접 수정하거나 서브클래싱하지 않으면 이 방법을 적용할 수가 없다. 따라서 NSPasteboardItem을 대신 사용하는 방법을 적용해야 한다. 이 때 핵심은 해당 클래스가 어떤 모종의 방법을 사용해서 직렬화 및 역직렬화가 가능해야 한다는 점이다.

더 보기 »복사/붙여넣기를 지원하는 Swift 타입 작성하기 2