Objective-C Tips from WWDC 2013

애플 WWDC2013, Session 228에 소개된 내용들 중 iOS나 Mac 개발시 자주쓰일만한 팁들을 추려내서 간단히 정리해보았다. 서브스크립팅(subscripting) 사용하기 Modern Objective-C 문법이 적용되면서 NSDictionary나 NSArray같은 foundation 데이터 구조객체들은 서브스크립팅을 이용하여 다음과같이 간결하게 작성이 가능하게되었다. [myArray objectAtIndex:3] -> myArray[3] [myDictionary objectForKey:@"key"] -> myDictionary[@"key"] 사용자가 만든 커스텀 클래스에도 서브스크립팅을 위한 set/get메서드만 잘 정의해두면 훨씬 더 간결한 프로그램 작성이 가능하다. MyCustomArray 클래스에 - (id)objectAtIndexedSubscript:(NSUInteger)idx; - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx; 위 두가지 메서드 구현시 다음과같이 배열처럼 인덱스로 바로 접근 가능 ...

2014년 5월 19일 · 2분 · 345단어

iOS 타이틀레이블 위치 강제 조정

iOS 네비게이션바(Navigationbar)의 좌우 툴바버튼이 폭 균형이 맞지 않을경우, 타이틀 레이블의 중앙 정렬이 한쪽으로 쏠리면서 좋지 않게 보인다. 이를 방지하여 레이블을 강제로 중앙 정렬하기 위해서 다음과 같은 방법들이 있으니 상황에따라서 적절히 적용하면 된다. 방법1: viewWillAppear:에서 titleView를 hide했다가 viewDidAppear에서 titleView의 위치를 원하는대로 설정 후 unhide 이경우 타이틀레이블의 트랜지션 애니메이션은 보이지 않게되니 네비게이션 push동작이있는 상황에서는 쓰지 않는것을 추천한다. 방법2: 네비게이션바의 타이틀뷰에 UILabel을 상속받은 CustomTitleLabel를 set. navigationItem.titleView = [[CustomTitleLabel alloc] init]; 네비게이션바의 레이아웃이 조정될때 자동으로 titleView의 frame값도 같이 조정되게 되는데, 기본적으로 중앙정렬을 하는 동작이 일어나게 된다. 해당 동작이 일어나는 것을 막기위해 CustomTitleLabel의 setFrame: 메서드를 오버라이드하여 setFrame:의 동작을 마음대로 조정한다. ...

2014년 5월 19일 · 1분 · 133단어

NSView debug drawing

NSView debug drawing NSView의 레이아웃 계층(layout hierachy)이 어떻게 구성되어있는지 비주얼라이즈해서 보고싶은경우 NSShowAllViews Preference값을 YES로 셋팅해준 후 어플리케이션을 다시 실행하면 된다. 터미널의 커맨드라인에서 다음 명령을 실행하면 해당 번들ID를 가진 앱의 설정값을 변경 가능하다. defaults write com.your.apps.bundlename NSShowAllViews YES Constraint기반의 레이아웃이 어떻게 적용되고있는지는 NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints을 이용하여 볼 수 있다. defaults write com.your.apps.bundlename NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints YES 반대로 다시 끄고싶으면 값을 NO로 바꾸어 재실행한다. Preference 값을 지정하는 다른 방법 앞서 소개한것 처럼 커맨드라인에서 NSUserDefaults 키값을 강제로 바꿔줄 수도있지만, Xcode상에서 이 값을 scheme에 설정하여 실행할때마다 오버라이드하여 사용하는 방법 또한 편리하다. Xcode의 Edit Scheme 메뉴로 들어가서 ‘Arguments’ 탭의 Arguments Passed On Launch 항목에 아래 스크린샷처럼 -NSShowAllViews YES 라고 추가해 주면 해당 스킴에 의해 빌드되서 실행되는 어플리케이션의 경우 해당 값이 항상 설정되어 실행된다. ...

2014년 5월 10일 · 1분 · 114단어

NSButton으로 이미지버튼 만들기

