Objective-C의 보호 된 메서드


112

Objective-C의 보호 된 메소드와 동등한 것은 무엇입니까? 파생 클래스 만 호출 / 구현할 수있는 메서드를 정의하고 싶습니다.

답변:


47

protected 또는 private 메서드를 선언 할 수 없습니다 . Objective-C의 동적 특성은 메서드에 대한 액세스 제어를 구현하는 것을 불가능하게합니다. (컴파일러 나 런타임을 대폭 수정하여 상당한 속도 저하로이를 수행 할 수 있지만 명백한 이유로이 작업은 수행되지 않습니다.)

출처 에서 가져옴 .


기술적으로는 할 수 없지만 개인 변수를 에뮬레이트 할 수 있습니다.
Sharen Eayrs

Lee-@protected에서 함수 포인터를 선언하고 init 메서드에서 함수를 할당하면 작동합니까?
bikram990

156

다음을 수행하여 메서드에 대한 보호 및 개인 액세스를 시뮬레이션 할 수 있습니다 .

  • 클래스 확장 (즉, 클래스의 .m 파일 상단 근처에 선언 된 명명되지 않은 범주)에서 개인 메서드를 선언합니다.
  • 보호 된 메서드를 Subclass 헤더에 선언 – Apple은 UIGestureRecognizer와 관련하여이 패턴을 사용합니다 (문서 및 UIGestureRecognizerSubclass.h에 대한 참조 참조).

이러한 보호 기능은 Sachin이 언급했듯이 런타임시 적용되지 않습니다 (예 : Java에서와 같이).


2
UIGestureRecognizer와 유사한 솔루션 정보 : 문제는 일부 코드가 하위 클래스를 가져 오면 Subclass 헤더도 가져 오므로 "보호 된"메서드에 액세스 할 수 있다는 것입니다. 그 주위에 방법이 있습니까?
yonix

5
안녕하세요 yonix, 하위 클래스 헤더에 대한 가져 오기는 .h 파일이 아닌 .m 파일 내에서 수행되므로 하위 클래스를 가져 오는 것은 이러한 보호 된 메서드를 가져 오지 않습니다.
Brian Westphal

멋진 제안 브라이언, 톤 감사합니다! 원래 포스터에 선언 된 속성의 경우 하위 클래스의 클래스 확장 (이름이 지정되지 않은 범주) 구현에서 @dynamic을 사용하여 런타임에 부모 클래스의 구현이 사용되도록합니다
user1046037

1
UIGestureRecognizerSubclass.h를 어떻게 볼 수 있습니까?
Sharen Eayrs

5
Apple이 내부적으로 어떻게 수행하는지 지적 해 주셔서 감사합니다. 나는 전체 예를 게시 물건을 애플에서와 같은 방식으로 구현하는 방법UIGestureRecognizerSubclass.h
더러운 헨리

14

다음은 메서드 자체를 구현하지 않고도 하위 클래스에 보호 된 메서드를 표시하기 위해 수행 한 작업입니다. 이것은 불완전한 구현에 대한 내 하위 클래스에서 컴파일러 경고를받지 않았 음을 의미합니다.

SuperClassProtectedMethods.h (프로토콜 파일) :

@protocol SuperClassProtectedMethods <NSObject>
- (void) protectMethod:(NSObject *)foo;
@end

@interface SuperClass (ProtectedMethods) < SuperClassProtectedMethods >
@end

SuperClass.m : (컴파일러는 이제 보호 된 메서드를 추가하도록 강제합니다)

#import "SuperClassProtectedMethods.h"
@implementation SuperClass
- (void) protectedMethod:(NSObject *)foo {}
@end

SubClass.m :

#import "SuperClassProtectedMethods.h"
// Subclass can now call the protected methods, but no external classes importing .h files will be able to see the protected methods.

2
protected 의 의미는 외부에서 호출 할 수 없다는 것입니다 . 외부에서 볼 수 있는지 여부에 관계없이 클래스에 정의 된 모든 메서드를 호출 할 수 있습니다.
eonil

네, 이해합니다. 이 방법은 실제 컴파일 된 코드가 아니라 인간의 두뇌에 적용됩니다. 그러나 Objective-C는이를 허용하지 않습니다 (외부에서 호출 할 수 없음). 당신은 항상 performSelector그것을 할 수 있습니다 .
Michael Kernahan

1
당신은 또한 할 수 있습니다 [(id)obj hiddenMethod]. 정확히 말하면 보호 된 방법은 Objective-C에서 지원되지 않습니다.
eonil

