I am surprised at the quote you found indicating that the param and return parameters are important for the uniqueness of the method signature. After re-reading, I think you found an error in the document .
Determining the type of parameter in the interface will trigger a warning for callers who do not pass this type (or pass this parameter to this type), regardless of implementation. Changing a parameter type in an implementation is exactly the same as casting a parameter inside a method. There is nothing wrong with that, not even a reason for warning. As long as different types share methods (polymorphic or inherited) with the declared type.
In other words, an example repetition ...
The following will lead to a compiler error, proving that different types of parameters do not give any difference to the compiler (the same is true for the return type) ...
// .h - (void)foo:(NSString *)str; // .m - (void)foo:(NSString *)str { NSLog(@"called foo %@", [str class]); } - (void)foo:(NSNumber *)str { <----- duplicate declaration error }
The following are compiler warnings, errors or runtime errors ...
// .h - (void)foo:(NSString *)str; // .m - (void)foo:(NSNumber *)str { // everything implements 'class', so no problem here NSLog(@"called foo %@", [str class]); }
The following is exactly like the previous example in every way ...
// .h - (void)foo:(NSString *)str; // .m - (void)foo:(NSString *)str { NSNumber *number = (NSNumber *)str; NSLog(@"called foo %@", [number class]); }
The following warnings will not cause, but will generate a runtime error, because we abuse the act by invoking a method that the passed type does not implement (assuming the caller calls with a string, as the interface indicates) ...
// .h - (void)foo:(NSString *)str; // .m - (void)foo:(NSNumber *)str { NSLog(@"does str equal 2? %d", [str isEqualToNumber:@2]); <--- crash! }
All of the above corresponds to intuition and behavior in practice, just the wrong passage in the dock. An interesting find!