Objective-C 훑어보기

Objective-C 2011. 3. 20. 23:40



iPhone 의 인기와 더불어 주목받고 있는 Objective-C 언어에 대해서 간략히 알아보자. 
Objective-C 언어는 C 언어 기반위에 객체지향적인 요소를 가미한 언어로서, 객체지향 언어의 원류인  Smalltalk 에서
그 개념을 많이  차용했다고 한다.  이 포스팅에서는 언어의 구체적인 설명은 하지않고,  간략히 어떤 언어 요소들이
있는지만  알아보겠다. 



1. Objective-C 에서 클래스 정의 
#import "SuperClass.h"
@interface NewClass : SuperClass {
   int instanceVariable;
}
- method;
- methodWithParameter:param;

@end
@implementation NewClass

- method {
   return (nil);
}
- methodWithParameter:param {
   return (nil);
}



2. Object Pointers
SpecificClass * specificObject;
id anyObject;
id 타입은 void * 형 포인터로 어떤 객체 포인터도 할당하거나 할당받을 수 있다.


3. Sending Messages
[object method];
[object methodWithParam:param];

objective-c에서는 메시지를 호출한다고 하기 보단, 객체에게 메세지를 보낸다고 한다. 



3. Naming Method

Objective-C에서는 메시지의 이름을 부여할 때,  메소드가 취하는 행위를 기술하도록 이름짓는다. 메시지의 이름은
다음과  같은 형식을 따른다.
반환타입+메시지행위+첫번째 인자이름: 첫번째 인자 이름:  두번째 인자이름...
반환타입이나 인자가 존재하지 않는 경우 생략될 수 있다. 


- valuePrepositionParameter:parameter
- objectForKey:key
- stringByAppendingString:string;
- numberFromString:string;




4. Parameter and Return Types
인자와 반환값은 괄호사이에 기술한다
- (id)objectForKey:(id)aKey;
- (NSMenuItem)itemWithTag:(NSInteger)aTag;
- (unichar)characterAtIndex:(NSUInteger)index;
- (NSString*)stringByAddingPercentEscapeUsingEncoding:(NSStringEncoding)encoding;
- (void)runInNewThread;
- (void)addAttribute:(NSString*)name value:(id)value range:(NSRange)aRange;



5. Method Selectors
메서드의 이름, 인자변수의 이름, 인자의 타입이 유일한 식별자를 구성하며, Java 의 메소드 시그니처와 동일한 의미를 갖는다. 
(NSfont*)fontWithFamily:(NSString*)family traits:(NSFontTraitMask)fontTraitMask weight:(NSInteger)weight size:(CGFloat)size

의 메소드 식별자는  fontWithFamily:family:traits:weight:size 가 된다.  이 식별자는  실제로 selector 라 불리는 숫자 상수와 
맵핑이 되며, 그 숫자 상수는 SEL 타입을 갖는다.  @selector()  지시어는  특정 메소드의 selector  상수를 반환한다
SEL selector = @selector(fontWithFamily:traits:weight:size)


6. Instance Variable

isa 인스턴스 변수
모든 Objective-C 객체가 상속받는 인스턴스 변수로,  클래스 자체를 정의하는  Class  타입의 객체이다.
- (Class)class 메소드 호출을 통해 얻을 수 있으며, - (NSString *)className 통해 클래스의 이름을 문자열로 얻을 수 있다.
 

Properties
객체의 프로퍼티를 정의하는 키워드로 @property  와 @synthesize 가 있다. @property 는 클래스가 계약을 지킬 것이라고 컴파일러에게 알려주는 역할을 한다.  @synthesize 는 컴파일러에게 해당 인스턴스 변수에 대한 getter와 setter  를 생성하라고 지시한다    
 int tag;

라는 인스턴스 변수에 대해 @property int tag; @synthesize tag;를  선언되면 컴파일러는
- (void)setTag:(int)newTag  
- (int)tag

와 같은 한쌍의 접근자를 생성할 것이다. 이렇게 생성된 접근자는 디폴트로 threadsafe 하다. @property만 선언했다면, 구현파일에
 getter 와 setter를 기술하는 것은 프로그래머의 몫이다. 즉 @synthesize를 통해 자동생성하거나,   프로그래머가 직접 구현해줘야 한다. 그렇지 않으면 컴파일 에러가 발생할 것이다.

@property 지시어와 함께 사용할 수 있는 속성들이 있는데, getter와 setter울 생서을 위한 속성이 된다. 

 Property Attributes 

 Attribute  Description
 readonly  getter 만을 생성한다. readwrite 속성과 상반된다. 
 readwrite  디폴트 값이며,  getter 와 setter 를 모두 생성한다. 
 copy  setter 에서 인자를 인수변수에 저장할 때, 인자의 복사본을 저장한다.  객체 포인터 타입에만 유효한 속성이다.  (primitive 타입은 항상 복사되기 때문) 리시버가 센더의 인자값을 변경하지 못하게
