Index: src/OFObject.h ================================================================== --- src/OFObject.h +++ src/OFObject.h @@ -808,10 +808,22 @@ - (void)performSelector: (SEL)selector onThread: (OFThread*)thread withObject: (id)object1 withObject: (id)object2 afterDelay: (double)delay; + +/*! + * @brief This method is called when @ref resolveClassMethod: or + * @ref resolveInstanceMethod: returned NO. It should return a target + * to which the message should be forwarded. + * + * @note When the message should not be forwarded, you should not return nil, + * but instead return the result of the superclass! + * + * @return The target to forward the message to + */ +- (id)forwardingTargetForSelector: (SEL)selector; @end /*! * @brief A protocol for the creation of copies. */ Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -124,44 +124,51 @@ } static IMP forward_handler(id obj, SEL sel) { + id target; + + /* Try resolveClassMethod:/resolveInstanceMethod: */ if (class_isMetaClass(object_getClass(obj))) { - if (![obj respondsToSelector: @selector(resolveClassMethod:)]) - return method_not_found_handler; - - if (![obj resolveClassMethod: sel]) - return method_not_found_handler; - - if (![obj respondsToSelector: sel]) { - fprintf(stderr, "Runtime error: [%s " - "resolveClassMethod: %s] returned YES without " - "adding the method!\n", class_getName(obj), - sel_getName(sel)); - abort(); + if ([obj respondsToSelector: @selector(resolveClassMethod:)] && + [obj resolveClassMethod: sel]) { + if (![obj respondsToSelector: sel]) { + fprintf(stderr, "Runtime error: [%s " + "resolveClassMethod: %s] returned YES " + "without adding the method!\n", + class_getName(obj), sel_getName(sel)); + abort(); + } + + return objc_msg_lookup(obj, sel); } } else { Class c = object_getClass(obj); - if (![c respondsToSelector: @selector(resolveInstanceMethod:)]) - return method_not_found_handler; - - if (![c resolveInstanceMethod: sel]) - return method_not_found_handler; - - if (![obj respondsToSelector: sel]) { - fprintf(stderr, "Runtime error: [%s " - "resolveInstanceMethod: %s] returned YES without " - "adding the method!\n", - class_getName(object_getClass(obj)), - sel_getName(sel)); - abort(); + if ([c respondsToSelector: @selector(resolveInstanceMethod:)] && + [c resolveInstanceMethod: sel]) { + if (![obj respondsToSelector: sel]) { + fprintf(stderr, "Runtime error: [%s " + "resolveInstanceMethod: %s] returned YES " + "without adding the method!\n", + class_getName(object_getClass(obj)), + sel_getName(sel)); + abort(); + } + + return objc_msg_lookup(obj, sel); } } - return objc_msg_lookup(obj, sel); + /* Try forwardingTargetForSelector: */ + target = [obj forwardingTargetForSelector: sel]; + + if (target != obj && target != nil) + return objc_msg_lookup(target, sel); + + return method_not_found_handler; } #endif #ifndef HAVE_OBJC_ENUMERATIONMUTATION void @@ -951,10 +958,15 @@ /* To detect double-free */ PRE_MEM(pointer)->owner = nil; free(PRE_MEM(pointer)); } + +- (id)forwardingTargetForSelector: (SEL)selector +{ + return nil; +} - retain { #if defined(OF_ATOMIC_OPS) of_atomic_inc_32(&PRE_IVAR->retainCount);