Objective-C에서 ivar와 속성의 차이점은 무엇입니까?


82

Objective-C에서 ivar와 속성을 사용하는이 세 가지 방법의 의미 론적 차이는 무엇입니까?

1.

@class MyOtherObject; 
@interface MyObject {
}
@property (nonatomic, retain) MyOtherObject *otherObj;

2.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}
@property (nonatomic, retain) MyOtherObject *otherObj;

삼.

#import "MyOtherObject.h"
@interface MyObject {
    MyOtherObject *otherObj;
}

답변:


57

1 번은 컴파일러와 링커가 보는 코드의 양을 최소화하고 잠재적으로 순환 참조를 피하기 위해 MyOtherObject 클래스를 정방향 선언함으로써 다른 두 개와 다릅니다. 이렇게하면 #import를 .m 파일에 넣어야합니다.

@property를 선언하고 (및 .m에서 @synthesize와 일치) 파일을 지정하는 방식으로 처리 된 메모리 의미 체계와 함께 접근 자 메서드를 자동 생성합니다. 대부분의 객체에 대한 경험 규칙은 Retain이지만 NSStrings는 예를 들어 Copy를 사용해야합니다. Singleton과 Delegates는 일반적으로 Assign을 사용해야합니다. 손으로 쓰는 접근자는 지루하고 오류가 발생하기 쉬우므로 많은 입력 및 멍청한 버그를 줄일 수 있습니다.

또한 합성 된 속성을 선언하면 다음과 같은 점 표기법을 사용하여 접근 자 메서드를 호출 할 수 있습니다.

self.otherObj = someOtherNewObject; // set it  
MyOtherObject *thingee = self.otherObj; // get it 

일반적인 메시지 전달 방식 대신 :

[self setOtherObject:someOtherNewObject]; // set it
MyOtherObject *thingee = [self otherObj]; // get it 

이면에서 실제로 다음과 같은 메서드를 호출합니다.

- (void) setOtherObj:(MyOtherObject *)anOtherObject {

    if (otherObject == anOtherObject) {
        return;  
    }

    MyOtherObject *oldOtherObject = otherObject; // keep a reference to the old value for a second
    otherObject = [anOtherObject retain]; // put the new value in  
    [oldOtherObject release]; // let go of the old object
} // set it

…아니면 이거

- (MyOtherObject *) otherObject {  
    return otherObject;
} // get it

엉덩이에 전체적인 통증이 있습니다. 이제 수업의 모든 ivar 에 대해 수행 하십시오. 정확하게하지 않으면 메모리 누수가 발생합니다. 컴파일러가 작업을 수행하도록하는 것이 가장 좋습니다.

나는 것을 볼 수 1 바르가 없습니다. 오타가 아니라고 가정하면 @property / @synthesize 지시문이 배후에서 ivar도 선언하므로 괜찮습니다. 나는 이것이 Mac OS X-Snow Leopard 및 iOS4의 새로운 기능이라고 생각합니다.

3 번 에는 이러한 접근자가 생성되지 않았으므로 직접 작성해야합니다. 접근 자 메서드에 부작용이 생기도록하려면 위에 표시된대로 표준 메모리 관리 댄스를 수행 한 다음 접근 자 메서드 내에서 필요한 모든 부수 작업을 수행합니다. 당신이 재산을 합성하는 경우 뿐만 아니라 자신을 작성할 때 , 다음 당신의 버전이 우선합니다.

내가 모든 걸 다뤘나요?


네, 정말 감사합니다! 제가하고 싶은 한가지 메모는 # 1에서 포워드 클래스 pragma를 꺼내서 #import "MyOtherObject"로 대체하면 컴파일 시간 오류가 발생하지만 이유는 확실하지 않습니다. ....
ennuikiller

접근법 # 1보다 접근법 # 2를 사용하면 어떤 이점이 있습니까?
Greg

@Greg Method # 1은 순환 참조를 방지합니다. stackoverflow.com/questions/7221174/…
willc2

3
점 표기법에 관한 것 외에는 좋은 대답입니다. 점 표기법에 사용하기 위해 속성을 합성 할 필요가 없습니다. 실제로 속성을 선언 할 필요가 없습니다. 선언 된 setter와 getter (예 : setFoo:and foo)가있는 한 점 표기법을 사용할 수 있습니다.
JeremyP 2012-08-05

관련성을 위해 ARC를 사용하면 합성이 자동으로 수행됩니다.
Sean Larkin

17

예전에는 ivar가 있었고 다른 클래스가 설정하거나 읽도록하려면 getter (예 : -(NSString *)foo)및 setter (예 :))를 정의해야했습니다 -(void)setFoo:(NSString *)aFoo;.

당신에게 제공하는 속성은 ivar와 함께 무료로 (거의!) setter 및 getter입니다. 따라서 지금 속성을 정의 할 때 원 자성 (예 : 여러 스레드에서 여러 설정 작업을 허용 하시겠습니까?)을 설정할 수있을뿐만 아니라 의미 체계를 할당 / 유지 / 복사 할 수 있습니다 (즉, setter가 새 값을 복사해야하는 경우). 또는 현재 값을 저장하십시오. 다른 클래스가 나중에 변경 될 수있는 변경 가능한 문자열로 문자열 속성을 설정하려는 경우 중요합니다.)

이것이하는 일 @synthesize입니다. 많은 사람들이 바르 이름을 동일하게두고, 그러나 당신이 당신의 합성 문을 (즉, 쓸 때 당신은 그것을 변경할 수 있습니다 @synthesize foo=_foo;수단이라는 바르하게 _foo재산에 대한을 foo읽거나이 속성을 작성하려는 그렇다면, 당신은 사용하지 않는 self.foo, 당신은 것입니다 사용해야 _foo = ...합니다. setter와 getter 만 사용하려는 경우 ivar에 대한 직접 참조를 포착하는 데 도움이됩니다.

Xcode 4.6 @synthesize부터는 명령문 을 사용할 필요가 없습니다 . 컴파일러가 자동으로 수행하고 기본적으로 ivar의 이름 앞에 _.



그래서 내가 원자적인 ivar를 가지고 있다면, 당신은 setter가 그것을 설정하거나 getter가 그것을 얻는 동안 다른 스레드가 시작되어 둘 중 하나를 시도하면 모두 바보가된다는 것을 의미합니까? 그렇다면 원자의 요점은 무엇입니까? 내 이해는 atomic은 적어도 ivar를 설정하면 설정되고 보유 횟수가 적절하다는 것을 확인합니다. 그렇지 않으면 왜 원자 적입니까? [이 모든 문제를 해결하지 않는 것이 단지 foobared 얻기에서 당신을 방지]
데이비드 H

2
유효한 전체 객체를 확보 할 수 있습니다. getter는 할당 해제중인 객체를 반환하지 않지만 다른 스레드가 setter를 사용하는 경우 이전 또는 이후의 값을 가져올 수 있습니다. getter 및 setter 외부에서 처리해야하는 지정. 즉, getter 또는 setter 작업 중에 스레드가 중단 되지 않지만 작업 순서는 정의되지 않습니다 (이 수준에서는 AFAIK 일 수 없음).
jscs

글쎄, 나는 당신의 원래 코멘트가 잘못 배치되었다고 주장하고 싶습니다. 다른 곳에서 다루어집니다.
David H
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.