How does a category work? - objective-c

I'm new to objective-c and need to extend a standard class of a framework with an instance variable plus accessors. I heard that this is done with a so called "category", which sounds pretty confusing to me. How does this basically work?

A category adds methods to the table of methods inside a class. It's very handy for adding application specific methods to existing framework classes.
If you need to add instance variables to a class, a category won't do the job -- categories only add methods, not data. To add instance variables, you must subclass.

A category of a class adds methods to that class. It cannot add instance variables.
If you need to add instance variables you may want to subclass instead.

Related

Categories & Variables

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/

Core Data, iVars and Categories

One of my core data subclasses has an NSSet of items. It is often (but not always, so no NSOrderedSet) useful to instead retrieve an ordered NSArray, so I added orderedItems to the class, which sorts them.
I then ran into performance issues so decided to try caching the orderedItems. My plan is to use an iVar, _cachedOrderedItems in the class, which I will return if it is not null.
The snag comes with my use of categories. I read some good advice about putting all of my custom code in a category so that I can re-generate the core data class if necessary and not lose all my customizations. One of those customizations is the orderedItems method.
It seems I can not declare an iVar in the category itself. And if I try to put it in the core data class instead, I can not access it in the category.
Do I need to move my custom code back into the core data class? Or am I missing something?
I have also heard about Mogenerator, and would consider learning to use this if it would help.
You can use associative references to add ivars to a class any time you can't modify the original class, including in categories. For a detailed example, see Faking instance variables in Objective-C categories with Associative References.
You own the class, so you can use a class continuation (discussed here) instead of a category. This allows you to add instance variables.
You should definitely use mogenerator. See for example http://importantshock.wordpress.com/2006/12/19/mogenerator-or-how-i-nearly-abandoned-core-data/.
You can make an Aggregate target in XCode, add a Run Script with the following:
mogenerator -m path/to/your/datamodel.xcdatamodeld/version.xcdatamodel --template-var arc=true -M /CoreData/Generated -H /CoreData
For every NSManagedObject you get a class and a subclass. When updating your datamodel, run the script again and the base class will be updated, preserving all the changes you made to the managed object subclass. Remove --template-var arc=true for none arc.

Using functionality of one class in another

I'm trying to use ILGeoNames classes in my project. But I have problem with understanding in which way I can use this classes for my purpose. There is "simple project" in this framework. From it I want only one thing: country time zone (I already have county name). Because there are many method, variables and others staffs I can't understand what exactly I need to use. Please, help me solve this question.
If its a bunch of classes and you want to make use of a certain class's methods or properties, then you have to #import name_of_class_you_want_to_utilize; at the start of your file and then make your calls. Class methods can be called directly, whereas instance methods require you to create an instance of the class to access them.

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.

Share code between classes in Objective-C without inheritance?

Since Objective-C does not support multiple inheritance, is there some other mechanism to share code between classes?
I'm writing a Cocoa library on top of an existing xml schema. Many elements in the schema (for example, ) are used in multiple types. I was hoping to centralize this somehow, so that I didn't have to add #property NSString *name and the associated code to generate the xml for the name property in every single class that has a name attribute. That would be fairly straightforward if multiple inheritance were supported, but I don't know how to do it otherwise.
The best thing I can think of is to create a common superclass that has a superset of methods to encode each optional property, then call the appropriate methods (i.e. encodeName) in the encoding method for each class. Does that seem like the best way to go?
I would recommend you create a new Category with your properties/functions etc and add said category to NSObject. That would make all properties and functions available to all subclasses of NSObject. It's not exactly multiple inheritance but provides a great amount of flexibility.
It is actually possible to add data to a class at run time using the runtime's Associative Reference functions. It's a little deeper than normal SDK work, but works quite well. It's not the same as a full property with getters and setters, but it does associate objects with an instance.
If the methods are only required on certain objects then maybe a sub class from that class is the way to go or a category on that specific class would be better. The category on NSObject is quite a wide net to cast.
If you want to add additional state then sub classing is probably your safest bet.
If you do add a category make sure you prefix your methods with something unique so to avoid any conflicts. E.g. PSMySpecialMethod as opposed to mySpecialMethod