할 때 사용한다. 
 assign  인스턴스 변수에 레퍼런스 카운팅 없이 단순 할당한다.  가비지 컬렉션이 존재하는 환경에서 참조를 유지하고 싶거나, 인자값이 변경불가능할 때 사용한다. 
 retain  assign과 유사하며, 가비지 컬렉션이 없는 Managed memory 환경에서 객체의 참조 카운터를 증가
시킨다. 
 getter=name 지정한 name 이름으로 getter 를 생성한다.  getter와 setter의 표준 패턴을 위반해서  Key-Value Coding 과 같은 기술들이 인식할 수 없게 될수도 있기 때문에 사용에 주의해야한다. 
 setter=name 지정한 name 이름으로 setter 를 생성한다.
 nonatomic 디폴트로 생성된  setter 는  atomic 속성을 갖는다. 락을 사용하여 thread-safe 하지만, 상당한 오버헤드를 수반한다. 쓰레드의 개입이 없을 경우,  명시적으로 nonatomic 으로 선언하여 performance 를 높이는게 좋다.
 
 

7. Class Methods
클래스 메소드는 메소드 이름 앞에 + 기호를 갖는다. 모든 클래스는 런타임에  그 클래스 인스턴스의 identity와 behavior를  정의하는 
하나의 Class  객체를 생성한다.  클래스는 이 Class 객체가 응답하는 메시지를 정의한다.  Objective-C의 클래스 메소드는 자바와 비슷한 역할을 하지만 기술적으로는 다르다.
@interface RandomSequece : NSObject {
long long int seed;
}
+ (NSNumber*)number;
+ (NSNumber*)string;
- (NSNumber*)nextNumber;
- (NSString*)string;
@end
...
NSNumber *n = [RandomSequence number];
NSString *s = [RandomSequence string];

관례적으로  클래스 메소드를 먼저 정의하고, 인스턴스 메소드를 정의한다. 자바에서 클래스메소드는 this 키워드를 사용할 수 없지만,  Objective-C 의 클래스메소드 에서는 self  키워드를 사용할 수 있다.  클래스 메소드에  self 는 Class 객체를 가리키며, 인스턴스 메소드 처럼 서브클래스에 상속할 수 있으며 오버라이딩 또한 가능하다.

@interface Classy : NSObject {
   + (void)greeting;
+ (NSString*)salutation;
}
@end

@implementation
+ (void)greeting {
NSLog(@"%@, world!", [self salutation]);
 }
+ (NSString*)salutation {
NSLog(@"Greetings");
}
@end
@interface Classic : Classy
   + (NSString*)salutation;
@end
   + (NSString*)salutation {
     return (@"Hello");
}
@end
...
[Classy greeting];    // Logs "Greetings, world"
[Classic greeting];   // Logs "Hello, world!" 

[Classic greeting]  은 Classy Class 객체에 메시지를 보내고,   [self salutation]은 해당 Cass 클래스 객체에 메시지를 보낸다.
[Classic greeting] 은 greeting 메소드가 없지만, 수퍼클래스로부터 상속받은 greeting 메시지를 호출하며, [self salutation] 은 Classic
Class 객체에 메시지를 보낸다. 

 

8. Constructing Objects
java 에서는 객체를 생성하는 문법을 존재하여, 객체를 생성하는 방법을 명시적으로 제약한다.  반면 Objective-C 는 객체를
생성하는 방법을 클래스 설계자가 결정하도록 한다. 
 
객체를 생성하는 과정은 2가지 과정을 거친다. 
1) 메모리 구조 할당
2) 인스턴스 초기화

@interface RandomSequence : NSObject {
long long seed;
}
- (id)init;
- (id)initWithSeed:(long long)startingSeed;
@end

@implementation RandomSequence
- (id)init {
self  = [super init];
if (self != nil) {  
   seed = 1;
}
return (self);
}
- (id)initWithSeed:(long long)startingSeed {
self = [super init];
if (self != nil) {
seed = startingSeed;
}
return (self);
}
@end
...
RandomSequence *r1 = [[RandomSequence alloc] init];
RandomSequence *r2 = [[RandomSequence alloc] initWithSeed:-43 ];
RandomSequence * r3 = [RandomSequence new];

alloc 은 NSObject 에 정의된 클래스 메소드 +(id)alloc   이다.  객체를 생성하기 위해 클래스 참조를 사용하여 메모리를 할당하고,
그것을  isa 변수에 할당한다. 그리고 인스턴스를 모두 0으로 채운뒤, 참조를 반환한다. 이 시점에서 요청된 객체가 존재하지만
아직 초기화는 되지않았다.  init 메시는 객체를 초기화를 담당하며, 이메시지가  반환되면 깨체는 사용할 준비가 된 상태가 된다. 
new 도 NSObject의 클래스 메소드로 내부적으로 alloc과 init 를 호출한다

