József Vesza
József Vesza

Reputation: 4795

Casting method parameters in Objective-C

Update

Okay, first of all, thank you all for the huge amount of activity. It seems that I did not phrase my question too well, since many of the answers got (rightfully) stuck on the id input parameter, and following poor design patterns, but it was merely an example. I'll add some context to my question:

With these assertions, here is my assumption: Given, that you know the type of the parameter, there is no benefit in type checking and casting, just for the sake of extra safety.

Original post

Suppose I have a general method in my protocol declaration, which takes an id input parameter:

@protocol MyProtocol <NSObject>

- (void)doSomethingWithParameter:(id)inputParameter;

@end

In a class, which conforms to MyProtocol, I usually prefer making the type of inputParameter explicit like so:

- (void)doSomethingWithParameter:(SpecificClass *)inputParameter
{
    /... do something with param
}

Occasionally I received critique for choosing this solution, as opposed to the following:

- (void)doSomethingWithParameter:(id)inputParameter
{
    if ([inputParameter isKindOfClass:[SpecificClass class]]) {
        SpecificClass *myInstance = (SpecificClass *)inputParameter;
        /... do something with param
    }
}

I really prefer the first version, since it clearly states the parameter my instance is expecting. It is more concise, and clear. I generally don't think I can gain much from type checking/casting.

My question: from a coding standard standpoint, which one is the better solution? Does the first one have any disadvantages?

Upvotes: 2

Views: 445

Answers (3)

Jakub Vano
Jakub Vano

Reputation: 3873

Update

From the update to your question, it seems that you are trying to achieve some variation of a functionality provided by the generics in modern languages.

Since Objective-C does not support this pattern, you can either sacrifice type safety, or rethink your design decisions.

If you go the first way, you should make it really clear by other means (naming, documentation) what types are you expecting. Then it might be reasonable to assume that your method will only be called with proper params.

But I would still add NSParameterAssert to simplify future debugging.


Original Answer

If you are using the first approach, you have a mismatch between declaration and definition of the method. Due to dynamic nature of obj-c (method signature does not include types of parameters), compiler does not complain about it.

However, when calling the method, only declaration is visible, so any information about the type of parameters is derived from that - all the type checking (yes, here compiler does it) is performed based on declaration.

In conclusion, to avoid confusing bugs and misuse of API, you should definitely use the second approach. Or change declaration together with definition.

Edit

Also, I can think of third solution, that somewhat merges convenience of the first approach with type safety of the second one:

- (void)doSomethingWithParameter:(SpecificClass *)inputParameter
{
    NSParameterAssert([inputParameter isKindOfClass:[SpecificClass class]]);

    // do something
}

Upvotes: 5

x4h1d
x4h1d

Reputation: 6092

First of all, when you use id for a parameter type that means either that type may vary or you may invoke method with ambiguous parameter. For both cases, second one is preferred as it checks type and prevents unwanted crash.

If you prefer the type of inputParameter explicit then simply define it in the protocol, like

@protocol MyProtocol <NSObject>
- (void)doSomethingWithParameter:(SpecificClass *)inputParameter;
@end

and for this forward declaration you may have to import module/class, like

#import "SpecificClass.h" // import class

OR

@class  SpecificClass; // import module

Upvotes: 1

gnasher729
gnasher729

Reputation: 52530

What you do is perfectly fine. If your method is called with a parameter that is an instance of the wrong class, that is a bug in the caller. In Objective-C, you don't work around bugs, you make them crash your code, and then you fix the bug (that is why nobody handles exceptions, exceptions are bugs in your code and when they crash your code, the cause of the exception needs to be fixed).

This is much more common when you pass blocks, for example a block testing array elements, where you know exactly what type of array to expect.

Upvotes: -2

Related Questions