내 인터페이스에서 다음과 같이 읽기 전용 속성을 선언했습니다.
@property (readonly, nonatomic, copy) NSString* eventDomain;
속성을 오해하고있을 수도 있지만으로 선언 readonly
하면 구현 ( .m
) 파일 내부에서 생성 된 setter를 사용할 수 있지만 외부 엔터티는 값을 변경할 수 없다고 생각했습니다. 이 SO 질문 은 그것이 일어나야한다고 말합니다. 그것이 내가 추구하는 행동입니다. 그러나 표준 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
재산에 대한 선언을 오해하고 있습니까? 아니면 다른 일이 일어나고 있습니까?
답변
세터도 필요하다고 컴파일러에 알려야합니다. 일반적인 방법은 .m 파일 의 클래스 확장자 에 넣는 것입니다 .
@interface YourClass ()
@property (nonatomic, copy) NSString* eventDomain;
@end
답변
에이코와 다른 사람들이 정답을주었습니다.
더 간단한 방법은 다음과 같습니다 . 전용 멤버 변수에 직접 액세스합니다.
예
헤더 .h 파일에서 :
@property (strong, nonatomic, readonly) NSString* foo;
구현 .m 파일에서 :
// inside one of my init methods
self->_foo = @"someString"; // Notice the underscore prefix of var name.
그게 전부입니다. 소란스럽지 않고 소란스럽지 않습니다.
세부
Xcode 4.4 및 LLVM 컴파일러 4.0 ( Xcode 4.4의 새로운 기능)부터는 다른 답변에서 논의 된 집안일을 엉망으로 만들 필요가 없습니다.
synthesize
키워드- 변수 선언
- 구현 .m 파일에서 속성을 다시 선언합니다.
속성을 선언 한 후 foo
Xcode가 underscore : 접두사로 명명 된 전용 멤버 변수를 추가했다고 가정 할 수 있습니다 _foo
.
속성이 선언 된 readwrite
경우 Xcode는 명명 된 getter 메서드 foo
와 명명 된 setter를 생성합니다 setFoo
. 이러한 메서드는 점 표기법 (my Object.myMethod)을 사용할 때 암시 적으로 호출됩니다. 속성이 선언 된 경우 readonly
setter가 생성되지 않습니다. 이는 밑줄로 명명 된 백업 변수 자체가 읽기 전용 이 아님을 의미합니다. readonly
에는 세터 방법은 값을 설정 도트 표기법 따라서 합성하지시키고 단순히 수단 컴파일러 에러 실패. 컴파일러가 존재하지 않는 메서드 (세터) 호출을 중지하기 때문에 점 표기법이 실패합니다.
이 문제를 해결하는 가장 간단한 방법은 밑줄로 명명 된 멤버 변수에 직접 액세스하는 것입니다. 밑줄로 명명 된 변수를 선언하지 않아도 그렇게 할 수 있습니다! Xcode는 빌드 / 컴파일 프로세스의 일부로 해당 선언을 삽입하므로 컴파일 된 코드에는 실제로 변수 선언이 있습니다. 그러나 원래 소스 코드 파일에서는 이러한 선언을 볼 수 없습니다. 마술이 아니라 문법적인 설탕 .
사용 self->
은 개체 / 인스턴스의 멤버 변수에 액세스하는 방법입니다. 이를 생략하고 var 이름 만 사용할 수 있습니다. 그러나 나는 내 코드를 자체 문서화하기 때문에 self + arrow를 사용하는 것을 선호합니다. 당신이 볼 때 self->_foo
당신은 모호함없이 알고 _foo
이 인스턴스의 멤버 변수입니다.
그건 그렇고, 재산 접근 자의 장단점과 직접 ivar 접근에 대한 논의는 Matt Neuberg 박사 의 Programming iOS 책 에서 읽을 수있는 사려 깊은 대우 입니다. 읽고 다시 읽는 것이 매우 도움이된다는 것을 알았습니다.
답변
읽기 전용 속성으로 작업하는 또 다른 방법은 @synthesize를 사용하여 백업 저장소를 지정하는 것입니다. 예를 들면
@interface MyClass
@property (readonly) int whatever;
@end
그런 다음 구현에서
@implementation MyClass
@synthesize whatever = m_whatever;
@end
그러면 m_whatever
멤버 변수이므로 메서드를 설정할 수 있습니다 .
지난 며칠 동안 제가 깨달은 또 다른 흥미로운 점은 다음과 같은 하위 클래스에서 쓰기 가능한 읽기 전용 속성을 만들 수 있다는 것입니다.
(헤더 파일에서)
@interface MyClass
{
@protected
int m_propertyBackingStore;
}
@property (readonly) int myProperty;
@end
그런 다음 구현에서
@synthesize myProperty = m_propertyBackingStore;
헤더 파일의 선언을 사용하므로 하위 클래스는 읽기 전용을 유지하면서 속성 값을 업데이트 할 수 있습니다.
데이터 숨김 및 캡슐화 측면에서 약간 유감스럽게도.
답변
기존 클래스 사용자 정의를 참조하십시오.iOS 문서에서 .
readonly 속성이 읽기 전용임을 나타냅니다. 읽기 전용을 지정하는 경우 @implementation에 getter 메소드 만 필요합니다. 구현 블록에서 @synthesize를 사용하면 getter 메서드 만 합성됩니다. 또한 도트 구문을 사용하여 값을 할당하려고하면 컴파일러 오류가 발생합니다.
읽기 전용 속성에는 getter 메서드 만 있습니다. 여전히 속성의 클래스 내에서 직접 또는 키 값 코딩을 사용하여 백업 ivar를 설정할 수 있습니다.
답변
다른 질문을 오해하고 있습니다. 이 질문 에는 다음과 같이 선언 된 클래스 확장이 있습니다.
@interface MYShapeEditorDocument ()
@property (readwrite, copy) NSArray *shapesInOrderBackToFront;
@end
이것이 클래스의 구현에서만 볼 수있는 setter를 생성하는 것입니다. 따라서 Eiko가 말했듯이 클래스 확장을 선언하고 속성 선언을 재정 의하여 컴파일러에게 클래스 내에서만 setter를 생성하도록 지시해야합니다.
답변
가장 짧은 해결책은 다음과 같습니다.
MyClass.h
@interface MyClass {
int myProperty;
}
@property (readonly) int myProperty;
@end
MyClass.h
@implementation MyClass
@synthesize myProperty;
@end
답변
속성이 읽기 전용으로 정의 된 경우 이는 클래스 내부 또는 다른 클래스에서 외부 적으로 사용할 수있는 setter가 사실상 없다는 것을 의미합니다. (예 : 말이되는 경우에만 “게터”가 있습니다.)
소리에서 보면 private로 표시된 일반 읽기 / 쓰기 속성이 필요합니다.이 속성은 다음과 같이 인터페이스 파일에서 클래스 변수를 private으로 설정하여 얻을 수 있습니다.
@private
NSString* eventDomain;
}