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.
Related
I know how to bind a NSTableView to an NSArray via NSArrayController.
But what about binding NSTableView to MyCustomCollection? What do the bindings look like? Can I still use NSArrayController and just conform to a protocol in MyCustomCollection? Or should I use a different controller object? What does MyCustomCollection need to conform to?
This is hard to answer completely or specifically without knowing a lot more about your collection class. Almost certainly creating a custom collection class is the wrong thing to do. You should definitely elaborate on the reasons you feel this is necessary and your implementation. Be prepared to consider your reasons aren't good enough to justify jamming a custom collection into an NSArrayController or that it's not even possible to do exactly what you want (at least the way you're trying to do it).
Also note Cocoa collection classes are (I think all) members of a class cluster. This makes "doing it right" a significantly more complex challenge and makes subclassing an existing Cocoa collection class a Bad Idea™ if you have to ask how ("if you have to ask, you're not ready to try it" conceit, albeit justified).
I believe as long as your class responds to the same selectors as does (at least) NSArray (if not NSMutableArray if your class is mutable), including the Key Value Coding collection accessor methods, it should probably work alright. Since your table (or, more likely, its columns) is bound to the array controller, that part should work the same. Since NSArrayController inherits -content / -setContent: from NSObjectController and these methods take an id argument, I believe it likely uses the KVC accessor methods I referenced to get at the collection's members.
But I could be wrong... :-)
In the apple OS X 10.8 Core Library Documentation under Programming with Objective-C, it states,
"It's best practice to use a property on an object any time you need to
keep track of a value or another object. If you do need to define
your own instance variables without declaring a property, you can add
them inside braces at the top of the class interface or
implementation..."
So I'm curious, then, what are going to be the cases where you need to define instance variables without declaring properties? Aside from what apple says, could it really just be a personal preference thing?
Thanks!
Some of it is definitely a matter of preference, but not everything: you are better off with a property for items with external visibility, and items that need different access control inside vs. outside your class. The issue has been much less pronounced since the introduction of ARC, because before it you may wanted to use properties for automated calls of retain and release. The significance of this aspect of properties has been reduced greatly to situations when you need to automatically copy the objects into your property.
If you're using ARC and a recent runtime (recent enough to let you declare your ivars in your #implementation block), then instance variables are suddenly awesome again. Why? Because unlike #properties they're class-specific. No risk they'll accidentally be overridden by a subclass.
They're also faster in the simple case, since you don't call any methods to get or set them.
I personally also find it much cleaner. No more class extensions defining private #properties, and all that junk. Just ivars, nice and simple.
So the best advice, IMHO, is to use them by default. Only use #properties if you actually need their functionality, e.g.:
You need a way to access them from outside your class.
You want to allow subclasses to override them.
Your getter or setter is more than just a trivial assignment.
The latter two are all actually rarer than you might think. It's generally unwise to try to override properties in subclasses, just because it's a little unusual and there are some rough edges.
If you do find, later, that you need to upgrade an ivar to a #property, it's nice and easy - the only place it can be accessed is in your #implementation, so it's generally a simple search-and-replace to add "self." to its references (and maybe remove the leading underscore, if you name them that way). 'til then you needn't pay the cost and run the risks of using #properties.
I prefer properties because I am able to define setters/getters and because I like more that syntax.
Many people affirm that is a bad practice to use ivars, like in this article:
http://cocoasamurai.blogspot.it/2012/08/cover-up-those-ivars.html
Unfortunately nowadays programmers call bad practice all what they don't like, even without objective reasons.
If you declare an ivar you still can use the #private directive, so isn't a matter of exposing or not variables.I think that if you like more ivars you should use them.
I am new at programming in general (though I have had a C class many, many years ago) and am learning Objective-C for programming on the iPhone. I have what I think is a simple question, but after looking for a while (days, off and on) I can't find the answer that I'm looking for explicitly.
I know that when subclassing an Objective-C class I should implement the initialize method along with the deallocate method (unless using ARC for the latter, if I am correct?). The questions are:
Are these the only two to worry about, or will other classes potentially have additional methods that can be required to be implemented?
If other classes might have methods that I am required to implement when subclassing them, where is that documentation typically found? (I don't seem to see that in the Apple framework docs, though that kind of information is there for protocols it appears)
Thanks for your help!
Technically, you are not required to implement even the init and dealloc if the inherited versions are sufficient. Also, ARC does not free you from having to write dealloc in all cases (but it certainly covers the overwhelming majority). For example, if you allocate memory for your object using malloc, you need to free it in the dealloc.
When you add instance variables to your class, you need to initialize them. Typically, you do that in a designated initializer. Again, if you do not to initialize anything, you do not have to code your own initializer; same goes for deinitializer.
The only case when you need to implement a method is when you adopt a protocol with one or more methods marked #requried. These methods are marked in the protocol reference. For example, tableView:cellForRowAtIndexPath: and tableView:numberOfRowsInSection: are marked with the "required method" tag in Apple's documentation.
No methods are required when subclassing an NSObject (or any of their subclasses, such as UIViewController, UIView, etc. etc.).
If you create a new, let's say UIViewController, it's generally a good idea to keep the methods you find in the newly created file as a guideline/template, but you're not really required to keep any of the methods. The super class will always call the methods on itself.
Be aware, though, some methods you have to call super, like viewWillAppear, etc.
Am not sure how to put this, and I couldn't find the answer because of my inability to find the words to express what am looking for. (!)
In Java, I used to do something like this (I don't remember):
JPanel myButton = new JPanel("Press me"){
public void add(JComponent component){
//override add method
}
};
But, i couldn't find how to do this in Objective-C .. What I found in my search was categories and weird ^{} symbols ...
So, how can I override method(s) in a newly created object?
(For example, override -(BOOL)isEqual; in a newly created NSString* ?)
Am sorry if the question is a bit vague..
EDIT:
Obviously, without subclassing :)
EDIT:
Might as well post my problem in case someone has a better idea:
I have a few CCTransitions in COCOS2D, and I want to be notified when the transition ends .. The thing is, as soon as the transition ends, the -(void)finish; method is invoked (which is part of the CCTransition class structure)
I would really want to avoid subclassing the CCTransition class, and override the finish method to do my logic when the transition ends :)
EDIT:
-(void)onEnterTransitionDidFinish; ... I can't believe something as awesome as that existed and I haven't came across it while searching......
Which means, instead of subclassing CCTransition, override this method in my CCNode subclass :D!
It's still not going to be very clean, but assuming you're willing to concentrate the ugliness, you could do something like (untested):
Method methodToReplace =
[targetClass instanceMethodSignatureForSelector:#selector(methodToReplace)];
IMP implementationToSet =
[someProxyClass instanceMethodForSelector:#selector(implementationYouWant)];
method_setImplementation(methodToReplace, implementationToSet);
Relevant reference documentation is the Objective-C Runtime Reference and, optionally, the NSObject Class Reference (because it makes a few things slightly neater, though e.g. you could use class_getInstanceMethod from the runtime rather than instanceMethodSigntureForSelector:).
Note that you'll have no way to call the original implementation if you use exactly that recipe. method_setImplementation returns the old implementation, it's generally wise to add that to the class under a brand new selector and call that instead.
For reference, I've had a legitimate reason to do this sort of thing only exactly once: when we implemented printing support in an iOS application with which needed to be compatible with both OS 3.2 and 4.0. You need to subclass a particular class, but the class isn't available in 3.2. So you sort of have to subclass at runtime (though the conceptually neater way would be to use a normal subclass, put that into a framework and weak link, but Apple's iOS SDK terms allow static libraries only, so...).
Following Daniel's suggestion, you can implement a method in an NSObject category of the form
[anObject overrideMethod:#selector(foo:)
byBlock:^(id self,id super,id originalArg){
...
}];
What you need to do is to
objc_allocateClassPair against self's own class, to create a new temporary class
Turn a block into a function pointer, using e.g. this or this
method_setImplementation to set the new implementation to the temporary class
use object_setClass to self to set the class to the new temporary class
I haven't figured out how to provide super to the block :p
It's believed this is basically how the KVO is done by Apple, see e.g. this discussion.
Read Runtime reference.
What you have there in Java is an anonymous subclass. This is not possible in Objective-C (well, it sort of is but you would have to do some pretty involved contortions with the Obj-C runtime library).
But Objective-C as of iOS 4 or OS X 10.6 has "blocks", which is what the ^{} syntax is for. This is Objective-C's notion of a closure. This isn't going to help you directly if the APIs that you're calling don't support block callbacks, but you may be able to create wrapper classes that use blocks instead of subclassed methods to handle callbacks.
There are many resources for learning about blocks in Objective-C.
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).