코코아 앱 따라하기 – 2

지난 글에서 만든 TTS 앱을 조금 개선해보자. 이 앱에는 Start, Stop 두 개의 버튼이 있다. 그런데 두 버튼은 모두 활성화된 상태가 된다. 따라서 앱이 텍스트를 읽고 있지 않은 경우에도 stop 버튼을 클릭할 수 있고, 또 앱이 텍스트를 읽고 있는 중간에 start 버튼을 반복적으로 클릭할 수 있게 된다.

이 상황을 멋지게 해결하기 위해서는 버튼의 활성화 상태를 그 때 그 때 바꿔주는 것이다. 즉 앱이 읽는 중간에는 start 버튼이 비활성화 되어야 하고, 앱이 읽고 있지 않을 때에는 반대로 stop 버튼이 비활성화 되는 것이다.

버튼의 활성화 상태

버튼의 활성화 상태를 변경하는 방법에는 두 가지 방법이 있다.  우리가 앱에 추가한 Push Button은 NSButton 객체이다. 버튼 클래스는 enabled라는 프로퍼티를 가지고 있다.(BOOL 타입이다.) 따라서 -setEnabled: 를 호출해서 코드 상에서 활성화 상태를 변경하거나, 인터페이스 빌더의 속성 인스펙터에서 Enabled 값을 변경해줄 수 있다. 단, 인터페이스 빌더에서의 조작은 앱의 초기 상태만 결정할 뿐, 런타임에 동적으로 속성값을 변경하기 위해서는 아웃렛을 통한 프로퍼티 액세스를 해야한다.

stop 버튼의 초기상태

일단 stop 버튼의 초기 상태는 비활성화 상태여야 한다. 프로젝트를 열고 MainMenu.xib 파일을 선택하자. stop 버튼을 클릭하고 오른쪽 인스펙터에서 그림과 같이 속성 인스펙터 탭을 선택하고 Enabled 값을 체크 해제한다.

이 변경의 효과는 인터페이스 빌더 내에서 바로 확인할 수 있다. 그리고 AppController의 코드 상에서 이 값을 제어하기 위해서는 무엇이 필요할까? 바로 해당 클래스 내에서 두 버튼에 대한 참조점, 즉 아웃렛이 필요하다.

AppController.m 파일로 가서 @interface 부분에, 이전 시간에 했던 것과 같이 두 개의 NSButton에 대한 IBOutlet 을 정의한다.

@property (weak, nonatomic) IBOutlet NSButton* startButton; @property (weak, nonatomic) IBOutlet NSButton* stopButton;

그리고 -startSpeaking:-stopSpeaking:이 호출될 때 각각의 현재 상황에 맞게 버튼의 활성화 여부를 업데이트한다.

- (IBAction)startSpeaking:(id)sender
{
  NSString *words = [self.field stringValue];
  if([words length] > 0) {
    [self.speech startSpeaking:words];
    [self.startButton setEnabled:NO];
    [self.stopButton setEnabled:YES];
  }
}

- (IBAction)stopSpeaking:(id)sender
{
  [self.speech stopSpeaking];
  [self.startButton setEnabled:YES];
  [self.stopButton setEnabled:NO];
}

그리고, 잊지 말아야 할 것. 새로 추가한 아웃렛이 있으면 반드시 인터페이스 빌더에서 연결하는 처리를 해야한다. 연결하는 방법은 지난 시간에 언급했으니 생략하겠다. 연결까지 마무리했다면 다시 빌드하고 실행해보자.

읽기가 끝나는 시점을 알아내기

문제가 있다. 텍스트를 입력하고  Start 버튼을 누르면, 의도했던 대로 두 버튼의 상태가 변경되면서 음성이 흘러나온다. 그런데 문제는 stop  버튼을 클릭하지 않으면 읽기가 끝나도 버튼의 상태가 원래대로 돌아오지 않는 것이다.

음성합성기가 읽기를 끝내는 시점에 AppController에게 무언가 메시지를 보내어 읽기가 끝났다는 것을 알려주어야 할 것이다. 그런데 음성 합성기는 애플이 만든 클래스이고, 이 클래스는 우리가 만든 AppController라는 클래스를 본적도 없을 것이다. 그러면 어떻게 이 문제를 해결할 수 있을까?

