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

Swift

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

Swift :: NSScanner 사용예제

NSScanner로 문자열로부터 특정한 값 뽑아내기

이 문서는 Swift 4.2를 기준으로 수정되었습니다. NSScanner에 대한 Swift Foundation 대응 클래스인 Scanner 클래스가 새로 정의되었으며, CharacterSet에 대한 몇 가지 사용 방법이 변경되었습니다

  1. 스캔할 문자열을 넘겨서 Scanner 객체를 생성한다.
  2. 스캐너가 무시하고 지나가야 할 문자들이 있으면 CharacterSet 타입의 값으로 만들어서 charactersToBeSkipped 속성으로 지정한다.
  3. 자, 이제 스캔을 시작하지.

이때, 스캐너의 API는 예전 Objective-C API에서 크게 바뀌지 않은 관계로 포인터를 인자로 받고, 넘겨 받은 포인터가 가리키는 객체에 스캔한 값을 쓰게 된다.

더 보기 »Swift :: NSScanner 사용예제

Mac App’s Core Objects

App Life Cycle

여느 C 프로그램과 같이1 OSX앱도 main 함수로부터 시작한다. 이 함수는 단순히 NSApplicationMain() 함수를 다시 호출한다. 대략 이렇게 생겼다.

#import <Cocoa/Cocoa.h>
int main(int argc, const char* argv[]) {
    return NSApplicationMain(argc, (const char**) argv);
}

NSApplicationMain 함수는 앱을 초기화하고 실행할 준비를 한다. 초기화 과정의 일환으로 이 함수는 아래와 같은 작업을 한다.

  1. NSApplication 클래스 객체를 하나 만든다. 이 객체는 +sharedApplication 메소드로 얻을 수 있다.
  2. Info.plist 파일을 읽어들여서 여기에 기록된 NSMainNibFile로부터 nib 파일을 읽어들인다. 만약 스토리보드를 쓰고 있다면 기본 스토리보드를 읽어와서 객체들을 구성한다. UIApplicationMain과는 달리 앱 델리게이트는 기본 Nib 파일에 반드시 포함되어 있어야 한다.
  3. 애플리케이션 객체의 run 메소드를 호출한다. 이로써 론칭과정은 끝나고 앱의 이벤트 처리를 시작한다.

더 보기 »Mac App’s Core Objects

Objective-C / Swift :: NSRegularExpression

NSRegularExpression Foundation은 유니코드 문자열에 대해서 정규식을 적용할 수 있는 NSRegularExpression 클래스를 제공한다. 이 클래스의 인스턴스는 컴파일된 정규식 패턴을 나타낸다. 여기서 사용되는 정규식 표현 패턴은 ICU의 안을 따르고 있다. (파이썬 정규식과 거의 유사하다.) http://userguide.icu-project.org/strings/regexp 기본적으로 정규식 객체는 자신의 패턴을 문자열에 적용해서 매치 결과들에 대해서 실행되는 블럭 이터레이터를 제공한다. 그 외에도 매치 결과를 배열로 리턴하거나, 매치의 수를 찾거나, 첫 매치를 찾는 등의 편의 메소드도 제공한다. 각각의 매치 결과는 NSTextCheckingResult 객체인데, 이는 전체 매치의 범위(NSRange) 및 개별 캡쳐 그룹의 범위값을 가지고 있다. 객체… 더 보기 »Objective-C / Swift :: NSRegularExpression

NSApplicationMain

NSApplicationMain int NSApplicationMain(int argc, const char* argv[]); 코코아 앱이 실행될 때 main 함수가 곧장 호출하는 함수로, 앱 객체를 생성하고 앱의 런칭 과정을 처리한다. 앱 객체의 클래스는 무조건 NSApplication이며, 앱 델리게이트는 nib 파일 내에 정의되어 있어야 한다. (iOS는 앱 델리게이트 클래스명을 전달하는 인자 부분이 마련되어 있음) argc, argv 파라미터가 정의되어 있지만, 실제로 값을 전달해도 무시한다. 코코아 내에서는 프로그램 실행시의 arguments를 _NSGetArgv, _NSGetArgc, _NSGetEnviron 함수들을 통해서 얻어야 한다.

Swift :: @noescape explained

#@noescape @noescape는 함수 파라미터로 클로져를 선언할 때 해당 클로저내의 모든 정보가 외부로 나갈 수 없음을 명시한다. 표현이 좀 애매한데, @noescape로 선언된 클로져는 다음의 동작만이 가능하다. 클로저가 인자로 전달된 함수 내에서 호출 가능 함수 내에서 다른 함수(이 때 이 다른 함수도 클로져를 @noescape로 선언한 경우에만)로 전달하여 호출할 수 있다. 다른 함수나 클로저에서 역시 @noescape로 선언된 경우에 캡쳐 다음의 경우에는 쓸 수 없게 된다. 다른 지역변수에 대입이 불가하다. 이는 클로져 내의 캡쳐된 모든 변수에 대해서 추가적인 강한 참조를 더할 수 없다는 뜻이다.… 더 보기 »Swift :: @noescape explained

UIApplicationMain

