콘텐츠로 건너뛰기
Home » Development » Swift » 페이지 7

Swift

Swift / Cocoa / Foundation / Programming Language / UIKit / AppKit / Swift Standard Library / Swift 문법과 기능 / 공부하면서 알게된 내용들을 정리 / 어느 프로그래밍 언어 덕후의 연습장

Trie 자료구조 – Swift

for c in currentNode.children.keys.sorted() {트리(trie)자료 구조는 트리(tree)와 발음이 비슷한데, 실제로도 tree와 비슷한 형태로 문자열이나 이와 유사한 형태의 연속열들을 저장할 수 있는 자료 구조이다. 보통 영단어들을 저장할 때 유용한데, 다음과 같은 장점들을 가진다. 특정한 값을 찾을 때, 다른 구조들에 비해서 최악의 경우에서도 대개 더 나은 시간 복잡도를 보인다. 해시테이블과 달리 키 충돌을 고려할 필요가 없다. 특정한 요소에 다다르는 경로를 찾기위한 부가적인 해시 알고리듬을 요구하지 않는다. 알파벳순으로 정렬하기가 매우 쉽다. Trie는 어떤 단어의 첫글자와 그 다음에 올 수 있는 글자, 그리고 그… 더 보기 »Trie 자료구조 – Swift

enum 타입 사용법 정리 – Swift

Emumerations

“열거”타입은 임의의 관계를 맺는 값들을 하나의 타입으로 묶어서 타입-안전한 방식으로 다룰 수 있게 해준다. C에서도 enum 키워드를 이용해서 열거체를 선언할 수 있었는데, C의 열거체는 개별 정수에 대해서 다른 이름을 붙인 상수처럼 취급했다. 반면 Swift의 열거타입은 보다 유연하며 열거 타입 내의 개별 케이스가 단일 값을 대신해서 코드 상에서 구분하기 쉬운 이름을 갖는 것 보다 더 폭넓게 사용될 수 있다. 우선 각각의 케이스가 정수값이 아닌 실수나 문자열등의 다른 Swift 기본 타입의 값을 사용할 수 있다.

또한 각 케이스가 값 하나가 되는 것 외에 각각의 케이스가 연관 값을 갖는 것이 허용된다. 이 때에는 같은 열거형 내의 각각의 케이스가 서로 다른 타입의 연관 값을 갖는 것도 허용된다.

열거 타입은 Swift내에서 일급 클래스로 취급되며, 클래스가 가지는 계산 프로퍼티나 메소드를 포함하는 것도 가능하며, 이니셜라이저를 가지거나 확장도 할 수 있으며 따라서 프로토콜을 따르도록 정의될 수 있다.

더 보기 »enum 타입 사용법 정리 – Swift

required 가 붙은 이니셜라이저

UIView, UIViewController를 서브클래싱하는 코드를 작성하면서 init(frame:)을 오버라이딩하는 코드를 작성하면, Xcode는 매번 init?(coder:)가 정의되지 않았다는 컴파일 에러를 낸다. 일단 이 에러를 해결하려면 간단하게 부모 클래스의 이니셜라이저를 그대로 호출해주기만 하면 된다.

required override init?(coder aDecoder: NSCoder!) {
    super.init(coder: aDecoder)
}

왜 이 init?(coder:)는 자동으로 상속이 안되는 것일까?

잠깐, 이니셜라이저 관련한 프로그래밍 가이드에서는 required 이니셜라이저는 서브클래스에서 오버라이딩할 때 override를 붙이지 않는다고 했는데? Xcode는 override를 붙여야 한다고 한다. 이 부분은 재확인이 필요하다.
(https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID203)

더 보기 »required 가 붙은 이니셜라이저

(Swift) Set 타입

Set

일련의 값들이 순서를 가지고 (혹은 그 순서는 별로 중요하게 아니더라도) 집합을 이루고 있을 때 사용하는 가장 흔한 자료 구조는 배열이다. 배열은 원소들이 연속적으로 저장된다는 점에 기반하여 임의 원소에 빠르게 액세스할 수 있는 점과 선형적인 구조에 기반한 여러 테크닉들을 적용할 수 있다는 점에서 널리 사용된다.
하지만 배열은 집합과 관련된 문제에 대해서 항상 옳은 선택이 아닐 수 있다. 예를 들어 특정한 값이 집합내에 포함되어 있는지 여부는 contains(_:)를 통해서 손쉽게 알 수 있지만, 해당 메소드의 시간 복잡도는 $ O_{(n)} $ 이다. 이외에 배열은 두 개 이상의 배열에 대해서 합집합은 원소의 중복을 감안한다면 비교적 쉽게 얻을 수 있으나, 교집합이나 차집합에 대해서는 별도의 로직을 만들어서 이를 구해야하고 이 때의 성능도 거의 항상 $O_{(n)}$일 수 밖에 없다. 즉 개별 원소의 저장소로의 배열보다 집합 자체를 다뤄야 하는 상황이라면 배열보다 더 어울리는 자료구조가 있는데, 그것이 바로 Set이다.더 보기 »(Swift) Set 타입

프로퍼티와 전역변수 – Swift

Swift에서는 클래스나 구조체의 프로퍼티처럼 top-level의 자유 변수나 상수에 대해서도 계산된 프로퍼티나, `didSet`, `willSet`과 같은 옵저버 메소드를 정의하는 것이 가능하다.

(Swift) Objctive-C와 Swift 타입의 브릿징

브릿징

Swift의 많은 기본 타입들은 Objective-C의 파운데이션 타입에 대응되는 것들이 있고 (e.g. String <-> NSString) 이렇게 카운터파트가 존재하는 타입들은 파운데이션타입으로 브릿징된다. 브릿징은 Objective-C 타입이 Swift 타입으로 행동하거나 혹은 반대로 Swift 타입이 Objective-C 타입처럼 행동하여 이 둘을 상호간에 바꿔쓸 수 있음을 말한다. 다시 말해 파운데이션 API를 사용하면서 NSString 을 사용해야 할 때 String을 쓰거나 반대로 Swift 함수/메소드 호출 시 String 을 써야 할 때 NSString을 쓰는 것이 허용된다는 말이다. 1

 Swift는 어떤 Objective-C 타입들을 자동으로 Swift 타입으로 변환하며, 그 반대의 동작도 자동으로 수행합니다. 이렇게 Objective-C와 Swift 사이에서 전환되는 타입들을 “bridged types”라 부릅니다. 예를 들어, Swift 코드에서 NSString 파라미터를 요구하는 Objective-C API에 String 타입의 값을 넘겨줄 수 있습니다. 또한 많은 코코아 프레임워크들은 API를 좀 더 Swift 스럽게 새로 정의했습니다. 예를 들어 NSCoderdecodeObjectOfClass(_:forKey:)는 Swift의 제네릭 타입을 통해 보다 강한 타입시그니처를 갖게 됐습니다.2

사실 이 브릿징은 Objective-C에 익숙하다면 낯선 개념은 아니다. 코코아에는 Objective-C가 아닌 C로 제작된 코어 파운데이션 프레임워크가 있고, 이미 NS* 클래스들은 CF* 타입들과 브릿징되고 있다. 더 보기 »(Swift) Objctive-C와 Swift 타입의 브릿징

(Swift) Array – 05. NSArray

목차

  1. Array – 생성과 조작
  2. Array – Sequence 프로토콜
  3. Array – Collection 프로토콜
  4. Array – ArraySlice
  5. Array – NSArray

브릿징 – NSArray

NSArray에서 제공하는 API를 사용하기 위해서는 Array 인스턴스를 as NSArray를 통해서 브릿징해야 한다. 브릿징이 가능한 경우는 배열 내 원소의 타입이 다음 중 한가지여야 한다.

  1. 클래스
  2. @objc 속성이 있거나 Objective-C로부터 들여온 프로토콜
  3. 애초에 Foundation 타입으로 브릿지 되는 타입

아래 예제는 Array 인스턴스를 NSArray 인스턴스로 브릿징하여 그 내용을 write(to:atomically:)로 저장하는 방법을 보여준다. [String] 타입은 NSArray<NSString>으로 브릿징이 가능하지만 [String?] 타입에 대해서는 불가능한데, String? 옵셔널 타입은 NSString으로 브릿징되지 않기 때문이다.더 보기 »(Swift) Array – 05. NSArray

(Swift) tip – NSDateFormatter는 singleton으로 사용하라?

NSDateFormatter와 관련된 애플 공식 문서에는 다음과 같은 내용이 있다. 날짜 포매터를 생성하는 일은 비싼 작업입니다. 만약 포매터를 빈번하게 사용해야한다면, 여러 개의 인스턴스를 만들고 버리는것보다 하나의 인스턴스를 만들어서 이를 캐시에 보관해두는 편이 더 효율적입니다. static 변수를 사용하는 것도 한 가지 방법입니다. 1 이는 포매터에 의존하는 어떤 타입이 있을 때, 싱글턴을 쓰기에 참 좋은 예가 된다는 것을 암시한다. Objective-C에서는 싱글턴을 다음과 같은 식으로 만들었다. @implementation SomeClass +(NSDateFormatter*) defaultFormatter{ static NSDateFormatter *defaultFormatter = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ defaultFormatter= [[NSDateFormatter alloc] init];… 더 보기 »(Swift) tip – NSDateFormatter는 singleton으로 사용하라?

(Swift) Array 완전 정복 – 04. ArraySlice

ArraySlice 와 Range

배열은 단일 인덱스를 통해 하나의 원소를 액세스하는 것 외에도 범위(Range<Index>)값을 통해 하나 이상의 원소로 이루어진 부분 배열을 액세스하는 것이 가능하다.

let a = Array<Int>(1...10)
let b = a[3..<6] // [4, 5, 6]

범위는 ... 연산자와 ..< 연산자를 통해서 만들 수 있는데, 전자는 닫힌 범위, 후자는 열린 범위이다. 열린 범위는 맨 끝 값을 포함하지 않는 범위이다. 즉, 1...10 ==> 1, 2, 3 .. 10 이고 1..<10 ==> 1, 2, 3, .. 9 이다.
범위에 대해서도 좀 더 살펴봐야하겠지만, 여기서는 이 부분열에 대해 생각해보자. 이제 배열에 대해 보다 깊숙히 들여다 볼 차례이다.더 보기 »(Swift) Array 완전 정복 – 04. ArraySlice

(Swift) Array 완전 정복 – 03. Collection 프로토콜

Collection

 
Collection은 일반적인 “집합 컨테이너”를 묘사하는 프로토콜인데, 실질적으로는 Sequence 프로토콜을 상속하면서 한 가지 개념(기능)을 추가한 것으로 이해할 수 있다. 그것은 임의의 인덱스를 통해서 개별 원소를 액세스할 수 있는 점이다. 따라서 Sequence와 달리 여러번이고 순회할 수 있고, 순회 시 내부 자료가 소모되지 않는다.더 보기 »(Swift) Array 완전 정복 – 03. Collection 프로토콜