애플은 이런 문제를 해결할 수 있도록 델리게이트 패턴1을 사용하라고 알려준다. 음성합성기인 NSSpeechSynthesizer 클래스도 delegate라는 프로퍼티를 가지고 있다. 이 프로퍼티의 타입은 id<NSSynthesizerDelegate> 인데, id는 타입에 무관한 클래스를 의미하므로, “타입이 무엇이든 NSSynthesizerDelegate라는 프로토콜을 따르고 있는 클래스“이면 된다는 것이다. 프로토콜은 실제 구현없이, 어떠한 메소드를 가지고 있을 것이라는 약속이므로 음성합성기는 그 자신의 델리게이트의 구체적인 클래스를 알지 못하더라도 특정한 이벤트가 발생하는 시점에 델리게이트에게 메시지를 보내는 것이다.

NSSpeechSynthesizerDelegate에는 음성 합성기가 말하기를 완료하거나 중단했을 때 호출받는 -speechSynthesizer:didFinishSpeaking: 이라는 메소드가 정의되어 있다.  AppController가  이 프로토콜을 따르도록 하고 해당 메소드를 구현하여 이 문제를 해결해 보자.

먼저 AppController.h 파일을 열고 다음과 같이 클래스 선언 부분 뒤에 <NSSpeechSynthesizerDelegate>를 추가해준다.

@interface AppController: NSObject <NSSpeechSynthesizerDelegate>
//                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

그리고 다시 AppController.m 파일로 돌아와서, @implementation 블럭 안에 다음과 같이 해당 메소드를 구현해주면 된다.

#pragma mark - NSSpeechSynthesizerDelegate
- (void)speechSynthesizer:(NSSpeechSynthesizer*)sender 
        didFinishSpeaking:(BOOL)finishedSpeaking
{
  // 이 때 finishedSpeaking이 YES이면 완료, NO이면 중단인데
  // 여기서는 굳이 따질 필요가 없다.
  [self.startButton setEnabled:YES];
  [self.stopButton setEnabled:NO];
}

그리고 이 메소드를 작성했다면 -stopSpeaking:에서 버튼의 활성화 여부를 조정하기 위해 추가한 코드는 삭제하도록 한다. 이제 다시 앱을 빌드하고 실행해보자.  stop버튼을 눌러서 중단하거나, 읽기가 끝났을 때에는 항상 위 델리게이트 메소드를 호출받기 때문에 항상 자동으로 버튼의 상태가 원래대로 돌아오게 된다.

목소리 변경하기

목소리를 변경하는 기능을 어떻게 넣을 것인지를 상상해보자. 예를 들어 기존에 만들어 놓은 UI 하단에 목소리 리스트가 쭉 표시되고, 여기서 원하는 목소리를 클릭한 후에 Start 버튼을 클릭하면 그 목소리로 텍스트를 읽어주도록 하는 것이다. 목소리의 리스트를 표시하고, 특정한 행을 클릭했을 때 목소리를 바꾸는 일 역시 테이블 뷰(NSTableView)를 사용하면 구현할 수 있다. 그리고 테이블 뷰는 조금 전 사용한 델리게이트 패턴을 적극적으로 사용하는 코코아 컴포넌트의 전형적인 예이다.

이 기능을 추가하기 위해서 사용가능한 목소리의 목록을 얻어야 하고, 또 음성 합성기의 목소리를 변경하는 기능에 대해서도 조사해보아야 한다. NSSpeechSynthesizer의 클래스 레퍼런스 문서를 보면 다음의 두 메소드를 찾을 수 있다.

  • +availableVoices :: 사용가능한 모든 목소리의 식별자를 NSArray 타입으로 반환한다.
  • -setVoice: :: 목소리를 주어진 식별자의 것으로 변경한다.

이 때 주의해야 할 점은 목소리의 식별자는 내부적으로 문자열이기는 하지만, 범용 식별자 타입으로 macOS의 환경 설정에서 볼 수 있는 목소리 이름으로 표시되지는 않는다. 목소리의 식별자로부터 해당 목소리의 이름을 구하기 위해서는 +attributesForVoice: 를 사용해서 해당 식별자의 목소리의 속성이 담긴 사전을 얻고, 여기에서 NSVoiceName 이라는 키를 사용해서 목소리의 표시용 이름을 얻을 수 있다.

이러한 정보들은 모두 해당 클래스 레퍼런스를 통해서 알 수 있는 것들이니, 가능하면 직접 레퍼런스 문서를 항상 찾아보는 습관을 들이도록 하자.

사용 가능한 목소리의 리스트

