program tip

NSObject +로드 및 + 초기화-어떻게합니까?

radiobox 2020. 7. 27. 07:48
반응형

NSObject +로드 및 + 초기화-어떻게합니까?


개발자가 + initialize 또는 + load를 재정의하도록하는 상황을 이해하고 싶습니다. 설명서를 통해 Objective-C 런타임에서 이러한 메소드를 호출 할 수 있음을 분명히 알 수 있지만 실제로는 해당 메소드의 문서에서 명확합니다. :-)

호기심은 Apple의 예제 코드 인 MVCNetworking을 살펴 보는 것입니다. 그들의 모델 클래스에는 +(void) applicationStartup메소드가 있습니다. 파일 시스템에서 일부 하우스 키핑을 수행하고 NSDefaults 등을 읽습니다 .NSObject의 클래스 메소드를 취하려고 시도한 후이 정리 작업이 +로드에 들어가는 것처럼 보일 수 있습니다.

MVCNetworking 프로젝트를 수정하고 App Delegate에서 + applicationStartup에 대한 호출을 제거하고 하우스 키핑 비트를 +로드에 넣었습니다. 컴퓨터에서 불이 붙지 않았지만 그것이 옳은 것은 아닙니다! + load 또는 + initialize에 대해 호출 해야하는 사용자 지정 설정 방법에 대한 미묘함, 문제 및 기타 사항에 대한 이해를 얻고 싶습니다.


+로드 문서의 경우 :

로드 메시지는 동적으로로드되고 정적으로 링크 된 클래스 및 카테고리로 전송되지만 새로로드 된 클래스 또는 카테고리가 응답 할 수있는 메소드를 구현하는 경우에만 해당됩니다.

모든 문장의 정확한 의미를 모르면이 문장은 어색하고 파싱하기 어렵습니다. 도움!

  • "동적으로로드되고 정적으로 링크 된 것"이란 무엇입니까? 동적으로로드되고 정적으로 링크 될 수 있습니까? 아니면 상호 배타적입니까?

  • "... 새로로드 된 클래스 또는 카테고리는 응답 할 수있는 메소드를 구현합니다"어떤 메소드? 어떻게 응답합니까?


+ 초기화와 관련하여 설명서에 다음과 같이 나와 있습니다.

초기화는 클래스 당 한 번만 호출됩니다. 클래스 및 클래스 범주에 대해 독립적 인 초기화를 수행하려면로드 메소드를 구현해야합니다.

"클래스를 설정하려고하면 초기화를 사용하지 마십시오"라는 의미로 이것을 사용합니다. 좋아. 언제 또는 왜 초기화를 무시합니까?


load메시지

런타임은 load클래스 객체가 프로세스의 주소 공간에로드 된 직후에 각 클래스 객체에 메시지를 보냅니다 . 프로그램 실행 파일의 일부인 클래스의 경우, 런타임은 load프로세스 수명이 매우 일찍 메시지를 보냅니다 . 공유 (동적로드) 라이브러리에있는 클래스의 경우 런타임은 공유 라이브러리가 프로세스의 주소 공간에로드 된 직후로드 메시지를 보냅니다.

또한 load클래스 객체 자체가 load메소드를 구현하는 경우 런타임 은 클래스 객체 로만 보냅니다 . 예:

@interface Superclass : NSObject
@end

@interface Subclass : Superclass
@end

@implementation Superclass

+ (void)load {
    NSLog(@"in Superclass load");
}

@end

@implementation Subclass

// ... load not implemented in this class

@end

런타임은 load메시지를 Superclass클래스 객체 보냅니다 . 그것은 않습니다 하지 보내고 load받는 메시지 Subclass에도 불구하고, 클래스 객체 Subclass상속의 방법 Superclass.

런타임은 메시지를 모든 클래스의 수퍼 클래스 객체 (해당 수퍼 클래스 객체가 구현하는 경우 )와 링크 된 공유 라이브러리의 모든 클래스 객체에 load보낸 후에 메시지를 클래스 객체로 보냅니다 . 그러나 자신의 실행 파일에서 어떤 다른 클래스가 아직 받았는지 알 수 없습니다 .loadloadload

프로세스가 주소 공간에로드하는 모든 클래스는 프로세스가 클래스를 다른 용도로 사용하는지 여부에 관계없이 메소드를 load구현하는 경우 메시지 를 수신합니다 load.

You can see how the runtime looks up the load method as a special case in the _class_getLoadMethod of objc-runtime-new.mm, and calls it directly from call_class_loads in objc-loadmethod.mm.

The runtime also runs the load method of every category it loads, even if several categories on the same class implement load.  This is unusual.  Normally, if two categories define the same method on the same class, one of the methods will “win” and be used, and the other method will never be called.

The initialize Method

The runtime calls the initialize method on a class object just before sending the first message (other than load or initialize) to the class object or any instances of the class. This message is sent using the normal mechanism, so if your class doesn't implement initialize, but inherits from a class that does, then your class will use its superclass's initialize. The runtime will send the initialize to all of a class's superclasses first (if the superclasses haven't already been sent initialize).

Example:

@interface Superclass : NSObject
@end

@interface Subclass : Superclass
@end

@implementation Superclass

+ (void)initialize {
    NSLog(@"in Superclass initialize; self = %@", self);
}

@end

@implementation Subclass

// ... initialize not implemented in this class

@end

int main(int argc, char *argv[]) {
    @autoreleasepool {
        Subclass *object = [[Subclass alloc] init];
    }
    return 0;
}

This program prints two lines of output:

2012-11-10 16:18:38.984 testApp[7498:c07] in Superclass initialize; self = Superclass
2012-11-10 16:18:38.987 testApp[7498:c07] in Superclass initialize; self = Subclass

Since the system sends the initialize method lazily, a class won't receive the message unless your program actually sends messages to the class (or a subclass, or instances of the class or subclasses). And by the time you receive initialize, every class in your process should have already received load (if appropriate).

The canonical way to implement initialize is this:

@implementation Someclass

+ (void)initialize {
    if (self == [Someclass class]) {
        // do whatever
    }
}

The point of this pattern is to avoid Someclass re-initializing itself when it has a subclass that doesn't implement initialize.

The runtime sends the initialize message in the _class_initialize function in objc-initialize.mm. You can see that it uses objc_msgSend to send it, which is the normal message-sending function.

Further reading

Check out Mike Ash's Friday Q&A on this topic.


What it means is don't override +initialize in a category, you'll probably break something.

+load is called once per class or category that implements +load, as soon as that class or category is loaded. When it says "statically linked" it means compiled into your app binary. The +load methods on classes thus compiled will be executed when your app launches, probably before it enters main(). When it says "dynamically loaded", it means loaded via plugin bundles or a call to dlopen(). If you're on iOS, you can ignore that case.

+initialize is called the first time a message is sent to the class, just before it handles that message. This (obviously) only happens once. If you override +initialize in a category, one of three things will happen:

  • your category implementation gets called and the class's implementation doesn't
  • someone else's category implementation gets called; nothing you wrote does
  • your category hasn't been loaded yet and its implementation never gets called.

This is why you should never override +initialize in a category - in fact it's quite dangerous to try and replace any method in a category because you're never sure what you're replacing or whether your own replacement will itself be switched out by another category.

BTW, another issue to consider with +initialize is that if someone subclasses you, you'll potentially get called once for your class and once for each subclass. If you're doing something like setting up static variables, you'll want to guard against that: either with dispatch_once() or by testing self == [MyClass class].

참고URL : https://stackoverflow.com/questions/13326435/nsobject-load-and-initialize-what-do-they-do

반응형