For example if there is a 'handle all' type method...
if ([obj isKindOfClass:class1]) {
// ...
} else if ([obj isKindOfClass:class2]) {
// etc..
Is this bad practice? Is there a neater alternative or a better way to structure the code?
Are there disadvantages in tearms of runtime, readability, maintainability or anything?
Whenever something is considered good/bad practice, it is more or less subjective. When doing something is inherently right/wrong, it is more or less objective.
isKindOfClass: is a useful method to check class inheritance. It answers the only question, "is the object of a class which is (a subclass of) a given class?". It doesn't answer any other questions like "does this object implement that method in its own way?" or "can I use the object for X or Y?". If you use isKindOfClass: as intended, you won't have any problems. After all, in a dynamic typed language you ought to have tools to extract meta information about objects. isKindOfClass: is just one of the available tools.
The fact that certain objects may lie about their class should not really put you off. They just disguise themselves as objects of another class without breaking anything. And if that doesn't break anything, why should I care?
The main thing is that you should always remember to use the right tool for any given purpose. For example, isKindOfClass: is no substitute for respondsToSelector: or conformsToProtocol:.
Sort of. This question basically covers what you're asking: Is it safe to use isKindOfClass: against an NSString instance to determine type?
There are some caveats you need to bear in mind (see link above), but personally I think it's a fairly readable method. You just need to make sure what you're doing inside your conditional test is appropriate (the example Apple give is along the lines of "an object may say it's a kind of NSMutableArray, but you might not be able to mutate it").
I would consider the example you gave to be an anti-pattern, so yes, I would say it is harmful. Using isKindOf like that is defeating polymorphism and object orientation.
I would far prefer that you call:
[obj doTheThing];
and then implement doTheThing differently in your subclasses.
If obj could belong to classes that you don't have control over, use categories to add your doTheThing method to them. If you need default behaviour, add a category on NSObject.
This is a cleaner solution in my opinion, and it helps to separate the logic (what you're doing) from the implementation details (how to do it for specific different types of object).
Related
I just try to figure out the upside of categories compared to subclassing... I do understand how they are implemented, but the only upside I see right at the moment is, that it saves you from refactoring your whole code, if you wanna extend a used class in a later stage, which normaly shouldn't happen with a good planning. Otherwise it takes about the same time to implement as a subclass and it doesn't really bring different functionality. So for my knowledge about subclasses vs. categories I don't see a reason why to use categories. Can someone please wash my head and explain the reason for the existence of categories? I'd be very thankful :)
You're focusing on objects that you create, in which case, subclassing is fine. But what if you're calling some Cocoa method that returns some standard object. Do you want to have to create a new instance of your subclass everytime just so you can use your new method? No, it's much more convenient to be able to create methods that you add to existing class via category.
Also, you might want your new methods to be available to not only the base class, but all of its subclasses, too (e.g. if you add extension to NSString, it's available to NSMutableString instances, too).
For more information, see the discussion in Customizing Existing Classes in the Programming with Objective-C guide.
A major difference is that categories can not add instance variables, subclasses can.
Additionally there are classes that are very difficult to subclass such as NSString, see the subclassing notes. Here is an excerpt: "It is possible to subclass NSString (and NSMutableString), but doing so requires providing storage facilities for the string (which is not inherited by subclasses) and implementing two primitive methods." As soon as you see but you know it will not be easy.
Try adding a new method to the NSString class. Try doing it by subclassing NSString and by adding a category. One of these takes two minutes, the other you are never going to get working properly. That will then answer your question.
id<UIView> views = #[one, two, three];
NSInteger object = [views lastObject]; // Compiler will warn me that `views` stores only UIViews
How far would I have to go implement this? Does anybody have some experience with extending clang to support similar features?
Similar: nsmutablearray-force-the-array-to-hold-specific-object-type-only
I have thought about this also, though in the end I ask would it actually make me more productive. Objective-C seems to me to be a very pragmatic language, the features it has are real world useful, things like block are super useful, but features like namespaces and typed arrays in my experience not so much. I add a lot of NSAssert to my code to check stuff like that. Usually my mutable collections are contained within other classes and so I have a lot of control over what can be added to them, but maybe thats a pattern I adopt because I don't have typed collections?
Well, technically you already can...
UIView *views[] = {one, two, three};
NSInteger object = views[2];
Or, more usefully, you could use Objective-C++.
For the mechanism of "pass by value", it was so that the callee cannot alter the original data. So the callee can change the parameter variable in any way, but when the function returns, the original value in the argument variable is not changed.
But in Objective-C or Ruby, since all variables for objects are references to objects, when we pass the object to any method, the method can "send a message" to alter the object. After the method returns, the caller will continue with the argument already in a different state.
Or is there a way to guarantee the passed in object not changed (its states not altered) -- is there such a mechanism?
You're somewhat misusing the term "pass by value" and "pass by reference" here. What you really are discussing is const. In C++, you can refer to a const instance of a mutable class. There is no similar concept for ObjC objects (or in Ruby I believe, though I am much less familiar with Ruby than ObjC). ObjC does, via C, have the concept of const pointers, but these are a much weaker promise.
The best solution to this in ObjC is to prefer value (immutable) classes whenever possible. See Imutability in Objective-c for more discussion on that.
The next-best solution is to, as a matter of design, avoid this situation. Avoid side effects in your methods that are not obvious from the name. By avoiding this as a matter of design, callers should not need to worry about it. Remember, the caller and the called are on the same team. Neither should be trying to protected itself from the other. Good naming and good API design help the developer avoid error without compiler enforcement. ObjC has little compiler enforcement, so good naming and good API design are absolutely critical. I would say the same for Ruby, despite my limited experience there, in that it is also a highly dynamic language.
Finally, if you are dealing with a poorly behaved API that does modify your object when it shouldn't, you can resort to passing it a copy.
But if you're designing this from scratch, think hard about using an immutable class whenever possible.
I'm not sure what you are getting at. Ruby is pass-by-value. You cannot "change the argument variable":
def is_ruby_pass_by_value?(foo)
foo = 'No, Ruby is not pass-by-value.'
return nil
end
bar = 'Yes, of course, Ruby *is* pass-by-value!'
is_ruby_pass_by_value?(bar)
p bar
# 'Yes, of course, Ruby *is* pass-by-value!'
I'm not sure about Objective-C, but I would be surprised if it were different.
Is it more appropriate to check a class's type by calling isKindOfClass:, or take the "duck typing" approach by just checking whether it supports the method you're looking for via respondsToSelector: ?
Here's the code I'm thinking of, written both ways:
for (id widget in self.widgets)
{
[self tryToRefresh:widget];
// Does this widget have sources? Refresh them, too.
if ([widget isKindOfClass:[WidgetWithSources class]])
{
for (Source* source in [widget sources])
{
[self tryToRefresh:source];
}
}
}
Alternatively:
for (id widget in self.widgets)
{
[self tryToRefresh:widget];
// Does this widget have sources? Refresh them, too.
if ([widget respondsToSelector:(#selector(sources))])
{
for (Source* source in [widget sources])
{
[self tryToRefresh:source];
}
}
}
It depends on the situation!
My rule of thumb would be, is this just for me, or am I passing it along to someone else?
In your example, respondsToSelector: is fine, since all you need to know is whether you can send the object that message, so you can do something with the result. The class isn't really that important.
On the other hand, if you were going to pass that object to some other piece of code, you don't necessarily know what messages it will be intending to send. In those cases, you would probably be casting the object in order to pass it along, which is probably a clue that you should check to see if it really isKindOfClass: before you cast it.
Another thing to consider is ambiguity; respondsToSelector: tells you an object will respond to a message, but it could generate a false positive if the object returns a different type than you expect. For example, an object that declares a method:
- (int)sources;
Would pass the respondsToSelector: test but then generate an exception when you try to use its return value in a for-in loop.
How likely is that to happen? It depends on your code, how large your project is, how many people are writing code against your API, etc.
It's slightly more idiomatic Objective C to use respondsToSelector:. Objective C is highly dynamic, so your design time assumptions about class structure may not necessarily hold water at run time. respondsToSelector: gets round that by giving you a shortcut to the most common reason for querying the type of a class - whether it performs some operation.
In general where there's ambiguity around a couple of equally appealing choices, go for readability. In this case that means thinking about intent. Do you care if it's specifically a WidgetWithSources, or do you really just care that it has a sources selector? If it's the latter, then use respondsToSelector:. If the former, and it may well be in some cases, then use isKindOfClass. Readability, in this case, means that you're not asking the reader to make the connection between type equivalence of WidgetWithSources and the need to call sources. respondsToSelector: makes that connection for the reader, letting them know what you actually intended. It's a small act of kindness towards your fellow programmer.
Edit: #benzado's answer is nicely congruent.
Good answers from #Tim & #benzado, here is a variation on the theme, the previously covered two cases first:
If at some point you have may have a reference to distinct classes and need them differently then this is probably a case for isKindOfClass: For example, an color might be stored in preferences as either an NSData serialization on an NSColor, or as an NSString value with one of the standard names; to obtain the NSColor value in this case isKindOfClass: on the object return is probably appropriate.
If you have a reference to a single class but different versions of it over time have supported different methods then consider respondsToSelector: For example, many framework classes add new methods in later versions of the OS and Apple's standard recommendation is to check for these methods using respondsToSelector: (and not an OS version check).
If you have a reference to distinct classes and you are testing if they adhere to some informal protocol then:
If this is code you control you can switch to a formal protocol and then use conformsToProtocol: as your test. This has the advantage of testing for type and not just name; otherwise
If this is code you do not control then use respondsToSelector:, but we aware that this is only testing that a method with the same name exists, not that it takes the same types of arguments.
Checking either might be a warning that you are about to make a hackish solution. The widget already knows his class and his selectors.
So a third option might be to consider refactoring. Moving this logic to a [widget tryToRefresh] may be cleaner and allow future widgets to implement additional behind the scenes logic.
Suppose I’m making an Objective-C class that represents a fraction, and want to create immutable and mutable versions.
Following the patterns in the Foundation framework, you might expect to see the method fractionByAddingFraction: in the immutable version and addFraction: in the mutable version.
The paradox I’m running into is how to only include the fraction-adding logic once between the two classes. It seems that the immutable fractionByAddingFraction: method needs to know about (and make use of) the mutable addFraction: method in order to avoid code duplication, and yet including the mutable methods in the implementation of the immutable class means they could conceivably be called on the immutable object, which defeats the point.
A brief explanation (or better still, a continuation of this simplified example) would be much appreciated!
Your approach is correct (if you really need a mutable subclass, which you should avoid unless you actually need it). I'm not quite clear where the confusion is coming in. You would most easily implement addFraction: using fractionByAddingFraction:. It would be a little inefficient, but that's the direction that would make the most sense. Something like:
- (void)addFraction:(Fraction *)anotherFraction {
Fraction *newFraction = [self fractionByAddingFraction:anotherFraction];
self.internalStuff = newFraction.internalStuff;
}
But typically you would probably handle this more efficiently with some private _GetInternalStuffByAddingInternalStuffs() function that both classes would use.
The primary implementations of Foundation’s collections cheat: there’s only one implementation, which is a subclass of NSMutableFoo, and it has a private mutability flag. This means client code can’t test whether a particular object is mutable or not, but that would never be a good idea anyway except perhaps for debugging and assertions.