AppController에 사용가능한 전체 목소리의 리스트를 참조하는 allVoices 라는 NSArray 타입의 프로퍼티를 하나 만들도록 한다. 그리고 표시용 이름을 위한 별도의 리스트 프로퍼티를 하나 만들도록 하자. AppController.m 의 @interface 부분에 다음을 추가한다.

이 부분은 사실 만드는 사람 마음인데, 테이블 뷰 데이터 소스 메소드에서 매번 표시용 이름을 만들어주어도 되고, 미리 표시용 이름 리스트를 만들어주어도 된다.

@property (copy, nonatomic) NSArray* allVoices;
@property (copy, nonatomci) NSArray<NSString*>* voiceNames;

각각의 프로퍼티의 초기화 코드는 다음과 같다.

- (NSArray*) allVoices
{
  if(!_allVoices) {
    _allVoices = [NSSpeechSynthesizer availableVoices];
  }
  return _allVoices;
}

- (NSArray<NSString*>*) voiceNames
{
  if(!_voiceNames) {
    NSMutableArray *vs = [NSMutableArray arrayWithCapacity:[self.voices count]];
    for (id voice in self.allVoices) {
      [vs addObject:[[NSSpeechSynthesizer attributesForVoice: voice] objectForKey:NSVoiceName]];
    }
    _voiceNames = [vs copy];
  }
  return _voiceNames;
}

테이블 뷰의 데이터소스/델리게이트

이제 AppController를 테이블 뷰의 데이터소스와 델리게이트가 되도록 준비하자. 먼저 AppController.h 파일로 이동해서 클래스 정의 부분에 NSSpeechSynthesizerDelegate외에 NSTableViewDataSource와 NSTableViewDelegate 프로토콜을 추가한다. 상속과 달리 프로토콜은 하나의 클래스가 여러 개의 프로토콜을 따르는 것이 가능하며, < … > 속에 각 프로토콜을 컴마로 구분해서 넣어주면 된다.

/// AppController.h
@interface AppController : NSObject <NSSpeechSynthesizer, 
  NSTableViewDataSource, NSTableViewDelegate>

데이터소스 필수 메소드

데이터소스는 테이블 뷰의 각 셀에 표시될 데이터를 제공해주는데 필요한 메소드들을 정의하고 있다. 여기에는 여러 메소드들이 있지만, 필수적으로 다음 두 개의 메소드가 필요하다. 참고로, NSTableView는 iOS의 UITableView와 그 원리는 거의 비슷한데 몇 가지 다른 점이 있다. 기본적으로 하나의 테이블에 여러 개의 칼럼이 존재할 수 있고, 각 셀을 구성하는 뷰가 아닌, 셀의 데이터가 표시해야 하는 값을 제공한다.

현재는 NSTableView도 UITableView처럼 각각의 셀을 뷰 기반으로 구성할 수 있다. 이 때 iOS와 같이 각 셀을 표현할 뷰를 제공하는 역할은 데이터소스가 아닌 델리게이트가 담당한다.

전통적으로 NSTableView는 레이아웃 용도가 아닌 엑셀과 비슷한 값 위주의 표를 구현하는데, 사용되어 왔음을 염두에 두자. 이 예제에서는 뷰 기반이 아닌 셀 기반의 테이블 뷰를 사용할 것이다.

  • -numberOfRowsInTableView:  : 테이블 뷰 내의 행의 수를 결정한다.
  • -tableView:objectValueForTableColumn:row: :각 열과 행에서 표시할 값을 제공한다.

이제, 테이블 뷰 데이터소스 메소드들을 작성해보자. 테이블 뷰의 행 수는 allVoices 배열의 원소의 개수와 같으며, 여기서 사용할 테이블 뷰는 단일 행이므로 칼럼에 상관없이 row에 맞춰서 해당 위치의 voiceNames 원소를 리턴하면 된다.

#pragma mark - TableView DataSource

- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
{
  return [self.allVoices count];
}

- (id)tableView:(NSTableView*)tableView
  objectValueForTableColumn:(NSTableColumn*)tableColumn
  row:(NSInteger)row
{
  return [self.voiceNames objectAtIndex:row];
}

이제 화면에 테이블 뷰를 추가해보자. 인터페이스 빌더에서 윈도 크기를 아래로 늘리고 테이블 뷰를 하나 윈도 위로 드래그해서 추가한다.

