NSObject + load и + initialize-что они делают?



Я заинтересован в понимании обстоятельств, приводящих разработчика к переопределению +initialize или +load. Документация дает понять, что эти методы вызываются для вас средой выполнения Objective-C, но это действительно все, что ясно из документации этих методов. : -)



мое любопытство связано с тем, что я смотрю на пример кода Apple - MVCNetworking. Их класс модели имеет +(void) applicationStartup метод. Он делает небольшую уборку в файловой системе, считывает NSDefaults и т. д. и т. п... и, после попытки использовать методы класса grok NSObject кажется, что эта вспомогательная работа может быть в порядке, чтобы поместить в +load.



Я изменил проект MVCNetworking, удалив вызов делегата приложения в + applicationStartup и поместив биты домашнего хозяйства в +load... мой компьютер не загорелся, но это не значит, что это правильно! Я надеюсь получить представление о любых тонкостях, gotchas и тому подобном вокруг пользовательского метода настройки, который вы должны вызвать versus + load или +инициализировать.





для + load документация говорит:




сообщение о загрузке отправляется в классы и категории, которые являются обоими
динамически и статически, но только если загруженные
класс или категория реализует метод, который может ответить.




это предложение является kludgey и трудно разобрать, если вы не знаете точного значения всех слов. Помогите!




  • что значит "как динамически и статически?"Может ли что-то быть динамически загружено и статически связано, или они взаимоисключающие?


  • "...недавно загруженный класс или категория реализует метод, который может ответить" какой метод? Как реагировать?





Что касается + initialize, документация говорит:




инициализации вызывается только один раз для каждого класса. Если вы хотите выполнить
независимая инициализация для класса и для категорий
класса, вы должны реализовать методы загрузки.




Я понимаю это так: "если вы пытаетесь настроить класс... не используйте инициализировать.- Ладно, ладно. Когда или почему я должен переопределить инициализацию?

468   2  

2 ответов:

The 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 сообщение для объекта класса после его отправки элемент load сообщение для всех объектов суперкласса класса (если эти объекты суперкласса реализации load) и все объекты класса в общих библиотеках, на которые вы ссылаетесь. Но вы не знаете, какие другие классы в вашем собственном исполняемом файле получили load еще.

каждый класс, который ваш процесс загружает в свое адресное пространство, получит load сообщение, если оно реализует load метод, независимо от того, делает ли ваш процесс любое другое использование класс.

вы можете видеть, как среда выполнения ищет load метод как частный случай в _class_getLoadMethod на objc-runtime-new.mm, и вызывает его непосредственно из call_class_loads in objc-loadmethod.mm.

среда выполнения также работает load метод каждой категории он загружает, даже если несколько категорий в одном классе реализуют load.  Это необычно.  Обычно, если две категории определяют один и тот же метод в одном классе, один из методов "выиграет" и будет используется и другой метод никогда не вызывается.

The initialize метод

среда выполнения вызывает initialize метод на объекте класса непосредственно перед отправкой первого сообщения (кроме load или initialize) к объекту класса или любым экземплярам класса. Это сообщение отправлено с помощью обычного механизма, так что если ваш класс не реализует initialize, но наследует от класса, который делает, то ваш класс будет использовать свой суперкласс initialize. Среда выполнения будет отправлять элемент initialize сначала всем суперклассам класса (если суперклассы еще не были отправлены initialize).

пример:

@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;
}

эта программа выводит две строки вывода:

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

так как система отправляет initialize метод лениво, класс не получит сообщение, если ваша программа фактически не отправляет сообщения в класс (или подкласс, или экземпляры класса или подклассов). И к тому времени, как вы получите initialize, каждый класс в ваш процесс должен был уже получить load (если это уместно).

канонический способ реализации initialize это:

@implementation Someclass

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

смысл этого шаблона заключается в том, чтобы избежать Someclass повторная инициализация себя, когда он имеет подкласс, который не реализует initialize.

среда выполнения отправляет initialize сообщение

что это значит, не переопределять +initialize в категории, вы, вероятно, сломать что-то.

+load вызывается один раз для каждого класса или категории, реализующий +load,как только этот класс или категория загружается. Когда он говорит "статически связанный", это означает, что он скомпилирован в двоичный файл вашего приложения. Элемент +load методы в классах, скомпилированных таким образом, будут выполняться при запуске вашего приложения, вероятно, до его ввода main(). Когда он говорит "динамически", это означает, загружается через пакеты плагинов или вызов dlopen(). Если вы находитесь на iOS, вы можете игнорировать этот случай.

+initialize вызывается при первой отправке сообщения в класс, непосредственно перед обработкой этого сообщения. Это (очевидно) происходит только один раз. Если вы переопределите +initialize в категории произойдет одна из трех вещей:

  • ваша реализация категории вызывается, а реализация класса не
  • реализация чужой категории получает звонил; ничего ты не написал
  • ваша категория еще не загружена, и ее реализация никогда не вызывается.

вот почему вы никогда не должны переопределить +initialize в категории - на самом деле это довольно опасно пытаться заменить любой метод в категории, потому что вы никогда не уверены, что вы заменяете или будет ли ваша собственная замена сама по себе отключена другой категорией.

кстати, еще один вопрос, чтобы рассмотреть с +initialize Это то, что если кто-то подклассы вас, вы потенциально получите вызов один раз для вашего класса и один раз для каждого подкласса. Если вы делаете что-то вроде настройки static переменные, вы хотите, чтобы защититься от этого: либо с dispatch_once() или путем тестирования self == [MyClass class].

Comments

    Ничего не найдено.