NSObject에 정의되어 있는 setValue:forKey에서 setValue가 nil일 경우 처리함.
Cocoa 3rd RaiseMan Application에서 사용.
다음은 책의 내용중 일부.

NSObject에 정의된 이 메서드가 예외를 발생시키기 때문에 사용자가 ExpectedRaise필드를 비워 두면 여러분의 객체는 예외를 발생시킬 것이다. 일반적으로 setNilValueForKey:를 재정의해서 인스턴스 변수를 어떤 기본 값으로 정한다. 이 경우 Person 클래스에 있는 이 메서드를 재정의하여 expectedRaise를 0.0으로 설정한다. 다음 메서드를 Person.m에 추가하자.


- (void)setNilValueForKey:(NSString *)key {

if ([key isEqual:@"expectedRaise"]) {

[self setExpectedRaise:0.0];

} else {

[super setNilValueForKey:key];

}


}


위의 메서드를 재정의 하지 않은 상태에서 예제의 Raise 입력부를 비우면 다음과 같이 예외가 발생한다.
스크린샷 2009-09-09 오후 2.52.06
어렵구만. 근디, 재미는 있구만. :-)

//

//  AppController.h

//  MakeDataSource

//

//  Created by JoonHo Son on 09. 9. 8..

//  Copyright 2009 JoonHo Son(s9712094@gmail.com). All rights reserved.

//


#import <Cocoa/Cocoa.h>



@interface AppController : NSObject {

IBOutlet NSTextField *textField;

IBOutlet NSTableView *tableView;

NSMutableArray *array;

}


- (IBAction)addTodo:(id)sender;

@end



//

//  AppController.m

//  MakeDataSource

//

//  Created by JoonHo Son on 09. 9. 8..

//  Copyright 2009 JoonHo Son(s9712094@gmail.com). All rights reserved.

//


#import "AppController.h"



@implementation AppController

#pragma mark -

#pragma mark override methods

- (id)init {

if (![super init]) {

return nil;

}

array = [[NSMutableArray alloc] init];

return self;

}


- (void)dealloc {

[textField release];

[tableView release];

[array release];

[super dealloc];

}


#pragma mark -

#pragma mark private methods

- (void)addTodo:(id)sender {

NSString *string = [textField stringValue];

if ([string length] == 0) {

NSLog(@"You must input TODO text");

return;

}

[array addObject:string];

[tableView reloadData];

[textField setStringValue:@""];

int count = [array count];

int i;

for (i = 0; i < count; i++) {

NSLog(@"%d contents : %@", i, [array objectAtIndex:i]);

}

}


#pragma mark -

#pragma mark delegate methods

- (int)numberOfRowsInTableView:(NSTableView *)tv {

return [array count];

}


- (id)tableView:(NSTableView *)tv

objectValueForTableColumn:(NSTableColumn *)tableColumn

row:(NSInteger)row; {

NSString *v = [array objectAtIndex:row];

return v;

}


- (void)tableView:(NSTableView *)tv

   setObjectValue:(id)object

   forTableColumn:(NSTableColumn *)column

  row:(int)row {

[array replaceObjectAtIndex:row withObject:object];

}

@end



5장 143쪽에서 awakeFromNib메서드 구현 부분에서 NSTableView에 나열되어 있는 NSSpeechSynthesizer의 목소리 목록에서 기본 목소리 값을 선택하게끔 하는 부분이 있다.

// 테이블 뷰가 화면에 나타날 때 기본 목소리가 선택되어야 한다.
NSString *defaultVoice = [NSSpeechSynthesizer defaultVoice];
NSArray *voices = [NSSpeechSynthesizer availableVoices];
int defaultRow = [voices indexOfObject:defaultVoice];
[tableView selectedRow:defaultRow byExtendingSelection:NO];
[tableView scrollRowToVisible:defaultRow];


이 부분을 책에 있는 그대로 입력하게 되면 다음과 같은 경고(warning)이 출력된다.

Xcode의 개발자 문서에서 해당 메서드를 검색하니 deprecated 되었단다. NSTableView의 selectedRow:byExtendingSelection 대신 권장되는 selectedRowIndexs:byExtendingSelection 이다.
deprecated된 기존의 메서드의 NSInteger 타입이 아닌, NSIndexSet 타입의 파라미터를 받게된다. 따라서 위의 경고가 출력된 부분을 다음과 같이 수정하면 이상없이 빌드 / 실행(디버그) 할 수 있다.

[tableView selectRowIndexes:
[NSIndexSet indexSetWithIndex:defaultRow] byExtendingSelection:NO];


그림 2

Xcode에서 #pragma 주석을 이용하면 위와 같이 메서드를 그룹핑하여 쉽게 이동할 수 있다.
하지만 특정 환경에서는 제대로 작동되지 않는 경우가 있다.

그림 3

이는 아래와 같이 Xcode > Preferernces > Code Sense에 있는 Sort list alphabetically 옵션을 체크 해제해 주면 된다.

그림 4

+ Recent posts