위와 같이 대략적인 크기를 조절한 다음에, 테이블 뷰를 선택한 상태에서 속성 인스펙터를 보자. 이 때 주의해야할 점이 있다. 기술적으로 테이블 뷰는 스크롤뷰와 클립뷰 내부에 들어있는 상태이다. 따라서 테이블 뷰를 선택하기 위해서는 테이블 뷰 영역을 클릭하여 선택하는 것으로는 (클릭을 해 나가면서 그 내부의 요소를 점차 선택하게 되지만 알아보기 힘들다.) 조작이 어렵기 때문에 화면 왼쪽의 독을 늘려서 독에서 계층 구조를 통해서 테이블 뷰를 정확하게 선택해야 한다.

테이블 뷰를 제대로 선택했다면 속성 인스펙터는 아래와 같이 보일 것이다. 이 중에서 Content Mode 값은 “Cell Based”로 변경하고 열의 수는 1로 조정한다. 그런 다음 테이블 뷰에서 첫 번째 열의 폭을 충분히 큰 크기로 변경해둔다.

그리고 테이블 뷰의 칼럼 헤더 부분을 더블클릭해서 레이블을 Voice라고 변경해주자.

 

이제 아웃렛연결이 필요하다. NSTableView에는 delegatedataSource가 이미 IBOutlet으로 정의되어 있다. 따라서 테이블 뷰로부터 AppController로 연결을 만들어야 한다. 이 역시 캔버스 상에서는 선택이 어려우므로 독을 이용한다. 독에서도 ctrl + 드래그를 이용해서 아래와 같이 AppController로 연결할 수 있다. 이 때 delegate와 dataSource를 모두 연결해야 하므로 두 번 연결해야 한다.

이제 앱을 빌드하고 실행해보자. macOS가 지원하는 음성의 종류가 이렇게 많았다니!하면서 깜짝 놀랄 것이다. 하지만 모든 목소리가 한국어를 말하지는 않는다. 한국어로 말하는 음성은 Yuna를 비롯한 세 개 음성이며, 그외에는 영어 및 그외 각 언어에 대응한다. (숫자를 써서 읽도록 해보면 그 목소리에 해당하는 언어로 읽는다.)

하지만 아직 목소리를 변경하는 기능은 당연히 동작하지 않는다. 어떻게 이것을 처리할 수 있을까? 테이블 뷰에서 특정한 행을 클릭하면 해당 행이 선택된다. 이 것은 테이블 뷰의 ‘선택된 행(selection)이 변경되는 사건‘이다. 테이블 뷰는 역사적인 여러 이유로 이 이벤트의 동작은 타깃 액션이 아닌 노티피케이션 기반으로 처리한다. 즉 AppController가 특정한 테이블 뷰의 델리게이트가 되면 테이블 뷰는 자동으로 자신의 델리게이트가 테이블 뷰가 발송하는 노티피케이션을 수신하도록 등록하게 된다.

따라서 테이블 뷰의 선택영역이 변경되면 델리게이트에서는 -tableViewSelectionDidChanage: 라는 메소드가 호출된다. 이 메소드의 인자는 노티피케이션 객체인데 이 객체의 object라는 프로퍼티가 바로 노티피케이션을 발송한, 즉 클릭이 일어난 테이블 뷰가 된다. 이를 이용해서 테이블 뷰를 판별하는 방법도 있지만, 보통은 AppController가 테이블 뷰에 대한 아웃렛을 가지도록 하는 것이 더 선호된다. (어차피 object 가 바로 그 테이블 뷰인지 확인하는 절차가 필요하기 때문이다.)

AppController.m 상단의 인터페이스 부분에 다음과 같이 아웃렛을 하나 더 추가한다.

@property (weak, nonatomic) NSTableView* tableView;

그리고 다음과 같이 델리게이트 메소드를 작성하자.

#pragma mark - TableView Delegate

-tableViewSelectionDidChange:(NSNotification*)notification
{
  NSInteger i = [self.tableView selectedRow];
  [self.speech setVoice:[self.allVoices objectAtIndex:i]];
}

그리고 절대 빼먹으면 안되는 과정! AppController → NSTableView 로의 아웃렛 연결이다. 조금 전과 동일하게 독에서 연결해준다. 연결까지 끝났으면 다시 빌드하고 실행해보자. 이번에는 텍스트를 입력하고 start를 클릭해보고, 다시 다른 목소리를 선택해서 start해보자. 목소리가 바뀌는 것이 확인되는가?

기본 목소리가 보이게 하기

