본문 바로가기

Dev.iOS/Objective-C

[Objective-C] 2. 클래스에 대해서, 프로퍼티

Chapter 2. 클래스에 대해서, 프로퍼티


Objective-C 소스 파일(구현부)은 .m을 확장자로 한다.
헤더파일은 (.h)의 확장자를 갖는다.
헤더파일과 구현 파일 두 개가 합쳐서 클래스를 구성한다.
Objective-C 컴파일러는 두 개의 파일을 개별적으로 컴파일한다.

#import vs #include
ifdef를 기억하는가? #include는 중복되어 include되는 헤더 파일을 파악하지 못해 ifdef를 통해 이를 해결해야 했지만, #import 지시어는 여러 번 같은 클래스를 import ( include ) 하여도 중복되는 것은 무시한다.

헤더 파일의 #import <Foundation/Foundation.h> 와 구현 파일의 #import “header.h”에서
‘꺾쇠'와 'double quote, 큰 따옴표'의 차이는 무엇인가?


double quote로 import를 한 경우는, 시스템 파일이 아닌 로컬 파일, 즉 우리가 생성한 파일에 사용되며, 시스템에게 그 파일을 어디서 찾아야 하는지 알려준다. 때문에 컴파일러는 double quote로 import된 헤더 파일을 찾기 위해 먼저 현재 디렉터리를 검사한다. 필요하다면 컴파일러에게 검색할 실제 위치를 지정해줄 수도 있다.

#import 대신에 @class 지시어를 활용하자
@class 지시어는 헤더 파일에서 특정 클래스를 인스턴스로 접근할 때, 클래스 명을 컴파일러에게 알려줘야 할 경우에 사용한다. @class 지시어를 사용하면, 이 지시어를 통해 명시된 클래스의 인스턴스를 만나게 될 때 컴파일러에게 해당 인스턴스의 클래스 명이 무엇인지 알려준다. #import를 통해 헤더파일을 import 했을 경우, 전체 헤더 파일을 처리해야 하지만, @class 지시어를 달면 컴파일러가 전체를 처리할 필요가 없어지기 때문에 더 효율적이다. 하지만 클래스에 정의된 메서드를 사용해야 한다면 @class 지시어만으로는 부족하다. 메서드가 인수를 얼마나 많이 받는지, 인수가 어떤 형인지, 어떤 값을 반환하는지에 대한 정보들이 추가적으로 필요하기 때문이다. 이 경우에는 헤더 파일에서 #import를 통해 해당 클래스 파일을 import 해줘야 한다.


자동 생성 접근자 메서드
Objective 2.0부터는 setter와 getter메서드(접근자 메서드)를 자동으로 생성할 수 있다. 인터페이스 부분에서 @property 지시어를 사용해 프로퍼티를 지정해주는 방법이다. ( 이 프로퍼티들은 보통 인스턴스 변수와 같은 이름을 사용한다. ) 프로퍼티로 지정된 변수들은 컴파일러가 자동으로 synthesize(생성)해준다. 이렇게 컴파일러가 작성한 접근자 메서드는 효율적일 뿐만 아니라 멀티스레드, 다중 코어 환경에서 좀 더 안전하게 돌아간다.

Objective-C에서는 프로퍼티에 좀 더 쉽게 접근할 수 있는 문법을 제공한다.
점 연산자( . )를 사용하여 프로퍼티에 접근하는 것이다.
[instance setProperty: value];
이렇게도 할 수 있지만,
instance.property = value;
이렇게도 할 수 있는 것이다.

점 연산자를 자동 생성된 메서드 대신 직접 작성한 메서드에서도 사용할 수 있다.
하지만 문법적으로 가능하나 좋은 프로그래밍 스타일로 여기지지 않기 때문에
점 연산자는 프로퍼티에 접근할 때만 사용하도록 하자.

getter, setter 메소드 이름을 개발자가 재정의 할 수도 있다.
@property(nonatomic, strong, getter = getInstanceMember) UIImage;
이렇게 하면 get 메소드의 이름이 재정의되어 메소드를 호출할 때,
getInstanceMember라는 이름으로 호출할 수 있다.

프로퍼티의 속성인 nonatomic과 strong에 대해 알아보자.
nonatomic 부분에는 nonatomic과 atomic 속성이 올 수 있다.
atomic 속성이 설정되면 멤버 변수 접근에 대해서 mutex 설정이 되어 멀티스레드 환경에서 작동할 때 멤버 변수에 대한 접근이 제한되게 된다. 이 반대로 nonatomic으로 해주게 되면 제한되지 않게 되는 것이다. 싱글 스레드 환경에서 작동할 경우에는 특별히 atomic으로 속성을 변경해줄 필요가 없다. 또한 atomic으로 속성을 지정해준다고 해서 완벽하게 보장되는 것도 아니기 때문에 사용할 때는 각별히 주의할 필요가 있다. default 속성으로 nonatomic이 지정된다.

strong 부분에는 life qualifier가 오게 된다. 뒤에 메모리 관리에 대해서 이야기할 때 더 자세히 알아보도록 하자.


인스턴스 생성하기
1. alloc 메소드와 init 메소드 사용하기
모든 오브젝트 변수들은 포인터 형으로 선언되어야 한다. 이에 따라 프로그래머가 명시적으로 오브젝트를 생성하기 위한 메모리를 할당받아야 한다. 이런 역할을 하는 것이 alloc 메소드와 init 메소드이다. new 메소드도 존재하지만 주로 alloc과 init을 사용한다.
ex> MyClass *myClass = [[MyClass alloc] init];


2. 팩토리 메소드 사용하기
팩토리 메소드를 사용하면 alloc메소드와 init 메소드를 사용하지 않고도 인스턴스를 생성할 수 있다. 일단 프로그래밍이 간단해지며, 인스턴스를 생성할 때 인자를 넘겨주기 때문에 인자에 맞는 메모리를 할당하여 보다 메모리를 효율적으로 사용할 수 있다.


루트 클래스 : NSObject
어떠한 클래스도 상속받고 있지 않은 클래스를 루트 클래스라고 한다. Objective-C에서의 모든 클래스는 NSObject 클래스를 상속받아야 한다. 루트 클래스는 반드시 NSObject 프로토콜을 ‘구현'해야 한다. NSObject 프로토콜은 Objective-C 프로그램이 제대로 작동하는데 필요한 핵심적인 메소드들을 정의하고 있다. 대표적인 메소드로는 alloc 메소드가 있다.  



Chapter 2. end