Adding conflicting methods in an Objective C class using category - objective-c

I have added a method foo to a class MYCustomClass in a category Category1 separate from the original definition of the class. Then I added another method also called foo in another category Category2. I then call foo on an instance of MYCustomClass. In my case the foo in Category2 is being called. My question is: Is there any explanation for this? Or, is it one of those "undefined"/"compiler dependent" behaviours. Also, is it possible to handle such situations by qualifying the method call by specifying the category I want to be used in the call.
EDIT: I am aware that what I am doing is not supported. I am just interested in if there is a hack around it.

When a category is loaded, its methods are inserted into the existing method table, and there's no way to distinguish where they came from once that's done. The last category to load wins. Back in the NeXTSTEP days, we would sometimes do this deliberately as a very kludgey way to fix a broken method in code for which we didn't have the source.

It’s undefined behaviour. From the Objective-C Programming Language document:
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.
And no, you cannot specify that you want foo from Category1, or foo from Category2. If you need this, you should give different names to those methods, e.g. foo1 and foo2.

Related

How do I only let some classes call a method and not others in Objective C?

I have created three classes, and one method in one of the classes, but I only want my other two classes to be able to call the method. Any guess how to do this.
Thanks.
As mentioned in links given in the comments, a Category will get you similar behaviour in Objective-C. The difference, compared to C++, is that it's voluntary rather than enforced by the compiler.
Any class that imports the Category header can make the call and, even if the header isn't published, a programmer can call the method if the signature is known by declaring a Category interface (or ignoring a compiler warning).
If you're doing this as a way of reminding yourself not to call those methods, Categories work well. If you were trying to protect against someone else "hacking into" the methods, it would be little defense.

When are categories bad/dangerous?

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.

What happens if one class has many categories?

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.

When to use Categories

I've recently discovered categories and was wondering when it might be appropriate to use them in a user defined class/new class. For example, I can see the benefits of adding a category to an existing class like NSString, but when creating a new class what would be the advantage of adding a category to this rather than just implementing a normal method?
Hope this makes sense.
Many thanks
Jules
The answer isn't really any different for your own classes than it is for framework classes. If you have multiple projects, you'll likely end up sharing some classes between them. However, you may want to extend some of your classes so that they work more easily with a specific project, but not want to include those extra methods in your other projects, where they might not make sense. You can use a category to extend your class without needing to subclass.
If I understand your question correctly, creating a "new class" is always "subclassing" because you're subclassing NSObject at the very least.
You could use categories on a new class to separate out sections of responsibility of a complex class. For example, all the basic functionality (instance variables, accessors, description, etc.) can go in one file (the "main" class file) while all methods to support a protocol (such as NSTableViewDataSource) can go in another.
Some take this approach to keep things "neat". I'm a firm believer in "if it's my own custom class, all its code should be in one file" so I do not personally do this. I demarcate different logical aspects of the class' code with "#pragma mark Some Section Name" to help navigation and readability. Your mileage may vary.
Adding a Category on NSString is useful when you want to call a method on every single NSString instance you will encounter. This is a real improvement over inheritance for this kind of object because they are used by the core framework and you don't have to convert a NSString object to your subclass when you want to call your custom method.
On the other hand, you can just put methods in, no instance variables.
In the book Refactoring by Martin Fowler, he has a section titled "Introduce Foreign Method" (A server class you are using needs an additional method, but you can't modify the class.) That's what categories are good for.
That said, there are times when using a category, instead of changing the class, is appropriate. A good example on using a category, even though you could change the server class, is how Apple handled the UIViewController MediaPlayer Additions. They could have put these two methods in UIViewController itself but since the only people who would ever use them are people who are using the Media Player framework, it made more sense to keep the methods there.

Overriding methods using categories in Objective-C

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