이 앱에서 한가지 문제가 있는데, 만약 여러분의 맥이 한국어로 설정되어 있다면 기본 목소리는 Yuna가 된다. 그런데 목소리의 리스트는 기본적으로 알파벳순으로 정렬되어 있다. (참고로 이건 테이블 뷰가 자동으로 정렬해주는 것이 아니라, 처음부터 목소리 리스트가 이 순서대로 만들어져 있기 때문이다.) 문제는 다른 목소리를 선택해보기 전까지는 테이블 뷰내의 Yuna 항목은 선택되어 있지를 않다. 또, Yuna는 알파벳순으로 매우 뒤쪽에 위치하기 때문에 처음부터 보이질 않는다.

앱이 시작되었을 때 기본 목소리가 선택된 상태로 테이블 뷰 내에 보인다면 좋겠다. 이 부분을 처리해보겠다.

앱이 런칭하는 과정에 nib 파일을 로딩하는 과정이 포함된다고 했다. nib 파일 로딩이 끝나서, 해당 파일 내의 객체 그래프 복원이 완료되면, 인터페이스 빌더에서 추가된 모든 객체는 코코아 런타임으로부터 -awakeFromNib 이라는 메시지를 받게 된다.우리의 AppController 역시 인터페이스 빌더를 통해서 생성/초기화되기 때문에 화면이 만들어진 직후에 이 메소드를 호출받을 것이다. 따라서 이 메소드를 이용해서 테이블 뷰에서 기본 목소리가 선택된 상태로 있게 하고, 화면에 보이게도 해보자.

  • nib 파일 내의 모든 객체는 화면이 구성되는 시점에 -awakeFromNib 이라는 메소드를 받게 된다.
  • 음성합성기의 기본 목소리는 defaultVoice 라는 클래스 메소드에 정의되어 있다.
  • NSTableView는 -selectRowIndexes:byExtendingSelection: 이라는 메소드를 통해서 선택 영역을 코드상에서 변경할 수 있다.
  • -scrollRowToVisible: 을 통해서 n 번째 행이 화면내에 들어오도록 스크롤 할 수 있다.

이 내용을 종합해서 아래와 같은 코드를 추가해본다.

#pragma mark - ETC
- (void)awakeFromNib
{
  id currentVoice = [NSSpeechSynthesizer defaultVoice];
  NSInteger i = [self.allVoices indexOfObject:currentVoice];
  NSIndexSet *indexes = [NSIndexSet indexSetWithIndex:i];
  // 테이블뷰에서 행 선택
  [self.tableView selectRowIndexes:indexes byExtendingSelection:NO];
  // 스크롤
  [self.tableView scrollRowToVisible:i];
}

자 이제 다시 앱을 빌드하고 실행해보자. 아래와 같이 Yuna 의 목소리가 선택된 것이 보일 것이다.

여기까지해서 기본적인 코코아 앱을 만들고, 컨트롤러를 작성해서 상태에 따라 UI를 제어하는 기본적인 동작과, 테이블 뷰를 기본적인 레벨에서 구성하는 방법을 살펴보았다. 특히 델리게이트 패턴은 이렇게 기본적인 앱에서도 여러차례 등장할 만큼 중요한 패턴이라는 점도 알게되었다.

연재를 마무리하는 다음 글에서는 이 TTS앱을 다시 처음부터 재작성해 볼 것이다. 그러면서 iOS에는 없는 코코아바인딩이라는 기술을 사용해서 컨트롤러의 상태와 UI를 양방향으로 코드 없이 연결하는 방법에 대해서 살펴볼 예정이다. 코코아 바인딩을 사용하면 버튼의 상태를 제어하기 위한 메소드 호출 및 프로퍼티 선언을 생략할 수 있으며, 극단적으로는 테이블 뷰와 관련된 코드 역시 대부분 제거할 수 있음을 보일 예정이다.

 


  1. 프로토콜에 관한 글을 참고하자. 

Mac 기초에서 활용까지 – 강좌 진행 알림

오늘은 좀 쑥스럽지만, 제가 진행하는 강좌 홍보 하나 하려고 합니다.

일시

  • 1회 – 2011년 3월 19일 (토요일) 19:00 ~ 20:30
  • 2회 – 2011년 3월 26일 (토요일) 19:00 ~ 20:30

장소

  • 현대백화점 문화센터 무역센터점 (삼성동 코엑스몰 링코 옆에 있습니다.)

수강신청 및 문의

