Home » Development » Objective-C » Page 3

Objective-C

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 함수들을 통해서 얻어야 한다.

UIApplicationMain

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

Objective-C :: 임의의 데이터 타입을 NSData로 인코딩하기

NSValue NSData 변환

NSValueNSData로 변환하는 방법에 대해 생각해보자. 코어데이터 등에서 표준으로 지원하는 타입이 아닌 경우, NSData를 이용해서 이진데이터로 저장하는 방법이 있는데, 예를 들어서 NSRange(이건 C구조체이다.)를 이진데이터로 바꾸는 것은 다음과 같이 하면 된다.

NSRange r = NSMakeRange(0, 10);
NSValue* v = [NSValue valueWithRange:r];
NSData* d1 = [NSKeyedArchiver archivedDataWithRootObject:v];

구조체나 스칼라값 타입은 NSValue로 감싼 다음 이진데이터로 직렬화할 수 있다. NSValue 역시 NSCoding 프로토콜을 따르므로 위와 같이 처리하면 되는데….더 보기 »Objective-C :: 임의의 데이터 타입을 NSData로 인코딩하기

NSScanner

http://nshipster.com/nsscanner/

문자열은 모든 곳에 있고 컴퓨팅의 여러 부분을 담당하고 있다. 이메일, 에세이, 시, 소설, 이 글도 그렇고 심지어 블로그의 코드도 모두 문자열로 되어 있다. 문자열을 쪼개고 특정한 부분을 추출해 내는 능력은 프로그래밍에서 강력한 무기가 될 수 있다. 코코아는 문자열을 쪼개고 합치는 다양한 방법을 제공하는데, 그 중 몇 가지 유명한 예를 들자면,

  • string.componentsSeparatedByCharactersInSet / string.componentsSeparatedByString : 문자열을 특정 토큰을 기준으로 잘라 배열로 쪼갠다.
  • NSRegularExpression : 정규식을 적용한다. 하지만 정규식은 복잡한 문자열에 대해서는 꽤나 번거롭기도 하거니와 많은 주의를 기울일 필요가 있다.
  • NSDataScanner : 문자열에서 주소, 날짜와 시간, URL 등을 추출해 내지만 정해진 포맷에 대해서만 사용할 수 있다는 제약이 있다.
  • NSScanner : 고도로 커스터마징이 가능한 문자열 스캔 클래스.

NSScanner는 문자열의 래퍼처럼 사용하고, 내부의 문자열을 탐색해서 효과적으로 부분문자열 집합이나 숫자값등을 추출해 낼 수 있다. 이 동작을 제어하는 몇 가지 프로퍼티를 살펴보자면,

  • caseInsensitive:Bool : 문자열을 탐색할 때 대소문자 구분을 무시할 것인지 여부
  • charactersToBeSkipped:NSCharacterSet : 탐색시 무시할 글자들을 정의한다.
  • scanLocation:Int : 스캐너의 현재 위치이다. 이 값을 조정하면 빨리감기/되감기 등을 할 수 있다.
  • locale:NSLocale : 문자열을 숫자값으로 바꿔낼 때 사용할 로케일 값이다.
더 보기 »NSScanner

문자열의 부분집합(Swift)

문자열의 부분집합 구하기 Swift3으로 업데이트 (2016-07-04) 인덱스타입(Index)은 특정한 집합 내에서의 위치를 가리키기 때문에 다음번 인덱스의 위치를 계산하기 위해서는 원래의 문자집합을 알고 있어야 한다. 따라서 advance() 메소드는 상당히 부담스러우므로, 성능 개선을 위해서 이는 문자열에서 특정 인덱스의 오프셋 이동을 하는 메소드를 사용하도록 바뀌었다. String.index(_:offset:) Range 타입의 양끝은 startIndex, endIndex가 아닌 lowerBound, upperBound가 되었다. 따라서 서브스크립션 확장은 다음과 같이 재작성 된다. extension String { subscript(r: Range<Int>) -> String { let a = self.index(startIndex, offsetBy: r.lowerBound) let b = self.index(startIndex, offsetBy: r.upperBound) return self[a..<b]… 더 보기 »문자열의 부분집합(Swift)

Selector in Swift

셀렉터(Swift) 셀렉터는 Objective-C 메소드의 이름을 가리키는 참조타입이다. @selector() 디렉티브를 써서 메소드 이름을 정수값으로 맵핑하여 표시한다. Swift에서는 이 셀렉터는 Selector라는 구조체로 표현되며 문자열 리터럴로 만들 수 있다. 만드는 방법은 Objective-C 스타일과 거의 유사하다. import UIKit class MyViewController: UIViewController { let myButton = UIButton(frame: CGRect(x:0, y:0, width:100, height:50)) init(nibName nibNameOrNil:String?, bundle nibBundleOrNil:NSBundle?) { super.init(nibName:nibNameOrNil, bundle: nibBundleOrNil) myButton.addTarget(self, action:”tappedButton:”, forControlEvents:.TouchUpInside) } func tappedButton(sender:UIButton!) { println(“tapped inside”) } } NSObject의 performSelector:의 경우 안정성의 문제로 현재(2015. 01)까지는 Swift에서는 불가능하다. 만약 Swift 클래스가 Objective-C의 클래스를 상속받지… 더 보기 »Selector in Swift

블럭의 변수 캡쳐링

블럭 내 변수 캡쳐링

C의 코드블럭은 사실상 여타 프로그래밍 언어의 클로저개념1과 거의 동일하다.
블럭 내부에서는 다음의 변수들을 사용할 수 있다.

  1. 전역변수와 정적변수는 블럭내에서 액세스 가능하다.
  2. 블럭 내로 전달된 파라미터는 블럭 내부로 복사되며 지역변수처럼 액세스한다.
  3. 블럭을 감싼 영역의 스택 변수는 블럭 내에서 액세스 가능하되 상수로 취급한다.
  4. 블럭을 감싼 영역에서 __block 변경자와 함께 선언된 변수는 참조로 전달되며, 블럭내에서 변경 가능하다.
  5. 블럭 내에서 선언된 지역 변수는 함수의 지역변수와 동일하게 동작한다. 액세스 가능하며, 블럭의 스코프가 끝날 때 파괴된다.

더 보기 »블럭의 변수 캡쳐링

날짜와 시간을 다루기(Swift)

날짜와 시간 다루기 (Swift)

Swift에서 날짜와 시간을 다루는 방법은 Foundation 프레임워크의 NSDate, NSCalendar, NSDateFormatter, NSDateComponents 등을 사용하게 되므로 Objective-C의 그것과 약간의 문법 차이만 있을 뿐이다.

날짜 계산의 기본 개념

날짜 계산의 단위가 되는 객체는 NSDate이다. 이 클래스는 특정한 시점을 가리키는 정보를 담고 있다. 기본적으로는 기준일시로부터 몇초가 지났는지를 담아서 타임라인 상의 특정한 지점을 가리키게 된다.
Foundation에서 NSDate는 특정한 시점을 가리키는 포인터에 지나지 않는다. 다른 언어들의 date/datetime 객체와 달리 NSDate 클래스 자체로부터 이 날이 무슨 요일인지 등의 정보는 구할 수 없다. 그 이유는 Foundation은 특정 국가나 문화권에 종속되는 규격이 아니기 때문에 어떤 로케일을 적용하느냐에 따라서 한달의 길이라든가 그런 것들이 다를 수 있기 때문이다. 더 보기 »날짜와 시간을 다루기(Swift)