0

UILabel 및 UITextView의 attributedText 속성을 조작하는 메서드를 정의하는 UIView 범주가 있습니다.특정 하위 클래스에서 사용할 수있는 메서드를 호출 할 때 수퍼 클래스의 performSelector가 실패합니다.

@implementation UIView (replaceAttrText) 
-(void) replaceAttrText: (NSString *)str { 
    if ([self respondsToSelector: @selector(setAttributedText)]) { 
     NSMutableAttributedString *labelText = [self template]; 

     // change it 

     [self performSelector:@selector(setAttributedText) withObject: labelText]; 
    } 
} 
@end 

respondsToSelector는 UILabel의 및 UITextView 모두 false를 반환 (그들은 setAttributedText에 응답하지만) 및 setAttributedText이 respondsToSelector 확인하지 않고 직접 실행하면 예외가 발생합니다.

카테고리가 선택자없이 UILabel에 직접 구현되면 모든 것이 작동하지만 UILabel 및 UITextView에는 attributedText 속성이있는 공통 조상이 없습니다.

내가 뭘 잘못하고 있니? 감사!

+1

Apple에서 제공하는 클래스를 확장하면 일반적으로 아키텍처가 매우 약해지고 프로그램을 유지 관리하기 어려울 것이라는 신호가됩니다. 이 메소드는'setAttributedText :'를 구현하지 않는 클래스에 대해서는 아무것도하지 않습니다. 당신은 정말로 당신이 이야기하고있는 것을, 아주 구체적으로, 당신이 그것에 이야기하고있을 때 알고 있어야합니다. – bbum

+0

@bbum NSAttributedText를 확장하여 이러한 메서드를 구현할 수는 있지만 그 메서드가 호출 될 때마다 추가 할당이 필요하며 [NSObject의 해시]를 사용하여 컨트롤의 원래 값을 캐시합니다. iOS에 대한 유연성은 안전하지 않다고 느끼지 않습니다. – esp

+6

더 이상 자바 스크립트를 작성하지 않습니다. Objective-C 및 iOS 프레임 워크를 사용하고 있습니다. 애플에 의해 명시 적으로 권장되는 다른 언어의 패턴을 적용하는 것은 즉시 편리 할 수 ​​있지만 고통의 세계로 이어질 것이다. BTW : 만약 정말로 * 정말 * 좋은 생각이라고 생각한다면 적어도 같은 메소드를 접두사에 붙여서 같은 방법을 추가 할 임의의 미래의 업데이트와 충돌하지 않도록하십시오. – bbum

답변

5

UILabelUITextView에는 setAttributedText이라는 메서드가 없습니다. 그러나 그들은 setAttributedText:이라는 방법이 있습니다. 콜론에 유의하십시오. 콜론은 메소드 이름의 일부입니다. 그것을 가졌는지의 여부는 완전히 다른 두 가지 방법을 나타냅니다. , 즉

-(void) replaceAttrText: (NSString *)str { 
    if ([self respondsToSelector: @selector(setAttributedText:)]) { 
     NSMutableAttributedString *labelText = [self template]; 

     // change it 

     [self performSelector:@selector(setAttributedText:) withObject: labelText]; 
    } 
} 

setAttributedText에 모두 참조에 콜론을 추가

은 당신의 코드를 변경

.

+0

그게 내가 전에 선택기를 사용한 적은 ... 고마워! – esp

+3

맞는 구체적인 대답; 잘못된 패턴. 최소한 그 접두어 앞에 접두어를 붙이십시오. – bbum

4

@maddy는 적절한 답변을 제공합니다. 이것은 안티 패턴으로 간주되는 것을 처리합니다.

일반적으로 카테고리를 사용하여 Apple 제공 클래스를 확장해서는 안됩니다. 이렇게하면 코드가 시스템 프레임 워크와 효과적으로 얽히게됩니다. 이것은 유지 보수와 향상을 더 어렵게 만듭니다. 결국 자신 만의 클래스를 다룰 필요가 없으며, 인터 클래스를 통해 - 클래스가 확장하는 클래스의 패턴을 구현 한 코드를 리펙토링합니다 및 그것을 사용하는 클래스.

이러한 이유로 애플은 일반적으로 이러한 유형의 패턴을 권장합니다. 을 수행하면은 Apple 클래스를 확장합니다. 기존 메서드를 무시하지 말고 (구현 세부 정보 깨뜨림) 항상 메서드 앞에 접두어를 붙이면 향후 OS 릴리스 - 심지어 업데이트되지 않습니다. 당신과 충돌하는 방법을 포함하십시오 (전에 NSMutableArray에있는 addObjectIfAbsent:이 가장 주목할만한 이벤트였습니다).

또한 때로는 do-do-the-work-sometimes-does-non-isKindOfClass: 또는 respondsToSelector:을 확인하는 동작이 또 다른 반 패턴입니다. 잘 구조화 된 응용 프로그램은 일반적으로 형식을 전달하는 것을 피해야합니다. 따라서 형식의 수신기는 해당 형식에서 작동 할 수 있는지 파악해야합니다. 이렇게하면 컴파일러가 코드 정확성을 재확인 할 수있는 능력을 상실하게됩니다.

속성있는 텍스트가 필요한 UI 개체에 하나의 방법으로 액세스 할 수있는 UI 개체와 그렇지 않은 UI 개체가 액세스 할 수 있도록 응용 프로그램을 리팩터링하는 것이 좋습니다. 나는. 무엇이든간에 replaceAttrText: (Objective-C에서는 약어가 거의 사용되지 않습니다 .IE의 완성으로 인해 거의 입력 할 필요가 없으며 약어가 없으면 코드 명확성이 생깁니다.) 실제로 필요한 개체에서만 수행합니다 속성이 조정 된 텍스트입니다. 동적으로 또는 프로그래밍 방식으로 사용자 인터페이스를 생성하는 경우 모델과이 모델을 처리하는보기 사이에 컨트롤러 객체가있을 수 있습니다.

+4

-addObjectIfAbsent : 재미있었습니다. IIRC에서 구현 한 일부 개발자는 'void'를 반환했으며 NeXT는 객체가 실제로 추가되었는지 여부에 따라 'BOOL'을 반환했습니다. 충돌은 단순히 동작을 변경하는 것이 아니라 호출 사이트에서 스택 _을 손상 시켰습니다. 디버깅 할 수있는 즐거움. –

+0

X 코드에 대한 좋은 점은 인터페이스 변경이 정말 쉽다는 것입니다. JavaScript와는 달리, 메소드 이름을 절대로 변경하면 안됩니다. – esp

+0

@GrahamLee EOF의 기본 영구 저장소가 손상되었습니다. – bbum

관련 문제