programing

Objective-C에서 -init 메서드를 비공개로 할 수 있습니까?

easyjava 2023. 5. 4. 20:44
반응형

Objective-C에서 -init 메서드를 비공개로 할 수 있습니까?

나는 그것을 숨길 필요가 있습니다.-init목표-C에서 내 수업의 방법.

내가 어떻게 그럴 수 있을까?

NS_UNAVAILABLE

- (instancetype)init NS_UNAVAILABLE;

사용할 수 없는 특성의 간략한 버전입니다.이것은 macOS 10.7iOS 5에서 처음 등장했습니다.NSObjCRuntime에 정의되어 있습니다. has#define NS_UNAVAILABLE UNAVAILABLE_ATTRIBUTE.

ObjC 코드가 아닌 Swift 클라이언트에 대해서만 메서드를 비활성화하는 버전이 있습니다.

- (instancetype)init NS_SWIFT_UNAVAILABLE;

unavailable

헤더에 속성을 추가하여 init 호출 시 컴파일러 오류를 생성합니다.

-(instancetype) init __attribute__((unavailable("init not available")));  

컴파일 시간 오류

이유가 없으면 입력하십시오.__attribute__((unavailable))아니 심지어는__unavailable:

-(instancetype) __unavailable init;  

doesNotRecognizeSelector:

NSInvalidArgument를 제기하는 데 사용합니다.예외."런타임 시스템은 객체가 응답할 수 없거나 전달할 수 없는 Selector 메시지를 수신할 때마다 이 메서드를 호출합니다."

- (instancetype) init {
    [self release];
    [super doesNotRecognizeSelector:_cmd];
    return nil;
}

NSAssert

이 명령을 사용하여 NSInternalInconsistencyException을 던지고 다음 메시지를 표시합니다.

- (instancetype) init {
    [self release];
    NSAssert(false,@"unavailable, use initWithBlah: instead");
    return nil;
}

raise:format:

사용자 자신의 예외를 던집니다.

- (instancetype) init {
    [self release];
    [NSException raise:NSGenericException 
                format:@"Disabled. Use +[[%@ alloc] %@] instead",
                       NSStringFromClass([self class]),
                       NSStringFromSelector(@selector(initWithStateDictionary:))];
    return nil;
}

[self release] 존재했기 때문에 필요합니다.allocARC를 사용하면 컴파일러가 호출합니다.어쨌든, 의도적으로 실행을 중단하려고 할 때는 걱정할 필요가 없습니다.

objc_designated_initializer

사용하지 않도록 설정하려는 경우init지정된 이니셜라이저를 강제로 사용하려면 다음과 같은 속성이 있습니다.

-(instancetype)myOwnInit NS_DESIGNATED_INITIALIZER;

다른 이니셜라이저 메서드가 호출하지 않는 한 경고가 생성됩니다.myOwnInit내부적으로자세한 내용은 다음 Xcode 릴리스 이후에 Modern Objective-C 채택에 게시될 것입니다(아마도).

Apple은 헤더 파일에서 다음을 사용하여 init 생성자를 비활성화하기 시작했습니다.

- (instancetype)init NS_UNAVAILABLE;

Xcode에서 컴파일러 오류로 올바르게 표시됩니다.특히, 이 설정은 여러 HealthKit 헤더 파일에 설정됩니다(HKUnit도 그 중 하나입니다).

목표-C는 스몰토크와 마찬가지로 "프라이빗" 대 "퍼블릭" 방식의 개념이 없습니다.모든 메시지는 언제든지 모든 개체로 전송될 수 있습니다.

당신이 할 수 있는 것은 던지는 것입니다.NSInternalInconsistencyException만약 당신이-init메서드가 호출됩니다.

- (id)init {
    [self release];
    @throw [NSException exceptionWithName:NSInternalInconsistencyException
                                   reason:@"-init is not a valid initializer for the class Foo"
                                 userInfo:nil];
    return nil;
}