맥OS의 코코아(cocoa)프레임웍에서 NSButton을 이미지버튼(image button)으로 사용할때 아래 속성을 제대로 설정하지 않으면, 클릭했을때 투명이미지 처리가 제대로 안되는 문제가 발생한다. [button setButtonType:NSMomentaryChangeButton]; iOS의 UIButton에서 커스텀 버튼을 만들고 이미지를 설정해서 사용하는 것처럼 동일하게 NSButton을 사용하려면 다음과같이 사용하면된다. NSButton* button = [[NSButton alloc] initWithFrame:NSMakeRect(0 , 0, 30,20)]; [button setImage:[NSImage imageNamed:@"bg.png"]]; [button setAlternateImage:[NSImage imageNamed:@"bg_highlighted.png"]]; // button의 frame과 image사이즈가 다를경우 scaling 설정 [button.cell setImageScaling:NSImageScaleAxesIndependently]; [button setBordered:NO]; [button setButtonType:NSMomentaryChangeButton]; [self.view addSubview:button]; strechable NSImage iOS에는 이미지 내부의 특정 영역만 늘려주는 UIImage내의 stretchableImageWithLeftCapWidth:(iOS5 미만) 나 resizableImageWithCapInsets:(iOS 5 이상) 메서드를 이용하여 나인패치(nine-patch) 버튼을 만들 수 있었다. 해당 메서드는 현재 Mac OS에 포함되어있지않은데, iOS와 비슷한 형태로 구현을 해놓은 라이브러리가 있어서 소개한다. ...

2014년 5월 8일 · 1분 · 127단어

NSSplitView 구현 팁

맥용 코코아(Cocoa) 어플리케이션을 만들다보면 NSSplitView가 많이 사용되는데 이와 관련된 몇가지 팁들을 소개해본다. NSSplitView 디바이더(divider) 숨기기 NSSplitView를 서브클래싱 한 후 다음 메서드를 오버라이드하여 디바이더의 두께를 0으로 만들어 숨길 수 있다. -(CGFloat)dividerThickness { return 0; } 디바이더를 숨겨도 리사이즈가 가능하게 만들기 위와같이 디바이더의 두께를 0으로 지정한경우, 디바이더의 영역이 없기때문에 스플릿뷰를 리사이즈하는 동작이 불가능하게된다. 이때 디바이더 대신 특정영역을 지정하여 해당 영역을 사용자가 마우스로 클릭을 할경우 리사이즈되도록 할수있다. 아래의 delegate를 구현한 후 divider index에 맞춰서 클릭가능 영역을 지정하여 리턴해주면 된다. ...

2014년 5월 8일 · 1분 · 192단어

싱크로나이즈드 스크롤 구현하기

여러개의 NSScrollView를 사용할때 스크롤뷰들 중에서 하나만 스크롤해도 여러개의 스크롤 뷰가 동시에 따라 움지이는 싱크로나이즈드 스크롤(Synchronized scroll)을 구현하기 위한 방법을 소개한다. 스크롤 이벤트 감지 NSScrollView의 스크롤이벤트를 받아오기 위해서는 NSScrollView가 가진 contentView의 바운드가 변하는 것을 모니터링 하면된다. 다음 코드로 스크롤뷰가 가진 contentView의 bound변화 notification을 활성화 한 후 [[scrollView contentView] setPostsBoundsChangedNotifications:YES]; 노티피케이션센터에 NSViewBoundsDidChangeNotification에대한 옵저버를 등록하여 이벤트를 받아온다. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentDidScroll:) name:NSViewBoundsDidChangeNotification object:contentView]; NSScrollView를 특정 포인트로 스크롤 하기 앞에서 viewBound의 변화에대한 노티피케이션을 받았을때 변화된 bound를 불러와서 다른 스크롤뷰를 강제로 스크롤 시키면 된다. ...

2014년 5월 8일 · 1분 · 102단어

NSTimer 백그라운드 진입시 동작 분석

