본문 바로가기
프로그래밍 놀이터/iOS

[Objective-C] 선언 프로퍼티

by 돼지왕왕돼지 2017. 12. 28.

 [Objective-C] 선언 프로퍼티


출처 : OS X 구조를 이해하면서 배우는 Objective-C Chap 7.

@dynamic, @end, @implementation, @property, @synthesize, arc용, assign, Atomic, COPY, CoreData, getter, instance variable 이름, introspection, KVC, kvo, nonatomic, NSManagedObject, readonly, readwrite, Reflection, respondsToSelector, retain, Runtime, Setter, setValue, strong, Super Class, unsafe_unretained, weak, [Objective-C] 선언 프로퍼티, 도트 연산자, 리플렉션, 메서드 패밀리와 프로퍼티의 관계, 메타 데이터, 메타 정보 동적 접근, 명시적 프로퍼티 선언, 인수 없는 메서드, 인스턴스 변수 생성, 인트로스펙션, 접근자 메서드 생성, 초기자 프로퍼티 접근, 컴파일러 지시자, 키-값 코딩, 프로퍼티 개념, 프로퍼티 구현, 프로퍼티 선언과 기능, 프로퍼티란


Notice : 정리자(돼지왕 왕돼지)가 remind 하고 싶은 내용이나 모르는 내용 기반으로 정리하는 것이기 때문에 구체적인 내용은 책을 사서 보시기를 권장드립니다.


7.1. 프로퍼티란


* 7.1.1. 프로퍼티를 사용한 프로그래밍


-

선언 프로퍼티 관련 기능은..

     접근자 메서드 생성

          인스턴스 변수를 지정해서 전형적인 접근자 메서드를 생성할 수 있다.

          게터와 세터 모두 생성할지 게터만 생성할지 지정할 수 있다.

          대응하는 접근자를 스스로 정의할 수도 있다.


     인스턴스 변수 생성

          프로퍼티를 인스턴스 변수에 없는 이름으로 선언하면 접근자 메서드와 동시에 자동으로 인스턴스 변수도 생성된다.


     접근자 호출을 간편하게 기입

          접근자 메서드를 도트 연산자 ‘.’ 를 사용해서 호출할 수 있다.

          세터 메서드 호출은 구조체 멤버에 대입, 게터 메서드 호출은 구조체 멤버값 참조와 같은 기법으로 작성할 수 있다.

          이런 기법은 선언 프로터피뿐만 아니라 접근자 메서드가 정의되어 있으면 모두 이용할 수 있다.


     프로퍼티 관련 인트로스펙션

          클래스에 어떤 선언 프로퍼티가 들어 있는지, 그 이름과 형식은 무엇인지라는 정보를 실행할 때 동적으로 조사할 수 있다.




* 7.1.2. 프로퍼티 개념


-

키-값 코딩 도입으로 외부에서 접근 가능한 객체 속성이라는 의미.



-

선언 프로퍼티는 기능 면에서 접근자 메서드로 구현한 개념을 정리해서 간단하게 작성할 수 있도록 한 것.

한편, 키-값 코딩에서 접근자 메서드가 아닌 인스턴스 변수가 정의되어 있을 뿐이라도 프로퍼티로 다룰 수 있으므로 키-값 코딩에서 말하는 프로퍼티가 좀 더 포괄적인 개념이다.



cf) 인스트로펙션


-

데이터 형식과 내용을 설명하는 데이터는 메타 데이터, 정보를 설명하는 정보는 메타 정보라고 한다.

메타 데이터는 ‘제목은 회의록, 작성 시간은 언제, HTML 데이터로 문자코드는 유니코드, 읽기 전용 속성’ 같은 데이터이다.


어떤 클래스가 어떤 메서드나 프로퍼티를 가지는지에 대한 정보도 일종의 메타 정보이다.

객체지향 언어는 이런 메타 정보를 프로그램에서 동적으로 접근하는 기능을 인트로스펙션(introspection) 또는 리플렉션(reflection)이라고 부른다.

respondsToSelector: 메서드도 인트로스펙션이다.




7.2. 프로퍼티 선언과 기능


* 7.2.1. 명시적인 프로퍼티 선언