다른 대안은 - 아마도 실무에서 훨씬 더 나은 - 을 만드는 것입니다.-init가능하다면 당신의 수업을 위해 합리적인 것을 하세요.

싱글톤 개체가 사용되는지 "확인"하기 위해 이 작업을 수행하려는 경우에는 신경 쓰지 마십시오.구체적으로, "오버라이드"를 신경쓰지 마세요.+allocWithZone:,-init,-retain,-release싱글톤을 만드는 방법.이는 사실상 항상 불필요하며 실질적인 이점을 제공하지 않고 복잡성만 가중시키고 있습니다.

의 신에의, 당신코그쓰렇세요가 되도록 .+sharedWhatever메소드는 싱글톤에 액세스하는 방법이며 헤더에 싱글톤 인스턴스를 가져오는 방법으로 문서화합니다.대부분의 경우 그것이 당신이 필요로 하는 전부일 것입니다.

음을다사여사용수할없선수있언습다니할서메를을 사용하여 사용할 수 할 수 .NS_UNAVAILABLE.

그래서 당신은 이 선들을 당신의 @인터페이스 아래에 둘 수 있습니다.

- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;

접두사 헤더에 매크로를 더욱 잘 정의

#define NO_INIT \
- (instancetype)init NS_UNAVAILABLE; \
+ (instancetype)new NS_UNAVAILABLE;

그리고.

@interface YourClass : NSObject
NO_INIT

// Your properties and messages

@end

그것은 당신이 말하는 "사적으로 만들기"에 달려 있습니다.Objective-C에서 개체에 대한 메서드를 호출하는 것은 해당 개체에 메시지를 보내는 것으로 설명하는 것이 좋습니다.클라이언트가 개체에 대해 지정된 메서드를 호출하는 것을 금지하는 언어는 없습니다. 헤더 파일에 메서드를 선언하지 않는 것이 최선입니다.그럼에도 불구하고 클라이언트가 올바른 서명을 사용하여 "개인" 메서드를 호출하는 경우 클라이언트는 런타임에 계속 실행됩니다.

즉, Objective-C에서 개인 메서드를 만드는 가장 일반적인 방법은 구현 파일에 카테고리를 만들고 그 안에 있는 모든 "숨겨진" 메서드를 선언하는 것입니다.이것이 진정으로 전화를 막는 것은 아니라는 것을 기억하세요.init실행 중이지만 컴파일러가 이 작업을 수행하려고 하면 경고를 뱉습니다.

나의 수업

@interface MyClass (PrivateMethods)
- (NSString*) init;
@end

@implementation MyClass

- (NSString*) init
{
    // code...
}

@end

MacRumors.com 에는 이 주제에 대한 적절한 스레드가 있습니다.

default-init 방법을 말하는 경우에는 할 수 없습니다.NSObject에서 상속되며 모든 클래스가 경고 없이 응답합니다.

Matt가 제안하는 바와 같이 -init MyClass라는 새로운 메소드를 만들어 개인 범주에 넣을 수 있습니다.그런 다음 default -init 메서드를 정의하여 예외가 호출된 경우 예외를 발생시키거나 (더 나은) 일부 기본값으로 private -initMyClass를 호출합니다.

사람들이 그것을 숨기고 싶어하는 것처럼 보이는 주요 이유 중 하나는 싱글톤 물체 때문입니다.그런 경우에는 -init를 숨길 필요가 없으며, 대신 singleton 개체를 반환합니다(또는 아직 존재하지 않는 경우에는 생성).

헤더 파일에 저장

- (id)init UNAVAILABLE_ATTRIBUTE;

글쎄요, 당신이 그것을 "개인/보이지 않는"으로 만들 수 없는 문제는 init 메서드가 당신의 클래스가 아닌 id로 전송되기 때문입니다.