이것의 문제는 소위 보호 된 클래스가 속성을 광고 할 수 없다는 것입니다. 속성이 필요하지 않은 경우 보호 된 범주를 추가 할 수 있다는 사실을 누구나 잘 알고 있습니다.
Sharen Eayrs

@eonil : "[(id) obj hiddenMethod]도 할 수 있습니다." 예, 그렇게 할 수 있지만 해당 메서드가 포함 된 인터페이스에없는 경우 컴파일러에서 경고를 받게됩니다.
Kaiserludi

9

나는 방금 이것을 발견했고 그것은 나를 위해 작동합니다. Adam의 대답을 개선하려면 수퍼 클래스에서 .m 파일에서 보호 된 메서드를 구현하지만 .h 파일에서 선언하지 마십시오. 서브 클래스에서 슈퍼 클래스의 보호 된 메서드 선언으로 .m 파일에 새 범주를 만들고 서브 클래스에서 슈퍼 클래스의 보호 된 메서드를 사용할 수 있습니다. 이것은 궁극적으로 런타임에 강제로 보호되는 메서드의 호출자를 막지는 못합니다.

/////// SuperClass.h
@interface SuperClass

@end

/////// SuperClass.m
@implementation SuperClass
- (void) protectedMethod
{}
@end

/////// SubClass.h
@interface SubClass : SuperClass
@end

/////// SubClass.m
@interface SubClass (Protected)
- (void) protectedMethod ;
@end

@implementation SubClass
- (void) callerOfProtectedMethod
{
  [self protectedMethod] ; // this will not generate warning
} 
@end

2
이 경우 컴파일러는 여전히 구현되지 않은 메서드에 대한 경고를 발생 protectedMethod
시킵니다

이것은 좋은 해결 방법이지만 범주 (보호됨)를 만드는 대신 확장을 만들 수 있습니다.
다르 메쉬 Siddhpura

@skywinder 아마도 이전 버전에서했을 수도 있지만 현재 버전의 Xcode는이 솔루션에 문제가 없습니다.
Darren Ehlers

2

@protected 변수를 사용하는 또 다른 방법입니다.

@interface SuperClass:NSObject{
  @protected
    SEL protectedMehodSelector;
}

- (void) hackIt;
@end

@implementation SuperClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(baseHandling);
 }

return self;
}

- (void) baseHandling {

  // execute your code here
}

-(void) hackIt {

  [self performSelector: protectedMethodSelector];
}

@end

@interface SubClass:SuperClass
@end

@implementation SubClass

-(id)init{

self = [super init];
if(self) {
 protectedMethodSelector = @selector(customHandling);
 }

return self;
}

- (void) customHandling {

  // execute your custom code here
}

@end

보호 된 IVar를 protected라는 헤더 파일의 클래스 확장에 넣을 수 있습니다
malhal

1

메서드를 부모 클래스의 개인 메서드로 정의 할 수 [super performSelector:@selector(privateMethod)];있으며 자식 클래스에서 사용할 수 있습니다 .


0

당신은 할 수 종류의 범주로이 작업을 수행.

@interface SomeClass (Protected)
-(void)doMadProtectedThings;
@end

@implementation SomeClass (Protected)

- (void)doMadProtectedThings{
    NSLog(@"As long as the .h isn't imported into a class of completely different family, these methods will never be seen. You have to import this header into the subclasses of the super instance though.");
}

@end

다른 클래스에서 범주를 가져 오면 메서드가 숨겨지지는 않지만 숨겨지지는 않습니다. Objective-C의 동적 특성으로 인해 호출하는 인스턴스 유형에 관계없이 메서드를 완전히 숨기는 것은 실제로 불가능합니다.

가장 좋은 방법은 아마도 @Brian Westphal이 대답 한 클래스 연속 범주 일 것입니다. 그러나 각 하위 클래스 인스턴스에 대해이 범주의 메서드를 다시 정의해야합니다.


0

한 가지 옵션은 클래스 확장 을 사용 하여 메서드를 숨기는 것입니다.

에서 .h:

@interface SomeAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

에서 .m:

@interface SomeAppDelegate()
- (void)localMethod;
@end

@implementation SomeAppDelegate

- (void)localMethod
{
}

@end

@interface.m 파일에 선언이 필요하지 않다고 생각 합니다. 함수를 선언하고 사용할 수 있으며 개인용으로 취급됩니다.
Russ

1
이것은 Objective C의 최근 업데이트에서만 적용됩니다. 그 전에는 인터페이스에서 메서드를 선언해야했습니다. 그렇지 않으면 최소한 경고가 표시됩니다.
Guillaume Laurent

0

일반적으로 내부 접두사로 보호 된 메서드의 이름을 지정합니다.

-(void) internalMethod;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.