맥을 구입하고서도 어찌해야 할지 몰라 답답하신 분들. 맥을 어째 쓰고는 있지만 제대로 쓴다는 느낌이 안드시는 분들. 맥이 이뻐서 샀는데 전원을 켜면 도대체 뭘 어떻게 해야할지 모르는 분들을 위해 맥, OSX의 기본 사용방법과 이를 통한 활용법까지 제시해보려고 합니다. 2회라는 다소 적은 분량으로 꽤 빠듯할지도 모르겠지만 저녁시간이라 Q&A는 넉넉하게 진행할 수 있을 듯 합니다.

2회에 걸쳐 대략 다음과 같은 내용들을 다뤄볼 생각입니다.

  • OSX가 windows와 다른 점들
  • 키보드, 트랙패드 활용법
  • OSX만의 편리한 기능 100% 활용법 알아보기
  • 메일/일정/연락처 설정하기
  • 기본 어플 100% 활용하기
  • 올바른 맥북 관리 방법
  • Mac용 추천 어플리케이션 소개 및 기본 활용 방법

맥을 구입하신지 얼마 안되시는 분들, 그리고 맥을 사려고 계획하고 계신 분들은 들으시면 꽤 도움이 되리라고 자신합니다. (제 블로그를 보셔서 아시겠지만, 저 설명하나는 무지 잘하거든요)

모쪼록 많은 성원 부탁 드립니다.

추가 공지

당일 현장에서 접수하는 것도 가능합니다. 다만, 대략이나마 수강 인원 규모를 파악하는데 도움이 될까해서 수강 의사 있으시면 아래 댓글로 남겨주시면 감사하겠습니다. 혹은 트위터 @sooopd로 맨션 주셔도 좋습니다.

20110302 :: 맥북 프로 단상

새로운 맥북 프로

애플에서 새로운 맥북 프로를 드디어 발표했습니다. 여러 개선점들과 함께 더욱 강력해진 성능으로 말이지요. 애플 홈페이지에서 확인할 수 있는 정보는 대략 아래와 같습니다.

  • i7 쿼드코어 프로세서 탑재 (13” 모델은 i5)
  • AMD Radeon 6K 시리즈 그래픽 프로세서 탑재 (13” 모델은 Intel HD Graphics 3000)
  • 4GB 램 기본 탑재
  • Thunderbolt 단자
  • SDXC 메모리카드 슬롯
  • Audio IN/OUT 단자 (맥북화이트에는 AU IN이 없어요 ;ㅁ;)
  • 배터리 지속시간 최대 7시간 (잉? 이전 모델은 10시간 아니었나요)

Macbook Pro from apple.com

애플이 엔비디아와 결별하고 라데온 계열 그래픽 프로세서를 탑재한 첫 제품이로군요. 항간에 들리는 소문에는 맥북 화이트를 더 이상 생산하지 않을 거란 계획이라는 말도 있었는데, 이 부분은 아직 키노트를 보진 못해서 확인을 못했습니다. 이에 대한 제 생각은 애플의 맥북 프로에 대한 컨셉은 데스크톱을 대체하는 노트북이라는 개념으로 접근해야 할 듯 합니다. 여전히 묵직한 중량감은 매우 튼튼하기는 하나 mobility를 우선시하는 제품은 아니라는 생각입니다. 물론 애플은 이에 대해 맥북에어라는 걸출한 제품을 대신 출시한 바가 있지요.

어쨌거나 이번 새 모델의 출현은 맥북프로의 하드웨어적 성능을 기존 맥북과 비교하여 갑절 이상으로 끌어올리는 첫 걸음이라 할 수 있겠습니다.다만 늘 그렇지만 부품 하나하나의 스펙이 PC의 전체 성능을 보여주는 것은 아닙니다. 한편으로는 이런 정도의 부속품을 다른 메이커에서 만든다하더라도 맥북과 퍼포먼스를 비교한다면 차이가 날 수도 있다는 뜻입니다. (그리고 윈도 계열과는 다르게 OSX Leopard는 64비트로 동작하는 OS입니다.)

그럼에도 불구하고

그럼에도 불구하고 이 새로운 맥북 프로가 애플러들을 얼마나 만족시킬지는 미지수입니다. 가격장벽이 너무 큰 것 같아요. “강력해진” 성능을 체감하고 싶다면 최소한 15인치 이상의 모델을 사용해 줘야 하고 (아 전 15인치 이상 맥북들은 너무 허전해 보여서요 ㅠㅠ) 그만큼 가격부담은 커집니다.  OSX의 특성상 별도의 그래픽 카드가 보여주는 퍼포먼스는 내장 그래픽 카드를 보유한 가장 작은 모델들과는 확연히 차이가 날 수 밖에 없을 듯 합니다.

