2011-12-28 2 views
9

iOS 프로그래밍 책의 두 번째 장에서 Joe Conway는 서브 클래 싱하는 경우 클래스 메서드에서 'self'를 사용하는 방법을 설명합니다. 이 개념을 이해하고 서브 클래 싱 문제에 대해 질문합니다.하위 클래스의 Objective-C 클래스 메서드를 제대로 재정의하려면 어떻게해야합니까?

배경 : 우리는 누구의 클래스 메소드 + randomPossession이처럼 보이는 점유율 클래스를 생성 :

+(id)randomPossession 
{ 
NSArray *randomAdjectiveList = [NSArray arrayWithObjects:@"Fluffy", @"Rusty", @"Shiny", nil]; 
NSArray *randomNounList = [NSArray arrayWithObjects:@"Bear", @"Spork", @"Mac", nil]; 

unsigned long adjectiveIndex = rand() % [randomAdjectiveList count]; 
unsigned long nounIndex = rand() % [randomNounList count]; 

NSString *randomName = [NSString stringWithFormat:@"%@ %@", [randomAdjectiveList objectAtIndex:adjectiveIndex], [randomNounList objectAtIndex:nounIndex]]; 

int randomValue = rand() % 100; 

NSString *randomSerialNumber = [NSString stringWithFormat:@"%c%c%c%c%c", 
           '0' + rand() % 10, 
           'A' + rand() % 10, 
           '0' + rand() % 10, 
           'A' + rand() % 10, 
           '0' + rand() % 10]; 

Possession *newPossession = [[self alloc] initWithPossessionName:randomName valueInDollars:randomValue serialNumber:randomSerialNumber]; 

return [newPossession autorelease]; 
} 

내가 반환 값은 정말 id 형식이어야한다는 것을 알고 같은 해당 ID newPossession = ...

나는 점유율을 서브 클래스하고 새로운 바르, 한 brandname 다음과 같이 내가 BallGlove에 + randomPossession를 오버라이드있는 NSString *

를 포함하는 클래스라는 BallGlove 생성 :

+(id)randomPossession 
{ 
BallGlove *myGlove = [super randomPossession]; 

NSArray *brandNames = [NSArray arrayWithObjects:@"Rawlings", @"Mizuno", @"Wilson", nil]; 

unsigned long randomNameIndex = rand() % [brandNames count]; 

[myGlove setBrandName:[brandNames objectAtIndex:randomNameIndex]]; 

NSLog(@"myGlove is of type class: %@", [self class]); 

return myGlove; 
} 

내 질문은 다음과 같습니다.이 수업 방법을 커뮤니티가 적절하고 수용 할 수있는 방식 (즉, 변수에서 슈퍼 구현을 캡처하여 해당 형식을 병렬 처리하고 그에 따라 변수를 조작 한 다음이를 리턴하십시오. 내 결과는 반환 된 객체가 BallGlove의 인스턴스임을 보여 줬지만 만족스러운 구현에 관심이있었습니다. 미리 감사드립니다.

답변

0

기술적으로 좋습니다.

나는 대안을 제시하고 싶습니다. 이미 기본 클래스에 지정된 public initializer가 있습니다 (어쨌든 factory 클래스 메소드에서 만들고 호출하려는 경우). 그리고 하위 클래스의 해당 초 기자 (또는 하위 클래스의 새로운 이니셜 라이저)를 사용하십시오. 방법.

더 많은 코드는 아니지만 제 의견에는 더 쉽게 따르고 미래 보장이 필요합니다. 이니셜 라이저는 한 지점에서 유용 할 수 있지만 모든 응용 프로그램에 대한 솔루션이 아닙니다.

+0

+ 기본 클래스의 randomPossession은 실제로 지정된 초기화 프로그램을 호출합니다. 클래스 메서드는 또한 해당 이니셜 라이저에 대해 "임의"값을 만듭니다. 내가 생각하는 바를 믿는다면 오버라이드 된 클래스 메소드 (+ randomPossession)에서 "임의"값에 대한 코드를 복제하고 지정된 이니셜 라이저를 재정 의하여 BallGlove 클래스의 새 초기화 프로그램을 호출해야합니다. 내 추가 iVar 정보를 추가하십시오. 왜 일반적인 방법으로 해로운 제안 클래스 메서드를 무시 무엇입니까? 체인 이니셜 라이저에 비유 될 수 없는가? –

+0

지나치게 추한 것 같지 않습니다. 아주 일반적인 패턴이 아닙니다. 질문 자체가 그 좋은 지표입니다. :) 서브 클래 싱 (subclassing)으로 다소 애매한 것은 메소드의 이름이며, 좋은 네이밍은 objective-c에 관한 최상의 것들 중 하나입니다. 따라서 귀하의 경우 + randomBallGlove 메서드가 재정의하는 것보다 낫습니다. – Eiko

+0

대신 + randomPossession의 구현과 원하는 구현을 포함하는 + randomBallGlove라는 클래스 메서드를 만드는 것이 좋습니다. 나에게 좋은 소리. Possession의 하위 클래스에서 + randomPossession을 계속 사용할 수 있다고 제안 하시겠습니까? 메서드를 재정의하고 + randomBallGlove의 사용을 지시하는 예외를 throw합니까? 일반적으로 이러한 이벤트의 일반적인 프로토콜입니까?나는이 예가 실제로 존재하지 않을 수도 있음을 알고 있으며, 나는 단지 배웠고 일어난 사건에서 받아 들여진 구현에 관해서 궁금하다. 당신의 도움을 주셔서 감사합니다! –

