Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -376,10 +376,26 @@ * \return The old implementation */ + (IMP)replaceInstanceMethod: (SEL)selector withMethodFromClass: (Class)class_; +/** + * \brief Adds a class method to the class. + * + * If the method already exists, nothing is done and NO is returned. If you want + * to change the implementation of a method, use + * setImplementation:forClassMethod:. + * + * \param selector The selector for the new method + * \param typeEncoding The type encoding for the new method + * \param implementation The implementation for the new method + * \return Whether the method has been added + */ ++ (BOOL)addClassMethod: (SEL)selector + withTypeEncoding: (const char*)typeEncoding + implementation: (IMP)implementation; + /** * \brief Adds an instance method to the class. * * If the method already exists, nothing is done and NO is returned. If you want * to change the implementation of a method, use Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -338,31 +338,43 @@ selector: _cmd]; return objc_replace_class_method(self, selector, newImp); #elif defined(OF_OLD_GNU_RUNTIME) Method_t method; - IMP oldImp; + MethodList_t iter; - /* The class method is the instance method of the meta class */ - if ((method = class_get_instance_method(self->class_pointer, - selector)) == NULL) + method = class_get_class_method(self->class_pointer, selector); + + if (newImp == (IMP)0 || method == METHOD_NULL) @throw [OFInvalidArgumentException newWithClass: self selector: _cmd]; - if ((oldImp = method_get_imp(method)) == (IMP)0 || newImp == (IMP)0) - @throw [OFInvalidArgumentException newWithClass: self - selector: _cmd]; - - method->method_imp = newImp; - - /* Update the dtable if necessary */ - if (sarray_get_safe(((Class)self->class_pointer)->dtable, - (sidx)method->method_name->sel_id)) - sarray_at_put_safe(((Class)self->class_pointer)->dtable, - (sidx)method->method_name->sel_id, method->method_imp); - - return oldImp; + for (iter = ((Class)self->class_pointer)->methods; iter != NULL; + iter = iter->method_next) { + int i; + + for (i = 0; i < iter->method_count; i++) + if (sel_eq(iter->method_list[i].method_name, + selector)) { + IMP oldImp; + + oldImp = iter->method_list[i].method_imp; + iter->method_list[i].method_imp = newImp; + + sarray_at_put_safe( + ((Class)self->class_pointer)->dtable, + (sidx)selector->sel_id, newImp); + + return oldImp; + } + } + + assert([self addClassMethod: selector + withTypeEncoding: method->method_types + implementation: newImp]); + + return (IMP)0; #else Method method; if (newImp == (IMP)0 || (method = class_getClassMethod(self, selector)) == NULL) @@ -401,30 +413,43 @@ @throw [OFInvalidArgumentException newWithClass: self selector: _cmd]; return objc_replace_instance_method(self, selector, newImp); #elif defined(OF_OLD_GNU_RUNTIME) - Method_t method = class_get_instance_method(self, selector); - IMP oldImp; - - if (method == NULL) - @throw [OFInvalidArgumentException newWithClass: self - selector: _cmd]; - - if ((oldImp = method_get_imp(method)) == (IMP)0 || newImp == (IMP)0) + Method_t method; + MethodList_t iter; + + method = class_get_instance_method(self, selector); + + if (newImp == (IMP)0 || method == METHOD_NULL) @throw [OFInvalidArgumentException newWithClass: self selector: _cmd]; - method->method_imp = newImp; - - /* Update the dtable if necessary */ - if (sarray_get_safe(((Class)self)->dtable, - (sidx)method->method_name->sel_id)) - sarray_at_put_safe(((Class)self)->dtable, - (sidx)method->method_name->sel_id, method->method_imp); - - return oldImp; + for (iter = ((Class)self)->methods; iter != NULL; + iter = iter->method_next) { + int i; + + for (i = 0; i < iter->method_count; i++) + if (sel_eq(iter->method_list[i].method_name, + selector)) { + IMP oldImp; + + oldImp = iter->method_list[i].method_imp; + iter->method_list[i].method_imp = newImp; + + sarray_at_put_safe(((Class)self)->dtable, + (sidx)selector->sel_id, newImp); + + return oldImp; + } + } + + assert([self addInstanceMethod: selector + withTypeEncoding: method->method_types + implementation: newImp]); + + return (IMP)0; #else Method method; if (newImp == (IMP)0 || (method = class_getInstanceMethod(self, selector)) == NULL)