또한 이러한 성능을 극대화하기 위해서는 HDD보다는 SSD를 다는게 유리한데, 여전히 SSD의 가격은 너무나 비쌉니다.

한가지 가장 마음에 걸리는 것은 화면 해상도 입니다. 13인치 모델의 경우 ‘레티나’로 알려진 고해상도 디스플레이가 탑재될 것이라는 예상이 팽배했었는데, 1280×800 해상도를 고수하는 군요. 심지어 11인치 맥북에서도 1440×900의 고해상도 디스플레이를 사용했다는 점에서 약간 의외입니다.

썬더볼트 단자에 대해서도 아직까지는 시기 상조가 아닐까 싶습니다. 물론 HD 동영상을 실시간으로 편집하는 부분에 있어서는 유용한 부분이 있지만 아직까지 그 외의 부분에서는 얼마나 효용이 있을까 싶기도 하고 (외장 SSD와 연결하면 효과를 볼 수 있으려나요) 썬더볼트를 지원하는 외부 기기도 별로 많지 않습니다. (USB 젠더를 통해 연결한다고 그만큼 전송 속도가 빨라질지는 의문이구요)

아무튼 이런 전차로 새로운 맥북 프로에 대한 뽐뿌는 사전에 블록이 가능했다는 그런 이야기입니다.

20101111 :: 맥북에어 사용기

두둥 탁!

오늘 드디어 주문한 맥북 에어가 도착했습니다. 와우.

하드웨어적인 특성도 있고, 또 사용 자체가 제가 메인으로 쓰기 보다는 여자친구가 주로 쓰게 될 물건이라 오늘은 이것 저것 설치해서 테스트해 보고, 또 사용하는데 무리가 없도록 세팅하는 수준으로 가볍게 만져보았습니다. 어쨌거나 잠깐 사용해 보는 맥북에어에 대한 소감을 몇 자 적어보도록 하겠습니다.

가볍다

새 맥북 에어는 11.1인치 제품입니다. 어댑터를 제외하고는 1킬로그램 정도 무게가 나갑니다. 실제로 외관이 매우 얇고 (힌지 부분이 조금 두껍고 갈수록 얇아지는 모양입니다.) 끝부분이 약간 둥글려져 있는 관계로 실제 가지고 다닐 때의 무게는 무척 가볍게 느껴집니다. 13인치 맥북 화이트가 엄청 육중하게 느껴지는 정도입니다. (실제로 맥북 화이트는 육중한 무게를 자랑합니다.)

또한 하드웨어 자체에 하드 디스크가 없기 때문에 조용하고 열도 비교적 적게 날 뿐더러 가지고 다닐 때 어느 정도 충격을 받아도 안전합니다. (그렇다고 허공에 던지면 이름처럼 가뿐히 내려 앉는 그런 기능은 아직 없고 앞으로도 없을 예정입니다. 주의해 주세요) 게다가 어댑터의 경우에도 기존 맥북의 어댑터보다 작은 아이폰용 충전 어댑터 정도의 크기입니다. 하루 종일 쓸 요량으로 가방에 맥북에어와 어댑터를 같이 가지고 다녀도 하등 무게감에 무리가 없습니다.  1 kg 이라고 해도 어지간한 중철지보다는 가볍게 느껴집니다. (아마 실제 중량도 더 가볍지 않을까 싶습니다.)

이런 전차로 휴대성 하나는 태블릿을 제외하고 현존하는 노트북 및 넷북 중에서는 최강이 아닐까 싶습니다.

고해상도 디스플레이

11인치의 작은 화면이지만, 디스플레이자체는 매우 고해상도를 지원합니다. 첫 시동 후 화면을 열었을 때의 느낌은 매우 시원했습니다. 실제로 문서 작업이나 웹 서핑 등에서 그다지 답답함을 느끼기 힘듭니다. 실제로  PPT  작업이나 그래픽 작업을 하지 않는 이상에는 이만한 화면에서 불편함을 느끼기도 힘들 듯 합니다. 고해상도 디스플레이의 품질도 매우 또렷하여, 맥북 화이트의 느낌이 매우 벙쪄보일 정도입니다. 디스플레이 부분은 (그래픽 성능은 차치하고서라도) 매우 만족스럽습니다.

풀사이즈 키보드

