OS X 10.5에는 Ruby(v 1.8.6)와 Rails(v 1.2.6)가 설치되어 있습니다. Ruby를 이용하여 Cocoa Application을 만드는 방법을 간단히 알아 보겠습니다. 실제 테스트를 해보니 Ruby와 Cocoa가 이정도까지 잘 결합될 수 있는 것이 신기하네요.

1. 프로젝트 생성
사용자 삽입 이미지
New Project를 클릭하고 프로젝트 템플릿의 Max OS X/Application에서 Cocoa-Ruby Application을 선택합니다. 프로젝트명에 'CocoaRuby' 또는 원하시는 프로젝트명을 입력하고 Save 버튼을 클릭합니다.




2. 기존 코코아 어플리케이션과 차이점
사용자 삽입 이미지
그룹에서 보시면 Objective-C의 main.m과 함게 새로 추가된 Ruby의 rb_main.rb 파일이 생성되어 있습니다.



1) main.m
#import <Cocoa/Cocoa.h>
#import <RubyCocoa/RBRuntime.h>

int main(int argc, const char *argv[])
{
    return RBApplicationMain("rb_main.rb", argc, argv);
}

Ruby를 위한 'RBRuntime.h'가 import되어 있습니다. 그리고 Cocoa에서 일반적으로 사용하는 'return NSApplicationMain(argc,  (const char **) argv);' 대신에 RBApplicationMain("rb_main.rb", argc, argv)로 대체되었습니다. 어플리케이션이 시작되면 'rb_main.rb' 루비 스크립트가 실행됩니다.

2) rb_main.rb
require 'osx/cocoa'

def rb_main_init
  path = OSX::NSBundle.mainBundle.resourcePath.fileSystemRepresentation
  rbfiles = Dir.entries(path).select {|x| /\.rb\z/ =~ x}
  rbfiles -= [ File.basename(__FILE__) ]
  rbfiles.each do |path|
    require( File.basename(path) )
  end
end

if $0 == __FILE__ then
  rb_main_init
  OSX.NSApplicationMain(0, nil)
end

* if $0 == __FILE__ then
현재 파일이 메인일 경우에 실행됩니다. 위의 'RBApplicationMain'에서 'rb_main.rb'을 실행하기 때문에 if내의 명령들이 실행됩니다.

* rb_main_init
Ruby에서 코코아와 기타 프레임워크에 접근을 위해 필요한 파일을 include 합니다.

* OSX.NSApplicationMain(0, nil)
기존의 NSApplicationMain을 실행합니다.


3. Ruby AppController 생성

AppController를 Ruby class로 만들어 보겠습니다. NewFile을 클릭하고 아래와 같이 Ruby 항목에서 'Ruby NSObject subclass'를 선택합니다.

사용자 삽입 이미지

FileName에 'AppController.rb'를 입력하고 Finish버튼을 클릭합니다. 아래와 같이 NSObject의 서브클래스로 AppController Ruby 클래스가 생성되어 있습니다. 푸른색으로 되어 있는 부분을 추가합니다.

require 'osx/cocoa'

class AppController < OSX::NSObject
    ib_outlet :inputText
    ib_outlet :outputText
   
    def buttonClicked(sender)
        OSX.NSLog("Button Clicked");
        @outputText.setStringValue("Hello~ #{@inputText.stringValue}")
    end
   
    ib_action :buttonClicked
end

* ib_outlet, ib_action
IBOutlet과 (IBAction) 대신에 Ruby에서는 ib_outlet과 ib_action을 사용하며 용도는 동일합니다.

* dot(.)
기존 프레임워크들의 클래스 메소드는 '.'를 이용해서 호출하고 함수들은 앞에 'OSX.'를 추가해서 호출합니다.


4. 인터페이스 빌더에서 작업
1) 윈도우
메인 윈도우에 라이브러리에서 Label, TextField, Button을 드래그 해서 아래와 같이 배치합니다.
사용자 삽입 이미지

2) AppController
사용자 삽입 이미지
라이브러리 윈도우에서 'Object'를 드래그해서 MainMenu.nib 윈도우에 드랍합니다.

Object의 Class를 앞에서 만들어 놓은 Ruby의 AppController로 선택합니다.




아래와 같이 inputText는 TextField에 outputText는 Label에 buttonClick는 buttonClicked에 각각 연결합니다.

사용자 삽입 이미지 사용자 삽입 이미지

이제 완료되었습니다. 빌드를 하고 실행을 합니다. 아래와 같이 ruby를 입력하고 버튼을 클릭하면 Label이 변경되는 것을 확인할 수 있습니다.
사용자 삽입 이미지

Ruby 스크립트들은 어플리케이션 번들의 Resource 디렉토리 밑에 위치합니다. Ruby는 인터프리터 방식으로 실행되기 때문에, 배포 후에도 사용자들이 목적에 맞게 Ruby(*.rb) 파일을 수정하여 어플리케이션을 쉽게 변경할 수 있습니다.
 
사용자 삽입 이미지
AND

몇일 전에 받은 문서중에서 MS의 CHM(Compiled HTML Help)파일 포맷이 있어 맥에서도 볼 수 있는 툴이 있는지 검색해 보았습니다. 애플의 다운로드 페이지에서 찾아 보니 쓸만한 어플리케이션이 두개가 있었습니다. ArCHMokiCHM이란 어플리케이션 입니다. 많이 사용하지는 못했지만 둘다 UI와 기능은 거의 같아 보입니다.

사용자 삽입 이미지 사용자 삽입 이미지
AND

이번 포스팅에서는 Xcode 3에서 2.0으로 업그레이드 된 Objective-C와 추가된 컴파일 옵션에 대해서 알아 보겠습니다.

