Method resolution priority between categories and class extensions
0 reputation · 12 Aug 2020, 06:25 UTC
0 reputation · 12 Aug 2020, 06:25 UTC
Objective-C utilizes a dynamic messaging system where objc_msgSend resolves selectors at runtime. When a class incorporates both category methods and class extensions, the runtime must determine the priority of method resolution, particularly when these definitions overlap within a complex inheritance chain.
The runtime behavior regarding category method collisions is documented: the last category loaded typically overrides previous implementations. However, the interaction between these category-defined methods and methods declared in class extensions or subclasses introduces ambiguity in the dispatch order.
Given a scenario where a method is defined in a category of a superclass and also within a class extension of a subclass, the resolution priority remains a point of design uncertainty.
In the Objective-C runtime, method resolution is determined by how objc_msgSend traverses the class hierarchy. When a conflict occurs between categories and class extensions (anonymous categories), the priority depends on where the methods are defined relative to the class receiving the message.
Does the class extension take precedence over a category method defined in the same class?
Yes. If a category and a class extension define the same selector on the same class, the class extension typically takes precedence. This is because class extensions are compiled into the class's method table at compile time, whereas category methods are prepended to the method list at load time.
How does the runtime prioritize a category method in a superclass versus a class extension in a subclass?
The class extension in the subclass takes priority. The runtime begins its search at the class of the receiver and moves up the inheritance chain. Since the extension is part of the subclass's method table, the runtime finds that implementation before it ever reaches the superclass's category definitions.
To understand why this happens, consider the order of operations the runtime performs during dispatch:
While the hierarchy is predictable, collisions within the same class are a common source of bugs:
If you need to ensure a specific implementation is used regardless of load order, use method_replaceImplementations to manually swap or fix selectors at runtime during initialization.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.