애플 노트북의 키보드는 아이솔레이트 방식을 취하고 있어서 오밀조밀한 느낌을 주면서도 의외로 오타가 적습니다. 실제로 키 배열은 오밀조밀하나 풀 사이즈 키보드와 거의 비슷한 키 간 간격을 가지고 있기 때문에 타이핑에서도 그닥 불편함을 느끼기는 힘듭니다. 물론 이 부분은 맥을 이전에도 사용하던 제 주관적인 입장이니, 사람에 따라 다를 수도 있습니다만, 지난 번 소개해 드린 아이락스 제품을 사용해 본 여자친구도 기존 노트북 키보드보다 훨씬 더 편하다는 이야기도 있었습니다.

빠르고 가볍다.

맥북에어로 게임이나 그래픽 작업을 하려고 하시는 분은 (굳이 한다면 못할 것도 없지만) 없겠지만, 일반적인 인터넷 서핑 및 워드 프로세싱을 하는 대는 더할 나위 없는 성능을 보여줍니다.  SSD 를 채택하고 있어서 부팅 속도도 놀랍습니다. 전원 버튼을 누르면 2초 이내에 상큼한 시동음이 들리며 금새 로그인 화면이 표시됩니다. (자동 로그인 설정을 안 했기 때문에 부팅이 완료되는 시간까지는 제대로 신경써서 확인을 못했습니다만 기존  HDD  기반 노트북보다는 월등히 빠른 부팅을 보여줍니다. 아이패드의 부팅은 얼마나 걸리는지 사뭇 궁금해지는 군요. 또한, 평상시에도 전원을 굳이 끄고 다닐 필요가 없기 때문에 (뚜껑만 닫으면 꺼진 거나 다름 없는 상태이며 하드디스크가 충격으로 파손될 위험이 없습니다. 키노트에서는 이미 대기 상태로는 한달도 버틸 수 있다고 하였지요) 작업시에는 뚜껑만 열면 모든 준비가 완료됩니다.

아쉬운 점

애플의 제품은 대체로 기대한만큼 혹은 그 이상의 만족감을 주긴 하지만 그렇다고해서 아쉬운 점이 없는 것은 아니지요. 먼저 전원 버튼이 키보드 상단에 기능키와 함께 붙어 있는데 이게 무척이나 터프한 느낌을 줍니다. 개인적으로는 깔끔하게 재단된 금속 스위치를 생각했는데 말이지요.

그리고 걱정했던 64기가의 용량은 뭐라 말하기는 좀 힘듭니다. 음악이나 비디오, 사진을 대량으로 저장해서 가지고 다니지만 않는다면 문서등의 자료로는 충분히 사용할 수 있는 용량이라고 생각됩니다. 맥북 화이트의 하드 디스크는 설치 파일을 그대로 저장해놓은 자료와 예전에 쓰던 전화기에 들어있던 자료들, 그리고 음악과 영화감상을 위한 동영상 파일들이 대부분이라 비교하기는 좀 그렇군요.

유선 네트워크 포트가 없는 것은 조금 아쉽습니다. 사무실에서 무선랜을 사용하지 않는 곳이라면 꼼짝없이 로컬로만 사용해야 하고 그 경우에는 130만원짜리 디지털 타자기가 될 공산이 큽니다. 물론 두께나 크기 때문에 빠진 걸 감안하더라도 여전히 무선랜이 안되는 곳은 종종 있기 때문에 이 부분은 조금 아쉬운 부분입니다. (아이폰이 있다면 테더링으로 해결할 수도 있습니다. ㅋㅋㅋ)

총평

제 경우에는 굉장히 만족스러운 제품입니다. 휴대성이나 디자인면에서는 최고라고 평하고 싶네요. 맥북에어에 탐을 내신다면 ‘어디에 쓸 것인가’하는 것을 명확하게 해 보시고 생각해보시면 될 것 같습니다. 실제 컴퓨팅 파워는 그리 기대를 안하기 때문에 제 경우는 만족하는 것이 아닌가 싶습니다. 사실, 범용 기기인 컴퓨터에 대해 ‘용도를 특정’하는 것이 어찌보면 좀 우습기도 하지만 그렇다고 해도 괴물급 사양 노트북을 집에 마련해 놓고 데스크톱 대용으로 쓰는 것은 어찌보면 이런 기기를 사는 것 보다도 더 돈 낭비가 아닐까 하는 생각도 듭니다.

(당근, 이 글은 맥북에어에서 작성되었습니다. 메롱 )