0

I have a dictionary. I extract one of its values as follows:

NSString *magicValue= [filterDict valueForKey:[filterDict allKeys][0]];
[SomeClass foo: magicValue];

And foo is:

- (void)foo:(NSString*)magicValue
{
    NSLog("magicValue is string:%@",[magic isKindOfClass:[NSString class]] ? @"YES" : @"NO");
    NSLog("magicValue is number:%@",[magic isKindOfClass:[NSNumber class]] ? @"YES" : @"NO");
}

If the dictionary value is number magicValue will be NSNumber. So the defined string pointer will be pointing to an NSNumber. The log will return yes for the number check.

I never added protection to such methods, to check what class "magicValue" is. I assumed that when I define a method with string parameter it will be string.

Should I start accounting for such behavior and always add checks, or is it the fault of the guy that assigned that dictionary value to magic in such a way and used my method. I need some best practices advice and how to handle this.

This question could have already been answered but I didn't know how to search for it.

h3dkandi
  • 1,106
  • 1
  • 12
  • 27

2 Answers2

1

Most of the time you should know what class you're referencing, or at least what you intend it to be. On the occasions where you have an uexpected class which can cause a crash depending on what messages you send to it, you can then debug your code and get the correct reference.

There are times, usually when dealing with inheritance, when you need to determine the class at runtime rather than at compile time. This is when, isKindOfClass: can be useful. If you know that a value could be one of many classes, I would extract it as an id and then cast it at the last moment e.g.

id value = [[NSUserDefaults standardUserDefaults] valueForKey:aKey];
if ([value isKindOfClass:[MyClass class]]) {
    // Do one thing
}
else {
    // Do another
}
Rob Sanders
  • 5,197
  • 3
  • 31
  • 58
1

Short answer: No, do not check that, if there is no special reason.

Long answer:

You have to differentiate between two cases:

A. Using id

You have a variable or a return vale of the type id. This is in your example -valueForKey:. The reason for that typing is to keep the method generic. Even it is theoretically possible, in practice a type mismatch in such situation is very rare and detected fast in development. With a different motivation I asked the audience (>200) in a public talk, how many times they had such a typing error in production. For all listeners, all of their apps in all of the app's versions there was 1(in words: one!) case. Simply forget about that risk. It is the anxiety of developers using statically typing languages (Java, C++, Swift).

B. Wrong assignment

If you do not have an id type, it is still possible to do such tricks. (And sometimes you want to do that. That is a strength of dynamic typing.) There are two subcategories:

You can do it implicitly:

NSString *string = [NSNumber numberWithInt:1];

The compiler will warn you about that. So everything is fine, because the developer will see his mistake. You do not have to protect him or your code.

One can do it explicitly:

NSString *string = (NSString*)[NSNumber numberWithInt:1];

In such a case, code can break. But he did it explicitly. If it is wrong, the developer had criminal energy to do so and you do not have to protect him from himself.

Amin Negm-Awad
  • 16,582
  • 3
  • 35
  • 50