Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -431,15 +431,29 @@ /*! * @brief A method which is called once when the class is loaded into the * runtime. * - * Derived classes can overide this to execute their own code when the class is - * loaded. + * Derived classes can override this to execute their own code when the class + * is loaded. */ + (void)load; +/*! + * @brief A method which is called when the class is unloaded from the runtime. + * + * Derived classes can override this to execute their own code when the class + * is unloaded. + * + * @warning This is not supported by the Apple runtime and currently only + * called by the ObjFW runtime when objc_unregister_class() or + * objc_exit() has been called! + * In the future, this might also be called by the ObjFW runtime when + * the class is part of a plugin that has been unloaded. + */ ++ (void)unload; + /*! * @brief A method which is called the moment before the first call to the class * is being made. * * Derived classes can override this to execute their own code on Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -241,10 +241,14 @@ gettimeofday(&t, NULL); srand((unsigned)(t.tv_sec ^ t.tv_usec)); of_hash_seed = (uint32_t)((rand() << 16) | (rand() & 0xFFFF)); #endif } + ++ (void)unload +{ +} + (void)initialize { } Index: src/runtime/class.m ================================================================== --- src/runtime/class.m +++ src/runtime/class.m @@ -243,13 +243,16 @@ (uint32_t)ml->methods[j].sel.uid, ml->methods[j].imp); } } - if (cls->subclass_list != NULL) - for (i = 0; cls->subclass_list[i] != NULL; i++) - objc_update_dtable(cls->subclass_list[i]); + if (cls->subclass_list != NULL) { + Class *iter; + + for (iter = cls->subclass_list; *iter != NULL; iter++) + objc_update_dtable(*iter); + } } static void add_subclass(Class cls) { @@ -808,10 +811,35 @@ static void unregister_class(Class rcls) { struct objc_abi_class *cls = (struct objc_abi_class*)rcls; + + if ((rcls->info & OBJC_CLASS_INFO_SETUP) && + rcls->superclass != Nil && + rcls->superclass->subclass_list != NULL) { + size_t i = SIZE_MAX, count = 0; + Class *tmp; + + for (tmp = rcls->superclass->subclass_list; + *tmp != Nil; tmp++) { + if (*tmp == rcls) + i = count; + + count++; + } + + if (count > 0 && i < SIZE_MAX) { + tmp = rcls->superclass->subclass_list; + tmp[i] = tmp[count - 1]; + tmp[count - 1] = NULL; + + if ((tmp = realloc(rcls->superclass->subclass_list, + count * sizeof(Class))) != NULL) + rcls->superclass->subclass_list = tmp; + } + } if (rcls->subclass_list != NULL) { free(rcls->subclass_list); rcls->subclass_list = NULL; } @@ -821,18 +849,26 @@ rcls->dtable = NULL; if (rcls->superclass != Nil) cls->superclass = rcls->superclass->name; + + rcls->info &= ~OBJC_CLASS_INFO_SETUP; } void objc_unregister_class(Class cls) { + while (cls->subclass_list != NULL && cls->subclass_list[0] != Nil) + objc_unregister_class(cls->subclass_list[0]); + + if (cls->info & OBJC_CLASS_INFO_LOADED) + call_method(cls, "unload"); + objc_hashtable_set(classes, cls->name, NULL); - if (strcmp(cls->name, "Protocol")) + if (strcmp(class_getName(cls), "Protocol")) classes_cnt--; unregister_class(cls); unregister_class(cls->isa); }