UIApplicationMain UIKit에서 앱의 런칭 프로세스를 처리하는 함수. UIApplication 객체를 생성하고, 앱의 기본 설정을 Info.plist 파일로부터 읽어들인다. int UIApplicationMain(int argc, char *argv[], NSString *pricipalClassName, NSString *delegateClassName); principalClassName : UIApplication 클래스를 서브클래싱한 경우 해당 클래스 이름을 전달한다. nil을 쓰는 경우 이 값은 UIApplication으로 고정된다. delegateClassName : 앱 델리게이트 클래스 이름. 만약 nib 파일 내에 앱 델리게이트 객체가 정의되어 있다면 nil을 전달해야 한다.

Swift :: 1.2의 커리드함수와 함수 합성에 대해

커링

Swift 1.2부터는 커리드 함수를 만들 때 파라미터 이름을 생략할 수 있게 되었다.1 함수를 커리드함수로 정의할 때

func f(a:Int)(b:Int)(c:Int) -> Int {
    return a * 2 + b * 3 + c * 5
}
let a = f(1)
let b = a(b:2)
let c = b(c:3)

이런식으로 커리드된 함수에서는 파라미터 이름을 반드시 넣어야 했는데, 이렇게 부분적용함수의 나머지 인자에 대해 반드시 이름을 쓰는 것만 허용이 됐었다. 이 경우에는 부분적용함수를 실제로 호출하는 경우, 반드시 해당 파라미터 이름을 기술해야하므로, 원 함수의 시그니쳐를 알지못하면 쓰기가 어렵기 때문에 활용할만한 곳이 많이 않았다. 하지만 Swift 1.2에서부터 이런 제한이 없어지고, 아래와 같이 2차 이후 부터의 인자 외부 이름을 생략하는 것이 허용됐다.더 보기 »Swift :: 1.2의 커리드함수와 함수 합성에 대해

Swift :: @autoclosure explained

#@autoclosure 인자로 클로저를 받는 함수를 하나 생각해보자. func f(pred: () -> Bool) { if pred() { println("It's true") } } 이 함수를 호출할 때에는 클로져 자체를 넘겨주게 된다. f({ 2 > 1}) // 혹은 f{2 > 1} @autoclosure는 함수의 파라미터를 자동으로 클로져로 감싸면서 호출한 시점의 문맥에서 동작하게 한다. 따라서 f(2 > 1) 로 호출할 수 있다. 이 기능의 의미는 인자로 전달되는 표현식의 평가 시점에 있다. 일반적인 함수 호출 흐름에서는 표현식이 함수의 인자로 들어가게 될 때, 함수는 값을 전달받게 되므로 표현식이… 더 보기 »Swift :: @autoclosure explained

Swift :: Encode and Decode a value type’s instance

임의의 Struct, Enum 타입을 인코딩하라.

임의의 값 타입을 인코딩하는 법을 찾아보자. (클래스의 경우에는 NSCoding이 있으니…) 먼저 인코딩이 필요한 함수를 생각해보자. NSData는 특정 포인터와 그 길이를 가지고 데이터를 만들 수 있다. NSData(bytes:UnsafePointer<T>, length:Int) 여기서 크기는 타입의 크기인데, C와 같이 Swift도 sizeof() 함수를 제공한다. (C에서는 연산자이다.)
Swift에서 inout T 타입과 UnsafePointer<T> 타입은 구분되므로 (T가 옵셔널인 경우에는 포인터로 간주될 수 있다.) 보조 함수인 withUnsafePointer<T>(_:_:) 함수를 사용하여 inout 으로 넘긴 T 타입을 포인터로 바꿀 수 있다.
따라서 인코드 함수는 다음과 같이

func encode<T>(var value:T) -> NSData {
    let data = withUnsafePointer(&value){
        (p:UnsafePointer<T>) -> NSData in
        return NSData(bytes:p, length:sizeof(T.Type))
    }
    return data
}

작성할 수 있다. 디코드하는 함수는? 이건 영락없이 포인터를 만들어서 메모리를 신규로 할당하고 여기에 바이트를 채워넣는 수 밖에 없어보인다. (물론 NSValue로 만들어서 내놓는 방법이 있는데, Swift는 아직 @encode를 쓸 수 없다.)
그래서 UnsafeMutablePointer<T> 타입을 이용해서 실제로 포인터를 다뤄보자.더 보기 »Swift :: Encode and Decode a value type’s instance

Swift – Access Control

Swift – Access Control

액세스 컨트롤은 다른 모듈이나 다른 소스파일로부터 코드의 일부에 접근하는 것을 제한하는 것을 의미한다. 이 기능을 사용하면 구현 코드를 숨기거나, 다른 곳에서 액세스할 수 있는 API를 선별적으로 지정할 수 있다.
액세스 레벨은 개별타입(클래스, 구조체, 열거체)에 대해서 프로퍼티, 메소드, 이니셜라이저, 서브스크립팅등에 대해 적용할 수 있다. 프로토콜은 특정한 컨텍스트에 대해 제한될 수 있는데 이는 전역 상수나 변수, 함수와 유사한 특성을 가진다. 그외에도 Swift는 명시적인 액세스 컨트롤을 할 필요가 그리 많지 않다. 만약 단일 타깃 앱을 개발하고 있다면 명시적으로 액세스 컨트롤을 정의할 필요가 없다.더 보기 »Swift – Access Control