2013-07-11 2 views
1

다음 상황이 발생했습니다. 저는 UITextView control (MyTextView : UITextView)을 확장 중입니다. 런타임 장치 버전에 따라 다른 구현이 있습니다. 그래서 현재 MyTextView 클래스를 구현할 때 "if-else"문이 많이 있습니다. 더 유지 보수, 나는 다른 클래스로 분할하고 싶은 있도록하기 위해모든 생성자에서 super를 호출하지 않고 클래스 인스턴스화

:

MyTextViewIos5 : MyTextView, MyTextViewIos6:MyTextView

는 따라 만들 수있는 서브 클래스 런타임에 알 수 공장 함수를 만드는 방법 기기 iOS 버전으로

MyTextView를 매개 변수로 사용하는 경우이 솔루션이 완벽하게 작동합니다. MyTextView (externalTextView:MyTextView)에서 상속 구체적인 방법과 그것을 확장하는 클래스가있을 때

MyTextView* textView = [Factory createWithFrame:frame]; 

이 문제는 시작 의 initWithFrame 방법은 다음과 같이 표시됩니다

- (id)initWithFrame:(CGRect)frame { 
    self = [Factory createWithFrame:frame]; 
    if (self) { 
     ... 
    } 
    return self; 
} 

을 대신 난 슈퍼 initwithFrame를 호출 내 공장에 전화 해.

내가 externalTextView 구체적인 방법, MyTextViewIos5 또는 MyTextViewIos6가 호출 된 특정 메소드를 구현하지 않는 오류와 함께 응용 프로그램 충돌 전화

.

작동시키기위한 일시적인 해결책이 있습니까?

+0

init 메소드에서'super'를 호출하지 않으시겠습니까? – sergio

+0

나는 잠깐 동안 당신이'alloc'을 서브 클래스 화함으로써 이것을 처리 할 수 ​​있다고 생각했지만 아마도 그렇게하지 않았을 것이다. (원래의 문제를 처리하는 "영리한"방법입니다.) –

답변

1

단순히 self = [Factory createWithFrame:]에 할당하면 사용자 지정 클래스가 아닌 MyTextViewIos5 또는 MyTextViewIos6의 데이터에만 적용됩니다. 결과적으로 사용자 정의 클래스의 메소드 테이블 등이 존재하지 않으므로 이것이 충돌합니다.

상속의 본질은 해당 기능을 상속 받기 위해 MyTextViewIos5MyTextViewIos6 중 하나를 서브 클래스로 지정해야한다는 것입니다. 문제는 어느 것을 알지 못한다는 것입니다.

사용자 지정 클래스의 기능을 대리인/프로토콜 디자인으로 구분하는 것이 좋습니다. MyTextView 수퍼 클래스에는 대리자를 관리하기위한 코드가 포함될 수 있습니다. 같은

뭔가 : 당신은 당신이 하나를 정의하면, 자신의 initWithFrame 방법에 [super initWithFrame]를 호출해야 MyTextView에서 파생 클래스의

- (void)methodCustomSubclassWouldHaveOverridden 
{ 
    [delegate handleThisForMe]; 
} 
+0

사용자 정의 클래스 기능이 무엇인지 알면 좋은 해결책입니다. 하지만 내 경우에는 외부 SDK를 구축하고 \ Inherit MyTextView 클래스를 사용할 사용자 정의 클래스에 대해서는 아무 것도 가정 할 수 없습니다. – ram

+0

@ user2572953 프로토콜을 사용하여 클라이언트가 구현해야하는 계약을 정의 할 수 있습니다. –

+0

죄송합니다, 내 잘못 ... 나는 당신의 솔루션을 정확하게 처음 이해하지 못했습니다. 당신이 옳습니다. 내 사용자 지정 기능을 대리자에두고 MyTextView 클래스에서 처리하면 작동합니다. 즉, 내 사용자 지정 ios5 및 ios6 클래스는 MyTextView의 하위 클래스가 아니며 정의 된 프로토콜을 구현합니다. 이 접근 방식은 작동하지만 상속을 사용하는 것보다 훨씬 덜 우아합니다. 다른 대안이 없다면 그것을 사용할 것입니다. 감사합니다. – ram

0

각 하나. 파생 클래스 인스턴스의 사용자 정의 초기화를 수행 할 필요가 없다면 init 메소드를 완전히 생략 할 수 있습니다. 파생 클래스가 특별한 초기화를 필요로하지 않는 경우

- (MyTextView*)createWithFrame:(CGRect)frame { 

    if (<iOS6>) 
     return [[MyTextViewOS6 alloc] initWithFrame]; 
    if (<iOS5>) 
     ... 
} 

지금, 당신은 단순히 그들 각각의 initWIthFrame 방법을 절약 할 수 (과 : 일반적인 경우

, 당신의 공장 createWithFrame 뭔가 같이해야한다 기본 클래스에서만 하나 정의).

또는이 같은 공장에서 초기화를 할 수있는 :

- (MyTextView*)createWithFrame:(CGRect)frame { 

    if (<iOS6>) 
     MyTextViewOS6* view = [[MyTextViewOS6 alloc] initWithFrame]; 
     view.iOS6SpecificProperty = ...; 
     [view iOS6SpecificMethod:...]; 
     return view; 
    if (<iOS5>) 
     ... 
} 

을 당신이 뭐 : ​​

self = [Factory createWithFrame:frame]; 

MyTextView의 새로운 인스턴스를 할당하고 self 원래 값을 대체 . 즉, 할 때 :

externalTextView* view = [[externalTextView alloc] initWithFrame]; 

우선 메모리는 externalTextView 유형의 개체에 할당됩니다. 그런 다음 해당 클래스의 initWithFrame 메소드가 호출됩니다. 이제 initWithFrame 안에 당신이 할 경우 : 당신이 공장을 통해 새로운 객체를 인스턴스화하고 (원래 ALLOC를 통해 생성 된 오브젝트 지적) self에 그 포인터를 할당하는

self = [Factory createWithFrame:frame]; 

.

희망이 도움이됩니다.

+0

불행히도 저스틴 (Justin)은 단순히 "self = [Factory createWithFrame :]을 지정하는 것은 MyTextViewIos5 또는 MyTextViewIos6에 대한 데이터이며 사용자 정의 클래스가 아니라는 것을 의미합니다. 결과적으로 사용자 정의 클래스의 메소드 테이블 등이 존재하지 않으므로 충돌이 발생합니다 ". – ram

관련 문제