-

프로퍼티 선언은 메서드 선언 중간이나 그 후에 작성해도 괜찮다.



-

같은 형의 프로퍼티를 선언할 때에는 다른 줄로 작성할 수도 있지만, 콤마로 프로퍼티명을 배열해서 선언할 수도 있다.



cf)

@property NSString* name;


@synthesize name

위와 같이 설정할 경우 instance variable 이름은 _name 이 아니라 name 이 된다.


최근의 XCode( clang 3.2 / 2012. 02. ) 에서는 @synthesize 를 명시적으로 하지 않은 @property 선언에 대해 컴파일러가 자동으로 @synthesize name = _name; 이라는 코드를 넣는다고 보면 된다.




* 7.2.2. 프로퍼티 구현


-

@synthesize 는 컴파일러 지시자이다.

이 녀석을 @implementation 에서 @end 사이에 작성하면 인터페이스에서 선언한 속성에 대응해서 접근자가 구성된다.



-

접근자를 구성하지 않아도 된다고 컴파일러에 알리기 위해 @dynamic 이라는 컴파일러 지시자를 사용할 수 있다.

필수는 아니다.



cf)

@dynamic 지시자를 사용하면, 여기서 사용되는 getter, setter 는 super class 것을 쓰거나, runtime 에 의해 추가되거나 등의 해당 class 에서 정의해서 사용하지 않는다는 것을 의미한다.


@dynamic 이 주로 사용되는 곳은 NSManagedObject ( CoreData ) 에서의 getter, setter 이다.




* 7.2.3. @synthesize 와 인스턴스 변수


-

@synthesize 작성도 여러 프로퍼티명을 콤마로 이어서 배열할 수 있다.



-

실제 인스턴스 변수명과 다른 이름을 프로퍼티로 외부에 제공하고 싶을 때가 있다.

예를 들어 프로퍼티명은 value 지만 대응하는 인스턴스 변수가 runningAverage 라면 다음처럼 지정할 수 있다.

@synthesize value = runningAverage;



-

인스턴스 변수 선언(일부 또는 전부)를 실행부에 작성할 수 있다.

선언 프로퍼티가 인스턴스 변수에 대응하는지 숨길 수 있다.

서브 클래스에서도 인스턴스 변수에는 직접 접근이 안 되므로 강제적으로 선언 프로퍼티를 사용하게 된다.

@interface Creature : NSObject


@property int hitPoint;


@end


@implemenation Creature{

     int hitPoint;

}


@end




* 7.2.4. @synthesize 로 인스턴스 변수 생성


-

선언한 프로퍼티에 대응하는 인스턴스 변수가 인터페이스에도, 구현 부분의 앞부분에도 선언되지 않았을 경우 프로퍼티에 @synthesize 를 적용하면 해당 이름과 형식의 인스턴스 변수를 자동으로 만들어 클래스 구현에 추가한다.


@synthesize 로 생성된 변수에는 클래스 외부나 서브 클래스에서 직접 접근할 수 없다.

이렇게 생성된 변수의 유효 범위(스코프)는 대응하는 @synthesize 이후부터이다.






* 7.2.5. 프로퍼티 속성 지정


-

메스드명 지정

     getter=게터명

     setter=세터명


읽기/쓰기 속성

     readonly

     readwrite (default)


값 설정 방법

     assign

     retain

     unsafe_unretained (ARC용)

     strong (ARC용)

     weak (ARC용)

     copy


메모리 관리 속성

     nonatomic



-

@property(setter=setValue:) int hitPoint;

도트 연산자 기법으로 .hitPoint 를 사용할 수 있지만, 실제 불리는 메서드는 setValue: 이다.




* 7.2.6. 값 설정 방법 지정


-

프로퍼티가 객체가 아닐 때, 단순대입만 가능하며 assign 이나 unsafe_unretained 를 지정



-

프로퍼티가 객체이고 ARC 를 사용할 때

     assign 또는 unsafe_unretained 를 지정하면 유지되지 않는 단순 대입

     strong 이나 retain 을 지정하면 강한 참조

     weak 을 지정하면 약한 참조

     copy 를 지정하면 cop 메서드에 의해 생성된 복제 객체를 강한 참조




