2011-01-03 6 views
81

내 인터페이스에서 readonly 속성을 다음과 같이 선언했습니다.Objective-C의 읽기 전용 속성?

어쩌면 속성을 잘못 이해하고 있지만 readonly으로 선언하면 생성 된 setter를 구현 내부에서 사용할 수 있습니다 (.m) 파일이지만 외부 엔티티는 값을 변경할 수 없습니다. This SO question는 그렇게해야한다고 말합니다. 그것이 내가 한 행동입니다. 그러나 표준 setter 또는 도트 구문을 사용하여 eventDomain을 내 init 메서드 내에 설정하려고하면 unrecognized selector sent to instance. 오류가 발생합니다. 물론 나는 재산을 @synthesize하고있다. 이것을 다음과 같이 사용하려고합니다 :

 // inside one of my init methods 
[self setEventDomain:@"someString"]; // unrecognized selector sent to instance error 

그래서 재산에 대한 readonly 선언을 오해하고 있습니까? 아니면 다른 일이 있습니까?

답변

105

설정자를 필요로한다는 것을 컴파일러에 알려줘야합니다. 일반적인 방법은하는 .m 파일에 class extension에 넣어하는 것입니다 : 당신은 다른 질문을 오해하는

@interface YourClass() 

@property (nonatomic, copy) NSString* eventDomain; 

@end 
+1

헤더 파일에 노출하지 않고 설정기를 수동으로 정의하는 것 외에도 AFAIK가 유일한 다른 방법입니다. – BoltClock

+0

아! 카테고리를 추가하십시오! 이것은 정확히 내가 겪은 것입니다. 너 락! 최대한 빨리 답변을 수락 ... :) – Alex

+21

이것은 카테고리가 아닙니다. 그것은 클래스 연장입니다 (에이코가 말했듯이). 그들은 유사한 목적으로 사용되었지만 분명히 다르다. 예를 들어 위의 내용을 진정한 범주에서 수행 할 수는 없습니다. – bbum

2

속성이 읽기 전용으로 정의 된 경우 클래스 내부에서 또는 다른 클래스의 외부에서 사용할 수있는 설정자가 실제로 없음을 의미합니다. (예 : 의미가있는 경우 "게터"만 있습니다.)

소리를 통해 일반 클래스로 표시된 일반 읽기/쓰기 속성이 필요합니다.이 속성은 클래스 변수를 설정하여 얻을 수 있습니다

@private 
    NSString* eventDomain; 
} 
7

. In that question 클래스 확장이, 이렇게 선언 클래스의 구현에서만 볼 세터를 생성하는 것입니다

@interface MYShapeEditorDocument() 
@property (readwrite, copy) NSArray *shapesInOrderBackToFront; 
@end 

. 따라서 Eiko가 말한 것처럼 클래스 확장을 선언하고 속성 선언을 재정 의하여 컴파일러에서 클래스 내에서만 setter를 생성하도록해야합니다.

20

iOS 문서의 Customizing Existing Classes을 참조하십시오.

읽기 전용 속성이 읽기 전용임을 나타냅니다. readonly를 지정하면 @implementation에 getter 메서드 만 필요합니다. 구현 블록에서 @synthesize를 사용하면 getter 메서드 만 합성됩니다. 또한 도트 구문을 사용하여 값을 할당하려고하면 컴파일러 오류가 발생합니다.

읽기 전용 속성에는 getter 메서드 만 있습니다. 속성의 클래스 내에서 또는 키 값 코딩을 사용하여 직접 백업 쌍을 설정할 수 있습니다.

34

readonly 속성으로 작업하는 또 다른 방법은 @synthesize를 사용하여 백업 저장소를 지정하는 것입니다. 예

구현

@implementation MyClass 

@synthesize whatever = _whatever; 

@end 

는 멤버 변수이기 때문에 내 방법이어서, _whatever 설정할 수있는 그런

@interface MyClass 

@property (readonly) int whatever; 

@end 

들어.그런 다음

(헤더 파일)

@interface MyClass 
{ 
    @protected 
    int _propertyBackingStore; 
} 

@property (readonly) int myProperty; 

@end 

:


나는 지난 몇 일에서 실현 한 또 다른 흥미로운 점은이 같은처럼 서브 클래스에서 쓸 수있는 읽기 전용 속성을 만들 수있다 , 구현시

@synthesize myProperty = _propertyBackingStore; 

헤더 파일에서 선언문을 사용합니다. e에서 하위 클래스는 읽기 전용을 유지하면서 속성 값을 업데이트 할 수 있습니다.