컴파일러(프로파일러)의 시점에서 id는 입력된 모든 것에 잠재적으로 응답할 수 있으므로(실행 시 id에 실제로 무엇이 들어가는지 확인할 수 없음), 컴파일러가 알고 있는 것보다 id가 id에 응답할 수 있는 방법이 없다는 것을 알 수 있는 어떤 곳도 없을 때만 id를 숨길 수 있습니다.어디에도 없기 때문에 (당신의 소스, 모든 립 등에서).

그래서 당신은 사용자가 그것을 지나쳐 컴파일러에 의해 박살나는 것을 막을 수 없습니다...하지만 당신이 할 수 있는 것은 사용자가 init를 호출하여 실제 인스턴스를 얻는 것을 막는 것입니다.

단순히 init를 구현함으로써, none을 반환하고 다른 사람이 받을 수 없는 (개인/보이지 않는) 이니셜라이저가 있습니다(예: initOnce, initWithSpecial...).

static SomeClass * SInstance = nil;

- (id)init
{
    // possibly throw smth. here
    return nil;
}

- (id)initOnce
{
    self = [super init];
    if (self) {
        return self;
    }
    return nil;
}

+ (SomeClass *) shared 
{
    if (nil == SInstance) {
        SInstance = [[SomeClass alloc] initOnce];
    }
    return SInstance;
}

참고: 누군가가 이 작업을 수행할 수 있습니다.

SomeClass * c = [[SomeClass alloc] initOnce];

그리고 실제로 새 인스턴스를 반환하지만, 프로젝트에서 initOnce가 공개적으로(헤더에서) 선언되지 않으면 경고(id가 응답하지 않을 수 있음...)가 생성되고, 어쨌든 이를 사용하는 사람은 실제 이니셜라이저가 initOnce라는 것을 정확히 알아야 합니다.

우리는 이것을 훨씬 더 막을 수 있지만, 필요 없습니다.

하위 클래스에 방법을 숨기기 위해 주장을 하고 예외를 제기하는 것은 선의의 사람들에게 나쁜 함정이라는 것을 언급해야 합니다.

을 사용하는 것이 좋습니다.__unavailable자노가 첫 번째 예로 설명했듯이.

메서드는 하위 클래스에서 재정의될 수 있습니다.즉, 슈퍼클래스의 메서드가 서브클래스에서 예외를 발생시키는 메서드를 사용하는 경우에는 의도한 대로 작동하지 않을 수 있습니다.다시 말해, 당신은 예전에 작동했던 것을 깨뜨린 것입니다.이는 초기화 방법에서도 마찬가지입니다.다음은 이러한 일반적인 구현의 예입니다.

- (SuperClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
    ...bla bla...
    return self;
}

- (SuperClass *)initWithLessParameters:(Type1 *)arg1
{
    self = [self initWithParameters:arg1 optional:DEFAULT_ARG2];
    return self;
}

하위 클래스에서 이 작업을 수행하면 -initWithLessParameters가 어떻게 되는지 상상해 보십시오.

- (SubClass *)initWithParameters:(Type1 *)arg1 optional:(Type2 *)arg2
{
    [self release];
    [super doesNotRecognizeSelector:_cmd];
    return nil;
}

이는 특히 초기화 방법에서 메서드를 재정의하지 않는 한 개인(숨김) 메서드를 사용해야 한다는 것을 의미합니다.그러나 슈퍼클래스의 구현을 항상 완전히 제어할 수 있는 것은 아니기 때문에 이것은 다른 주제입니다.(이것은 __attribute((objc_designated_initializer)를 심층적으로 사용하지는 않았지만 나쁜 관행으로 사용하는 것에 의문을 갖게 합니다.)

또한 하위 클래스에서 재정의해야 하는 메서드에 어설션 및 예외를 사용할 수 있음을 의미합니다.(Objective-C에서 추상 클래스를 만들 와 같은 "추상적" 방법)

그리고 +new 클래스 방법도 잊지 마세요.

언급URL : https://stackoverflow.com/questions/195078/is-it-possible-to-make-the-init-method-private-in-objective-c

반응형