역시나 깊이도 없고 내용도 별로 없는 제목 그대로 둘러보기 입니다. 자세하고 정확한 자료는 아래의 애플에서 제공하는 문서들을 참고하시기 바랍니다.



1. Objective-C 2.0

1) 가비지 컬렉션 지원
Cocoa Object에 가비지 콜렉션이 지원됩니다. 이제는 더이상 retain, release에 신경을 쓰면서 오브젝트의 retain counts를 관리할 필요가 없게 되었습니다. 가비지 컬렉션은 기본으로 꺼져있습니다. 이를 사용하기 위해서는 Project 정보 윈도우의 Build에서 GCC 4.0 - Code Generation 분류중 'Objective-C Garbage Collection' 항목에서 지원여부를 선택해야 합니다.
   
사용자 삽입 이미지

* Unsupported
가비지 컬렉션을 사용하지 않습니다.

* Supported (-fobjc-gc)
가비지 컬렉션과 이전의 retain/release를 병행해서 사용할 수 있습니다.

* Required (-fobjc-gc-only)
가비지 컬렉션만 사용하고 이전의 retain, release를 사용하지 않습니다. 새롭게 시작하는 프로젝트는 이 옵션을 선택하는 것이 좋을 것 같습니다.

가비지 컬렉션에 의해 메모리에서 삭제되는 오브젝트에게는 finalize이란 메시지가 전달됩니다. 이 메시지를 처리할 경우에는 반드시 super의 finalize도 호출해야 합니다.

- (void)finalize
{
    ...
    ...
    [super finalize];   
}


2) Property

@property와 @synthesize를 이용하여 class 내부변수를 편리하고 쉽게 관리할 수 있습니다.

@property(속성) 타입 변수명;
@synthesize 변수명

property의 속성들은 아래와 같으며 ','로 구분합니다.

* getter
getter=getName과 같이 getter 함수의 이름을 지정합니다. 특별히 지정되지 않았을 경우에는 변수명과 같은 이름이 사용됩니다.

* setter
setter=setName과 같이 setter 함수의 이름을 지정합니다. 특별히 지정되지 않았을 경우에는 set[변수명]으로 사용됩니다.

* readonly
읽기전용으로 getter 함수만 사용 가능하고 setter 함수는 사용할 수 없습니다.

* readwrite
getter, setter 함수 모두 사용할 수 있습니다.

* assign
setter에서 'value = newValue;'와 같이 단순한 할당이 적용됩니다;

* retain
아래와 같이 할당시 변수의 retain이 적용됩니다.
if (value != newValue)
{
    [value release];
    value = [newValue retain];
}

* copy
아래와 같이 할당시 변수의 copy가 적용됩니다.
if (value != newValue)
{
    [value release];
    value = [newValue copy];
}

아래는 property와 synthesize의 사용예입니다. property는 interface내에서 synthesize는 implementation내에서 선언됩니다.

* MyObject.h
#import <Cocoa/Cocoa.h>

@interface MyObject : NSObject {
    NSString *myName;
}

@property(copy,readwrite) NSString *myName;

@end

* MyObject.m
#import "MyObject.h"

@implementation MyObject
@synthesize myName;

@end

이제 getter와 setter의 구현없이 소스코드에서 아래와 같이 사용할 수 있습니다.
MyObject *myObject = [[MyObject alloc] init];

[myObject setMyName:@"KingKong"];
NSLog(@"%@", [myObject myName]);


3) Dot(.) 문법지원
C++, Java에서 사용하는 '.'를 사용할 수 있게되었습니다. '[obj myName]'과 같이 사용하던 것을 'obj.myName'으로 사용할 수 있습니다. 아래가 사용예입니다.

obj.myName = @"cocoa"; // [obj setMyName:@"cocoa"];
NSLog(@"%@", obj.myName); // NSLog(@"%@", [obj myName]);


4) 에뉴뮬레이션 문법 지원
C 스타일의 for문 대신에 "for ([변수] in [collection 오브젝트])"와 같이 편리하게 사용할 수 있습니다. collection 오브젝트에는 NSArray, NSDictionary, NSSet등의 클래스의 인스턴스가 올 수 있습니다.

NSArray *myArray = [NSArray arrayWithObjects: @"A", @"B", @"C", nil];
   
for (int i = 0; i < [myArray count]; i++) {
    NSLog(@"%@", [myArray objectAtIndex:i]);
}
       
for (NSString *str in myArray) {
    NSLog(@"%@", str);
}



2. 다양한 플랫폼 지원

1) OS X 지원
OS X 10.5, OS X 10.4, OS X 10.3(Xcode 설치시 옵션)의 여러 OS X 버젼과 아이폰을 지원합니다.

사용자 삽입 이미지

2) 64bit 아키텍쳐 지원
이제 코코아 어플리케이션도 64비트로 작성할 수 있습니다.  

사용자 삽입 이미지

3) 컴파일러(GCC) 버젼 선택
GCC 버젼을 선택할 수 있습니다. Xcode 2.5에서도 사용했던 4.0 버젼이 기본으로 선택되어 있으며, 최신버젼 4.2 또는 시스템에 실치된 gcc도 사용이 가능합니다. 그리고 LLVM(Low Level Virtual Machine)을 지원하는 gcc도 선택할 수 있습니다.

사용자 삽입 이미지


가비지 컬렉션, Property나 에뮬레이션 지원은 반가운 소식인데 닷('.') 문법 지원은 다소 의외입니다. '.'을 사용한 소스를 보면 C++, Java 프로그래머들은 처음 접할 시에 이질감이 덜하겠지만, Objective-C스러운(?) 맛이 줄어 들지 않을까 기우가 듭니다.

아무튼 애플에 의해 Objective-C가 다른 언어들의 장점을 흡수하면서 발전하는 모습을 보니 좋습니다.
AND