iOS에서 특정 시간주기로 특정 메서드을 호출하기위해 NSTimer를 사용하게 된다. 이때 앱이 백그라운드(background)로 진입할때, 그리고 잠시 후 다시 포어그라운드(foreground)로 돌아올경우 예약되어 사용중인 NSTimer가 어떻게 동작하는지 살펴보도록 하자. 기본적으로 타이머의 실행 주기는 타이머가 등록되는 시간을 기준으로하여 **고정 간격으로 실행(fire)**된다. 이는 앱이 백그라운드로 진입하면서 잠시 타이머가 정지한다 해도 영향을 받지않고 동일하게 적용된다. 백그라운드 진입시 NSTimer는 언제 정지하는가? 앱이 백그라운드로 진입하면서 AppDelegate의 applicationDidEnterBackground:가 호출될 때, 특별히 명시적으로 backgroundTask를 등록하지 않은경우에는 백그라운드 진입과 동시에 타이머는 정지하게된다. ...

2014년 4월 24일 · 2분 · 226단어

GCD 튜토리얼

지난 포스트에서 블록(block)의 동작에 대해서 분석해보았는데, 이런 블록들을 이용하여 멀티스레드 프로그래밍을 손쉽게 할 수 있는 방법을 제공하는 GCD (Grand Central Dispatch) 에대해 알아보도록 하자. 본 포스트의 내용은 1 의 내용을 요약하면서 추가적으로 유용한 내용들을 GCD 애플 문서2에서 발췌하여 정리한 내용임을 밝힌다. 디스패치 큐의 종류 컨커런트 디스패치 큐 (concurrent dispatch queue) : 해당 큐 내의 작업들간에 실행 순서는 보장할 수 없다. dispatch_queue_t queue = dispatch_queue_create(“com.letmecompile.concurrentQueue”, DISPATCH_QUEUE_CONCURRENT); 시리얼 디스패치 큐 (serial dispatch queue): 해당 큐 내의 작업들은 큐에 추가된 순서로 하나씩 수행됨을 보장한다. 때문에 시리얼큐는 하나 생성될때마다 스레드가 하나 더 생기기때문에 과도하게 많은숫자를 하면 성능에 문제가 있을 수 있다. dispatch_queue_t queue = dispatch_queue_create(“com.letmecompile.serialQueue”, NULL); ...

2014년 3월 18일 · 4분 · 819단어

Xcode LLDB 디버깅 테크닉

Xcode에 기본으로 내장되어있는 디버거(debugger)인 LLDB는 기존에 가장 많이 사용되던 gdb보다 많은 유용한 기능들을 갖고있다. LLDB 명령어 분석기에는 파이썬(Python) 인터프리터가 내장되어있어서 script 명령어로 파이썬 코드들을 사용할 수 있다. 이 또한 반대로 모든 LLDB API들이 SB(Scripting Bridge) 를 통해서 Python에서도 사용이 가능하도록 되어있다.[^1] 이러한 파이썬과의 연계를 통해서 Xcode 디버깅을 진행 할때 더 세분화된 조건들을 정의하여 브레이크포인트(breakpoint)에 지정할 수 있게되었고, 이런 조건에따라 액션 수행, 브레이크포인트 무시/진행여부 결정 등의 다양한 동작이 가능하다[^2]. 본 글은 애플의 “Advance Debugging with LLDB (WWDC 2013, Session 413)” 발표자료[^3]를 토대로 요약 및 정리한 내용이다. ...

2014년 2월 28일 · 4분 · 665단어

KVO 컨텍스트 표현을 위한 자기참조 포인터

다음과같은 포인터변수에 자신의 변수명 그대로 자기자신의 주소값을 할당하는 특이한 변수선언을 처음 볼 경우 당황스러울 것이다. void *myVariableName = &myVariableName 하지만 이는 자기참조 포인터 혹은 유니크 컨텍스트 포인터(unique context pointer)라는 이름으로 불리는 엄연히 C/C++/Obj-C에서 유효한 문법이다. 이를 이용하여 컴파일타임에 유니크한 포인터값을 생성할 수 있어서 컨텍스트 구분을 위한 변수를 표현할때 매우 유용하게 사용될 수 있다. 해당 컨텍스트변수가 해당 파일 내에서만 사용할 경우. .m파일에 다음과같이 선언하면된다. static void *MyContext = &MyContext; 만약 다른 파일에서도 사용되는 컨텍스트라면, ...

2014년 2월 20일 · 2분 · 229단어