Short answer: C.
Expansion: When the compiler generates a call to a method, it is really just generating a call to a C function -- to objc_msgSend() or variant therein -- that dynamically binds and dispatches the method.
Because the C ABI runs "at the metal" (pretty close), the way that arguments and return values are passed can change dramatically based on the type. For example, the compiler can pass anything up to 32 bits in size in a register (or 64 bits in some architectures), but anything larger will be on the stack itself.
Because of this, the compiler can't necessarily emit a generic bit of assembly to call objc_msgSend() -- to dispatch the method call -- through (id) as the different signatures -- the different argument types to the method -- may require different code generation.
Now, technically, the compiler could generate the same code for many cases, but it chooses to take a conservative policy and complain. In particular, the assumption is that if you have 2 conflicting typed declarations, there may be others and reminding you that having a method of the same name with different argument types is extremely strongly discouraged.