- (id)init...계열의 메소드를 오버라이드 하거나 재정의 해서 객체생성을 커스터마이징 할 수 있다. 
+ (id)alloc  또는 +(id)new 를 재정의 해서는 안된다. 



9. Writing an init Method
Objective-C에서 생성자를 작성하기 위해서 4가지 계약을 충족해야 한다
1) 수퍼 클래스의 생성자를 호출한다  :  [super init]
2) 자신의  self 변수를 업데이트 한다  :  self = [super init]
3) nil 객체 검사를 한다                          : if (self != nil ) { ... }
4) 자신의 포인터를 반환한다                : return self

모든 생성자는 수퍼클래스의 생성자를 호출해야한다. 자바는 언어 차원에서 이를 지원하지만,  Objective-C 는 프로그래머에게
책임이 있다.  self 를 변경하는 것은 자바 프로그래머에게는 이상하지만,  Class Cluster를 위해 핵심이 되는 부분이다.
nil 객체 검사를 하는 이유는, 반드시 메모리 할당이 성공한다고 보장할 수 없기 때문이다. 메모리 고갈로 인한 실패가 있을 수 있기
때문에 방어적인 프로그램을 위한 것이다.  모든 잘 작성된 생성자는 위의 4가지 조건을 만족해야 한다 

Chaining Initializers
자바에서는 명시적인 생성자 호출 문법을 가지고 있어서, 특정한 수퍼클래스의 생성자나 자신의 생성자를 호출 할 수 있다.
Objective-C에서는 이러한 문법은 없지만, 동일한 원리로  수퍼클래스나 자신의 init...계열의 메시지로 초기화가 가능하다.

Designated Initializer
Objective-C 의 많은 클래스들이 "설계된" 생성자를 갖으며, 객체 생성시 이를 사용하여 초기화를 해야한다
그렇기 때문에 이러한 클래스들을 사용할 경우에는 문서를 참조해야 한다. 

Convenience Constructors
클래스 메소드의 일반적인 용례는 복잡한 객체 생성 및 초기화를 간소화시킷는 것이다. 
Cocoa framework의  NSDictrionary  클래스는 [NSDictionary dictionary]  클래스 메소드를 제공하며, 이것은
[[NSDictionary alloc] init]  와 동일하다 


 
10. Destructors
Objective-C 에서도 선택적으로 - (void)finalize 메소드를 오버라이드 할수 있다. 이 메시지는 가비지 컬렉터에 의해 객체가 파괴되기
전에 호출된다. 모든 finalize 메소드는  반환되기 직전에 수퍼클래스의 finalize  메시지를 호출해야한다
- (void)finalize {
if (file != nil) {
[file close];
file = nil;
}
[super finalize]
}   

 
   
11. etc...

Inner / Anonymous Classes (내부 클래스와 익명클래스)
내부 클래스와 익명클래스는 코드 캡슐화나 어댑터로 사용되는데, Objective-C 에서는 비공식 프로토콜과 코드 블록을
사용하여 구현된다. (코드 블록은 변수에 실행가능한 코드 블록 할당을 허용하는 Objective-C 언어에 최근 추가된 개념이다)
 
Object Arrays
Objecitve-C에서는  C object 포인터 배열이나  NSArray 컬렉션 클래스를 사용하여 구현한다
 
final
final 키워드를 지원하지 않으며, 클래스 상속이나 메소드 오버라이딩을 막을 수 없다. 변수에 적용 할 경우,  const가 유사하다.
 
abstract
Objective-C 의 모든 클래스와 메소드는 구체 클래스이다 
 
package
Objective-C에는 패키지가 없으며, 패키지 범위 또한 없다. 
 
 


'Objective-C' 카테고리의 다른 글

Objective-C 문자열 조작 메서드  (0) 2011.04.29
다중인자를 갖는 PerformSelector 메시지  (0) 2011.03.23
Protocol 과 Category  (0) 2011.03.22
Objective-C 훑어보기  (2) 2011.03.20
[Cocoa] Cocoa Design Pattern  (0) 2011.03.20
HMAC-SHA1 구현  (0) 2011.03.03
  • sungsik81 2011.03.22 09:49 ADDR 수정/삭제 답글

    날 위한 포스트인가... 두둥...

  • 로그 @로그 2011.03.23 14:00 신고 ADDR 수정/삭제 답글

    예전에 자바 개발자를 위한 objective-c 보고 정리했던 거에요.. 정리라기 보단...
    책에서 그대로 가져온...^^;;