2012-09-03 3 views
10

나는 클래스 확장에 jQuery과에 속성을 추가하고 싶습니다 : 다음아이폰 OS 클래스 확장의 속성을 정의

@interface UITableViewController() 

@property NSString *entityString; 

@end 

내가 확장을 가져온 다음 내가있는 UITableViewController의 서브 클래스에 entityString 속성을 사용

@implementation CustomerTableViewController 

- (void)viewDidLoad { 
    self.entityString = @"Customer"; 
    ... 
    [super viewDidLoad]; 
} 
... 

Apple documentation는 말한다 :

the compiler will automatically synthesize the relevant accessor methods (...) inside the primary class implementation.

을하지만 전하려고 할 때 그것을 ecute 나는이 오류가 발생 :

-[CustomerTableViewController setEntityString:]: unrecognized selector sent to instance 0x737b670

내가 뭘 잘못하고있어? 어쩌면 하위 클래스에서 속성에 액세스 할 수 없습니까?

답변

5

클래스 확장 추가 인터페이스 선언하는 데 사용됩니다 - 메서드와 속성 - 구현이 계약 클래스의 주요 @implementaiton 내에서 충족됩니다.

바로 확장 기능을 통해 저장소 (ivars 추가)를 추가 할 수 없습니다. 클래스 확장은 인터페이스이며, 더 이상 필요하지 않습니다. @synthesize@property 선언에 대한 저장소를 생성하지만 @property@synthesize은 클래스의 @implementation에만 표시 될 수 있습니다 (명시 적 으로든 컴파일러의 기본 동작이든).

프레임 워크 클래스를 다시 컴파일 할 수 없기 때문에 프레임 워크 클래스에 ivars를 추가 할 수 없습니다.

@ prashat의 답변은 기존 클래스에 스토리지를 추가하는 한 가지 방법입니다. 그러나 그 경로를가는 것은 일반적으로 바람직하지 않습니다. 프레임 워크 클래스의 상태를 유지하는 것은 불량한 설계의 징후이며 시간이 지남에 따라 애플리케이션을 유지 관리하는 것을 훨씬 더 어렵게 만듭니다.

디자인을 다시 방문하는 것이 더 좋고 현재 직접적으로 포함 할 수없는 개체에 상태를 첨부해야하는 이유를 이해하고 해당 요구 사항을 리팩토링해야합니다.

+0

클래스 확장에 ivars를 추가 할 수 없습니까? 아니면 사용 된 컴파일러에 따라 다릅니 까? – tiguero

+3

클래스 확장에서 ivars 및 속성을 선언 할 수 있지만 클래스의 @implementation을 컴파일하기 전에 컴파일러에서 확장을 확인하지 않으면 해당 저장소가 만들어지지 않습니다. – bbum

+0

명확히 해 주셔서 고마워요. - alazaro가 실제로 프레임 워크 클래스에 클래스 확장을 사용하고 있다는 것을 알지 못했습니다. – tiguero

4

워드 프로세서 상태 :

Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main @implementation block for the corresponding class.

당신이 @property를 사용하는 경우, 그것은 접근 방법을 선언 거의 비슷하다. 따라서 UITableViewController를 사용하여 "주"@implementation 블록의 작성자 인 경우에만 이러한 작업을 수행 할 수 있습니다.

여기서 유일한 옵션은 인스턴스 변수를 추가 할 수없는 카테고리입니다.

The docs link 하고, 해당 페이지의 맨 마지막 줄에 유의하십시오

The implementation of the setValue: method must appear within the main @implementation block for the class (you cannot implement it in a category). If this is not the case, the compiler emits a warning that it cannot find a method definition for setValue:.

+0

나는 내 경우가 아니라고 생각한다. 나는 ivar + 접근자를 사용하지 않고있다. 그러나 컴파일러는 내 코드에 대해 불평하지 않습니다. 오류는 런타임에 발생합니다. – alazaro

+3

'@ property' **는 ** ivar plus 접근 자입니다. –

+0

예, 알지만 컴파일러가 대신 작업을 수행합니다. 클래스에 접근자를 추가 할 수도 있다고 생각했는데, 그것이 나에게 속하는지 아닌지에 관계없이 접근자를 추가 할 수 있다고 생각했습니다. – alazaro

12

대신 연관 참조와 범주를 사용하여 시도합니다. 훨씬 더 깔끔하고 UIButton의 모든 인스턴스에서 작동합니다.

UIButton+Property.h 

#import <Foundation/Foundation.h> 

@interface UIButton(Property) 

@property (nonatomic, retain) NSObject *property; 

@end 


UIButton+Property.m 

#import "UIButton+Property.h" 
#import <objc/runtime.h> 

@implementation UIButton(Property) 

static char UIB_PROPERTY_KEY; 

@dynamic property; 

-(void)setProperty:(NSObject *)property 
{ 
    objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

-(NSObject*)property 
{ 
    return (NSObject*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY); 
} 

@end 

// 예 사용

#import "UIButton+Property.h" 


UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
button1.property = @"HELLO"; 
NSLog(@"Property %@", button1.property); 
button1.property = nil; 
NSLog(@"Property %@", button1.property); 
+0

연관 참조는 클래스 확장보다 어떻게 깨끗합니까? – vikingosegundo

+4

그들은 작동하기 때문에 더 깨끗합니다. (클래스의 @implementation이 컴파일 될 때 확장이 없기 때문에 클래스 확장이 없지만) 깨끗하게 만들지는 못합니다. 기존 프레임 워크 클래스에 상태를 추가하는 것은 잘못된 디자인과 높은 취약성의 신호입니다. prashant의 답변이 작동하는 동안, 그런 일을하는 것은 일반적으로 아키텍처를 재고해야한다는 신호입니다. – bbum

+0

해당 코드에서'@ dynamic'을 사용할 필요가 없습니다. – bbum