데이터 숨기기 및 캡슐화 측면에서 약간 유감스럽게도.

+1

설명 된 첫 번째 방법은 허용 된 대답보다 쉽게 ​​처리 할 수 ​​있습니다. 그냥 "@ 합성 foo1, foo2, foo3;" .m에. 모든 것이 좋다. – sudo

4

가장 짧은 솔루션입니다 :

@interface MyClass { 

    int myProperty; 

} 

@property (readonly) int myProperty; 

@end 

에서 MyClass.h

@implementation MyClass 

@synthesize myProperty; 

@end 
30

에이코와 다른 사람들이 정답을 준

에서 MyClass.h.

다음은 더 간단한 방법입니다. private 멤버 변수에 직접 액세스하십시오.

그것 뿐이다
// inside one of my init methods 
self->_foo = @"someString"; // Notice the underscore prefix of var name. 

, 즉 당신이 필요로하는 모든입니다 : 구현하는 .m 파일에서

@property (strong, nonatomic, readonly) NSString* foo;

: .H 파일 헤더에서

. 불평, 호들갑.

에 대한 자세한 사항은 엑스 코드 4.4 LLVM 컴파일러 4.0 (New Features in Xcode 4.4)의로

, 당신은 다른 답변에서 논의 된 집안일 엉망 필요가 없습니다 :

  • synthesize 키워드
  • 선언을 변수
  • 구현 .m 파일의 속성을 다시 선언하십시오. _foo을 :

속성 foo를 선언 한 후, 당신은 엑스 코드는 밑줄의 접두어로라는 이름의 개인 멤버 변수를 추가했습니다 가정 할 수있다.

속성이 readwrite으로 선언 된 경우 Xcode는 foo이라는 getter 메서드와 setFoo이라는 세터를 생성합니다. 이러한 메서드는 내 표식 (my Object.myMethod)을 사용할 때 암시 적으로 호출됩니다. 속성이 readonly으로 선언 된 경우에는 setter가 생성되지 않습니다.즉, 밑줄로 이름 지은 백킹 변수는 이 아니며은 읽기 전용입니다. readonly은 단순히 setter 메서드가 합성되지 않았기 때문에 점 표기법을 사용하여 값을 설정하면 컴파일러 오류가 발생하여 실패합니다. 컴파일러가 존재하지 않는 메서드 (setter)를 호출하지 못하기 때문에 점 표기법이 실패합니다.

가장 간단한 방법은 밑줄로 명명 된 멤버 변수에 직접 액세스하는 것입니다. 밑줄 친 변수를 선언하지 않아도 그렇게 할 수 있습니다! Xcode는이 선언을 빌드/컴파일 프로세스의 일부로 삽입하므로 컴파일 된 코드는 실제로 변수 선언을 갖습니다. 그러나 원래의 소스 코드 파일에서 그 선언을 결코 볼 수 없습니다. 마법이 아닙니다. 단지 syntactic sugar입니다.

self->을 사용하면 개체/인스턴스의 멤버 변수에 액세스 할 수 있습니다. 이를 생략하고 var 이름 만 사용할 수 있습니다. 그러나 자기 코드를 스스로 문서화하기 때문에 self + arrow를 사용하는 것을 선호합니다. self->_foo을 보면 모호하지 않고 _foo이이 인스턴스의 멤버 변수임을 알 수 있습니다. 그런데


는 프로와 직접 바르 액세스 대 속성 접근의 단점에 대한 논의는 정확히 박사 Matt NeubergProgramming iOS 책에서 읽을 수 있습니다 사려 깊은 치료의 일종이다. 나는 그것을 읽고 다시 읽는 것이 매우 도움이된다는 것을 알았다.

+1

아마도 (클래스없이) 멤버 변수에 직접 액세스해서는 안된다는 것을 추가해야 할 것입니다! 그렇게하는 것은 OOP (정보 은닉)을 위반하는 것입니다. – HAS

+1

@HAS 여기에서 시나리오는이 클래스 외부에서 보이지 않는 멤버 변수를 개인적으로 설정하는 것입니다. 그것이 원래 포스터의 질문의 핵심입니다 : * 다른 클래스가 설정할 수 없도록 속성을'읽기 전용 '으로 선언하십시오. –

+0

나는 readonly 속성을 만드는 방법에 대해이 게시물을보고있었습니다. 이것은 나를 위해 작동하지 않습니다. 그것은 내가 init에 값을 할당 할 수있게 해주지 만 나중에 _variable을 할당과 함께 변경할 수도 있습니다. 컴파일러 오류 또는 경고를 발생시키지 않습니다. – netskink