* 7.2.7. atomic 관련 메모리 관리 속성



* 7.2.8. 선언 프로퍼티와 상속


-

슈퍼 클래스에서 선언된 프로퍼티는 서브 클래스에 상속된다.

이 때 서브 클래스에서 접근자 메서드 정의를 재정의할 수 있다.

하지만 슈퍼 클래스 @property 로 지정한 각종 속성, 즉 assign 인지 retain 인지 게터와 세터 이름 지정 등은 모두 같아야 한다.


딱 한 가지, 슈퍼 클래스에서 readonly 였던 프로퍼티를 서브 클래스에서 readwrite 로 변경하는 것은 허용된다.




* 7.2.9. 메서드 패밀리와 프로퍼티의 관계


-

선언 프로퍼티에서 접근자 메서드가 자동으로 생성되어 프로퍼티명이 게터 메서드의 샐럭터로 사용된다.

따라서 프로퍼티명이 메서드 패밀리 조건에 일치하지 않도록 주의해야 한다.

특히 ‘new’ 로 시작하는 이름은 프로퍼티명으로 자주 사용하므로 주의해야 한다.




7.3. 도트 연산자를 사용한 프로퍼티 접근

* 7.3.1. 도트 연산자 사용 방법


-

도트 연산자를 적용할 수 있는 건 클래스를 형식으로 지정한 인스턴스뿐이다.

id 형 변수에는 도트 연산자를 적용할 수 없으므로 주의해야 한다.


프로퍼티의 값은 void 형이 아니라면 id 를 포함해서 모두 가능하다.




* 7.3.2. 도트 연산자를 사용한 식 작성


-

대입식의 해석 : 대입 연산자는 오른쪽부터 먼저 계산된다.



-

증가, 감소 연산자, 복합 대입 연산자 해석

     obj.depth++;

     // equals

     [obj setDepath:[obj depth] + 1];



-

self 사용시, 접근자 자체의 정의 안에서 사용하면 재귀호출이 되어 무한 반복될 수 있으므로 주의해야 한다.



-

구조체 멤버 참조와 혼용

w = win.minSize.width; // 여기서 width 앞의 . 는 구조체 멤버 참조용 닷.



-

세터의 경우는 아래와 같이 값 assign 은 불가능하고, 구조체 전체를 set 하는 방향으로 해야 한다.

win.minSize.width = 320; // 불가능


NSSize sz = win.minSize;

sz.width = 320;

win.minSize = sz;




* 7.3.3. 도트 연산자는 언제 사용하는가


-

인수가 없는 메서드는 프로퍼티인지에 상관없이 게터 메서드처럼 도트 연산자를 적용할 수 있다.

하지만 기본적으로 선언 프로퍼티에 정의된 프로퍼티에만 도트 연산자를 사용해야 한다.


C언어와의 관계에서 도트 연산자는 구조체 요소 참조라는 오버헤드가 거의 없는 접근을 떠올리게 한다.

하지만 인수가 없는 함수를 도트 연산자로 사용할 경우, 그 인상과는 반대로 복잡한 작업이 이어진다.

따라서 프로퍼티의 값이 아닌 실행되는 절차가 중요할 경우에는 도트 연산자 사용이 좋지 않다.



-

다른 메서드 정의 안에서 대응하는 인스턴스 변수에 직접 접근하는 건 피해야 한다.

물론 해당 프로퍼티 구현 자체 또는 구현에 관련된 메서드에서는 변수에 직접 접근할 필요가 있다는 건 두말 할 필요가 없다.

하지만 클래스 구현 자체가 외부에 은폐되므로 실행 효율, 구현 편의성과 상속 유무를 생각해서 방침을 정해야 한다.



-

초기자에서 프로퍼티에 접근하는 것도 주의해야 한다.

초기자 실행 중에는 인스턴스 초기화가 아직 끝나지 않았으므로 프로퍼티에 따라서는 접근자 메서드가 정상적으로 동작하지 않을 가능성이 있다.

인스턴스 변수와 같은 감각으로 가볍게 접근하는 것은 위험하다.





댓글0