Can I use a class category to override a method that is already implemented using a category? Like this:
1) Original method
-(BOOL) method {
return true;
}
2) Overrided method
-(BOOL) method {
NSLog(#"error?");
return true;
}
Will this work, or is this illegal?
From Apple documentation:
Although the Objective-C language currently allows you to use a category to override methods the class inherits, or even methods declared in the class interface, you are strongly discouraged from doing so. A category is not a substitute for a subclass. There are several significant shortcomings to using a category to override methods:
When a category overrides an inherited
method, the method in the category
can, as usual, invoke the inherited
implementation via a message to super.
However, if a category overrides a
method that exists in the category's
class, there is no way to invoke the
original implementation.
A category cannot reliably override methods declared in another category of the same class.
This issue is of particular significance because many of the Cocoa classes are implemented using categories. A framework-defined method you try to override may itself have been implemented in a category, and so which implementation takes precedence is not defined.
The very presence of some category methods may cause behavior changes across all frameworks. For example, if you override the windowWillClose: delegate method in a category on NSObject, all window delegates in your program then respond using the category method; the behavior of all your instances of NSWindow may change. Categories you add on a framework class may cause mysterious changes in behavior and lead to crashes.
You can do this by adapting Class Cluster approach, or using methods swizzling technique.
Otherwise, the behavior of two or more categorized methods is undefined
Old documentation link is dead; best replacement I could find was here: Apple Docs:
Avoid Category Method Name Clashes
Because the methods declared in a category are added to an existing class, you need to be very careful about method names.
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. This is less likely to be an issue if you’re using categories with your own classes, but can cause problems when using categories to add methods to standard Cocoa or Cocoa Touch classes.
It's Apple using a lighter touch, but the main point is the same: you invite disaster, because the unpredictable behavior is silent.
It’s important to note that a category can also be used to override existing methods in the base class (e.g., the Car class’s drive method), but you should never do this. The problem is that categories are a flat organizational structure. If you override an existing method in Car+Maintenance.m, and then decide you want to change its behavior again with another category, there is no way for Objective-C to know which implementation to use. Subclassing is almost always a better option in such a situation.
From this tutorial, http://rypress.com/tutorials/objective-c/categories
Related
My question is quite simple.
In Objective C, what is the reason we cant have variables? If we ignore work arounds like Associative reference, extension, dynamic properties etc...what is the goal behind not allowing variables in Categories
If you want to add variables to an existing class, use Subclassing.
If you want to simple add your own methods to existing classes, use Categories.
Categories can be used to declare either instance methods or class
methods but are not usually suitable for declaring additional
properties. It’s valid syntax to include a property declaration in a
category interface, but it’s not possible to declare an additional
instance variable in a category. This means the compiler won’t
synthesize any instance variable, nor will it synthesize any property
accessor methods. You can write your own accessor methods in the
category implementation, but you won’t be able to keep track of a
value for that property unless it’s already stored by the original
class.
The only way to add a tradition property—backed by a new instance
variable—to an existing class is to use a class extension, as
described in “Class Extensions Extend the Internal Implementation.”
What is the goal behind not allowing variables in Categories?
Methods within a Category are added to a class at run-time, this means the compiler won’t synthesize any instance variable, nor will it synthesize any property accessor methods.
On the other hand when using subclassing, the class is compiled at the same time as the class extension.
source
Category provides an ability to add functionality to SDK class. First of all why we need categories we can extend a class to add functionality and data members to it.
Let say you want to extend some functionality of UINavigationController you can subclass and add whatever your requirement. But UINavigationController is also part of some SDK controls e.g. UIImagePickerController and more tab in UITabBarController. What you gonna do to that Navigation Controller you don’t have access to it.
See my blog post for details http://muhammadzahidimran.com/2016/12/09/adding-data-to-sdk-classes-using-categories/
I it might sound a silly question, but I still afraid of doing so. Because I would like to override an NSObject method, namely addObserver: with a Category. Does it has an effect on other apps running on the system?
Overriding addObserver:forKeyPath:option:contex is not a good idea. From a category implementation you can't call the method's super implementation, which basically means none of the observers will ever get added.
While this will only affect you app, it will do so at global level, meaning, even external frameworks will be affected, like UIKit or Fundation.
Although the Objective-C language currently allows you to use a category to override methods the class inherits, or even methods declared in the class interface, you are strongly discouraged from doing so. A category is not a substitute for a subclass.
About you question Does it has an effect on other apps running on the system?
Answer is Big No. It will affect only your app.
Although category gives you a provision to add new methods to an existing class. Also you can override an existing methods but in few cases you may end up loosing the control as which method will be called!!!
And sometimes even you override a method the Frameworks methods are used and your method are not considered.
So I would suggest that you should not use same method name to override. You can use as, to differentiate :
addObserverCustom:
I'm using categories with Core Data. Some of the tutorials I've read and lectures I've listened to say that categories are often considered "bad" practice. But because Objective-C is so dynamic it seems perfectly okay to define methods somewhere else, especially because only public properties of a class can be used. What are the pitfalls I should be looking out for when using categories? Or is there some reason that categories are actually bad practice? The reason I'm using them with Core Data is so that I don't have the rewrite my add-on methods every time I regenerate the subclasses.
The only "danger" I can think of is when you use them to replace methods in the original class rather than subclassing.
When doing this you lose the ability to access the original implementation, which, since it is usually a private method you are overriding, could have unforeseen effects.
Using categories to add extra methods to any object of a particular class is great, and precisely what they are for. Using them for core data, as you are doing, is fine because it does allow you to change your model and regenerate the "vanilla" object without destroying any extra code.
Tip of the hat to #CodaFi for this bit of documentation from apple:
Although the Objective-C language currently allows you to use a category to override methods the class inherits, or even methods declared in the class interface, you are strongly discouraged from doing so. A category is not a substitute for a subclass. There are several significant shortcomings to using a category to override methods:
When a category overrides an inherited method, the method in the category can, as usual, invoke the inherited implementation via a message to super. However, if a category overrides a method that exists in the category's class, there is no way to invoke the original implementation.
A category cannot reliably override methods declared in another category of the same class.
This issue is of particular significance because many of the Cocoa classes are implemented using categories. A framework-defined method you try to override may itself have been implemented in a category, and so which implementation takes precedence is not defined.
The very presence of some category methods may cause behavior changes across all frameworks. For example, if you override the windowWillClose: delegate method in a category on NSObject, all window delegates in your program then respond using the category method; the behavior of all your instances of NSWindow may change. Categories you add on a framework class may cause mysterious changes in behavior and lead to crashes.
In Objective C, if a class has many categories in a single application,
Do we specify which category of class we want while instantiating ?
All of the methods defined in all categories will be added to the class. This occurs at run-time and if there are two methods in different categories with the same signature it is undefined which method will be used, so there would be no point in specifying a particular category for any particular instantiation even if you could - all the instantiations will use the same method implementations anyway.
If you want to have methods that are only available to particular instantiations use a subclass instead.
No need to specify which category of class you want while instantiating. The method that category adds become the part of class. For example if you add method to NSString class then compile will expect an NSString instance to have in its repertoire.
Can anyone explain the differences between Protocols and Categories in Objective-C? When do you use one over the other?
A protocol is the same thing as an interface in Java: it's essentially a contract that says, "Any class that implements this protocol will also implement these methods."
A category, on the other hand, just binds methods to a class. For example, in Cocoa, I can create a category for NSObject that will allow me to add methods to the NSObject class (and, of course, all subclasses), even though I don't really have access to NSObject.
To summarize: a protocol specifies what methods a class will implement; a category adds methods to an existing class.
The proper use of each, then, should be clear: Use protocols to declare a set of methods that a class must implement, and use categories to add methods to an existing class.
A protocol says, "here are some methods I'd like you to implement." A category says, "I'm extending the functionality of this class with these additional methods."
Now, I suspect your confusion stems from Apple's use of the phrase "informal protocol". Here's the key (and most confusing) point: an informal protocol is actually not a protocol at all. It's actually a category on NSObject. Cocoa uses informal protocols pervasively to provide interfaces for delegates. Since the #protocol syntax didn't allow optional methods until Objective-C 2.0, Apple implemented optional methods to do nothing (or return a dummy value) and required methods to throw an exception. There was no way to enforce this through the compiler.
Now, with Objective-C 2.0, the #protocol syntax supports the #optional keyword, marking some methods in a protocol as optional. Thus, your class conforms to a protocol so long as it implements all the methods marked as #required. The compiler can determine whether your class implements all the required methods, too, which is a huge time saver. The iPhone SDK exclusively uses the Objective-C 2.0 #protocol syntax, and I can't think of a good reason not to use it in any new development (except for Mac OS X Cocoa apps that need to run on earlier versions of Mac OS X).
Categories:
A category is a way of adding new methods to all instances of an existing class without modifying the class itself.
You use a category when you want to add functionality to an existing class without deriving from that class or re-writing the original class.
Let's say you are using NSView objects in cocoa, and you find yourself wishing that all instances of NSView were able to perform some action. Obviously, you can't rewrite the NSView class, and even if you derive from it, not all of the NSView objects in your program will be of your derived type. The solution is to create a category on NSView, which you then use in your program. As long as you #import the header file containing your category declaration, it will appear as though every NSView object responds to the methods you defined in the catagory source file.
Protocols:
A protocol is a collection of methods that any class can choose to implement.
You use a protocol when you want to provide a guarantee that a certain class will respond to a specific set of methods. When a class adopts a protocol, it promises to implement all of the methods declared in the protocol header. This means that any other classes which use that class can be certain that those methods will be implemented, without needing to know anyting else about the class.
This can be useful when creating a family of similar classes that all need to communicate with a common "controller" class. The communication between the controller class and the controlled classes can all be packaged into a single protocol.
Side note: the objective-c language does not support multiple inheritance (a class can only derive from one superclass), but much of the same functionality can be provided by protocols because a class can conform to several different protocols.
To my understanding Protocols are a bit like Java's Interfaces. Protocols declare methods , but the implementation is up to each class. Categories seems to be something like Ruby's mixins. With Categories you can add methods to existing classes. Even built-in classes.
A protocol allows you to declare a list of methods which are not confined to any particular class or categories. The methods declared in the protocol can be adopted any class/categories. A class or category which adopts a protocol must implements all the required methods declared in the protocol.
A category allows you to add additional methods to an existing class but they do not allow additional instance variables. The methods the category adds become part of the class type.
Protocols are contracts to implement the specified methods. Any object that conforms to a protocol agrees to provide implementations for those methods. A good use of a protocol would be to define a set of callback methods for a delegate (where the delegate must respond to all methods).
Categories provide the ability to extend a current object by adding methods to it (class or instance methods). A good use for a category would be extending the NSString class to add functionality that wasn't there before, such as adding a method to create a new string that converts the receiver into 1337 5P34K.
NSString *test = #"Leet speak";
NSString *leet = [test stringByConvertingToLeet];
Definitions from S.G.Kochan's "Programming in Objective-C":
Categories:
A category provides an easy way for you to modularize the definition of a class into groups or categories of related methods. It also gives you an easy way to extend an existing class definition without even having access to the original source code for the class and without having to create a subclass.
Protocols:
A protocol is a list of methods that is shared among classes. The methods listed in the protocol do not have corresponding implementations; they’re meant to be implemented by someone else (like you!). A protocol provides a way to define a set of methods that are somehow related with a specified name. The methods are typically documented so that you know how they are to perform and so that you can implement them in your own class definitions, if desired.
A protocol list a set of methods, some of which you can optionally implement, and others that you are required to implement. If you decide to implement all of the required methods for a particular protocol, you are said to conform to or adopt that protocol. You are allowed to define a protocol where all methods are optional, or one where all are required.