1

예, 그렇게 초기화 할 수도 있습니다. 사실 그것이 대부분의 경우에 어떻게 이루어 지는지입니다. 제 말은, 그것은 우선 슈퍼 클래스로부터 상속을받는 이유입니다. 수퍼 클래스에있는 것 외에 물건을 원한다. 따라서 상속 된 클래스에 특정한 코드를 삽입하면 그렇게해야합니다.

BallGlove 개체를 어떻게 초기화 할 것인가는 상속 된 메서드를 정의하는 방법의 요소이기도합니다. 문제는 Possession init을 호출하거나 BallGlove init을 호출 할 때 발생합니다 (클래스 인스턴스를 만드는 것이 클래스 메서드를 사용하는 유일한 장소는 아닙니다). 따라서 객체를 작성하는 논리, 즉 BallGlove 객체를 잘 설명하는 방법에 따라 클래스 메소드가 BallGlove 객체 기준에 맞는 방식으로 설명하고 일반 객체 Possession이되지 않도록해야합니다. 내 대답은 당신이 그것을 올바르게 구현할 수 있다면, 클래스 메서드의 병렬 라인을 사용할 수 있다는 것입니다. 당신이 당신의 슈퍼 클래스 타입 Possession의 반환하는 경우 id 어떤 클래스 형식

+0

답장을 보내 주셔서 감사합니다. 그러나 그것은 정말로 질문에 대답하지 않았습니다. 문제는 우선 순위가 높은 클래스 메소드의 형식과 관련이 있습니다. 하위 클래스에 대한 편리한 메소드를 생성 할 필요성을 제외하고는 클래스 메소드를 재정의해야 할 이유가 확실하지 않습니다. 이와 같이, 나는 이것에 관해 아직 아무것도 보지 못했다. 내가 사용한 형식이 적절한 지 확인하는 예제가 있습니까? –

+0

@BrianPalma 죄송합니다. 아마도 나는 그 말이 맞지 않았을 것입니다. 나는 초기화 메소드와 같은 방법으로 클래스 메소드를 수행하는 것이 허용되지 않는 이유를 실제로 알지 못한다. 클래스 메소드는 init 메소드를 호출하고, 코드를 수행하며, 자동 완성 된 버전을 반환하는 경향이 있습니다. 형식을 확인하는 예제가 있는지 모르지만 그로 인해 발생할 수있는 문제는 볼 수 없습니다. 몇 가지 샘플 코드를 확인하고 다시 알려 드리겠습니다. – MadhavanRP

2

네의 대상을 가리킬 수 있기 때문

또한, 그것은 중요하지 않습니다, 그것은 그것을 할 수있는 완벽하게 합리적인 방법입니다. 클래스 메소드와 일반 메소드 사이에는 특별한 차이가 없습니다. 하나는 클래스에 의해 수행되고 다른 하나는 인스턴스에 의해 수행된다는 것입니다.

2

클래스 메소드를 오버라이드하는 순간 슈퍼 구현의 도움을 받거나 구현하지 않고 구현할 수 있습니다. 그것은 전적으로 당신에게 달려 있습니다. Init를 오버라이드한다는 것은 완전히 다른 이야기입니다. 인스턴스 메소드이기 때문에뿐만 아니라 관련된 컨벤션/계약이 있기 때문에입니다. 예를 들어, Liskov Subtitution 원칙을 위반해서는 안됩니다.

클래스 메서드를 무시하면 디자인 냄새가 있다고 생각되지만 클래스 메서드를 재정의하면 완벽하게 괜찮습니다. Objective-C에서 가능하지만 다른 언어에서는 그렇지 않습니다. 아주 좋은 이유입니다. 다형성을 개념으로 사용하는 것이 서로의 대체물로 사용될 수있는 인스턴스에 더 잘 바인딩되는 반면 클래스 메소드를 사용하면 개념이 깨집니다 (즉, 실제 제외가 없음).그것은 영리하지만 필수적으로 직관적이고 유연하지는 않습니다.

+0

답장을 보내 주셔서 감사합니다. 아래에서 언급했듯이, 편리한 메소드의 코드가 적을 때를 제외하고 서브 클래스에서 특정 클래스 메소드를 대체하는 용도에 대해서는 알지 못합니다. 이 시점에서 나는 그렇게 할 의사가 없습니다. 상황이 발생하면 나는 적절한 구현에 대해서만 궁금해했다. –

+0

@BrianPalma : "편의 방법"이외의 클래스 메서드를 재정의해야하는 이유가 있습니다. 예를 들어, NSView의'defaultMenu'와'requiresConstraintBasedLayout' 클래스 메소드는 단지 오버라이드 될뿐입니다. – Chuck

+0

@Chuck 죄송합니다, 나는 잘못 생각했거나 너무 작습니다! 모델 개체의 측면에서 "편의 방법"을 의미합니다. iOS 및 OS X에는 순수하게 재정의되어 [super someClassMethodHere]가 필요한 클래스 메소드가 있다는 것을 알고 있습니다. –

관련 문제