Hour 18. Extending a Class with Categories and Extensions


What You’ll Learn in This Hour

Image Differentiating categories and protocols

Image Choosing when to use a category

Image Comparing categories and subclasses

Image Building and testing a category


Comparing Categories and Protocols

In Hour 17, “Extending a Class with Protocols and Delegates,” you saw how to specify a set of methods for a protocol that can be adopted by any class. How the class that adopts the protocol implements it is up to that class: The protocol merely defines the required methods that must be (somehow) implemented by the class. Accordingly, when a class adopts a protocol, it can assume that it can call the required methods in that protocol. It will need to check to see if the optional methods are implemented.

Categories are somewhat similar to protocols. However, instead of being able to be adopted by any class, they are tied to a specific class. A category consists of an @interface as well as an @implementation just like a class. A category is added to the specific class at runtime rather than during the build process. Once added, the class and category together behave as a class does. Like protocols, categories declare methods. They do not declare variables or properties in their interface. You can declare private instance variables inside the method implementation.

You will find categories for some of the Cocoa frameworks classes on the web and in other resources. They are a good way to extend a framework class relatively safely (provided, of course, that the category code works properly).

Choosing When to Use a Category

Categories can be used to structure large projects. A base class can be designed with one or more categories, each of which adds specific types of functionality to the base class. Different individuals or teams can work on each category without running into too many conflicts. In addition, because the categories are assembled into the class at runtime, the people working on the categories do not need access to the source code of the class to which they are adding categories. They do need access to the interface, but the details of the coding can be kept confidential. This can help manage large projects in which parts of the project are confidential for one reason or another. At runtime, as categories are added to the primary class, any methods with the same signature as methods in the primary class are replaced with same-signature methods from a category.


Note: Multiple Method Replacements

If you replace a method in a class with more than one same-signature method in more than one category, the results are undefined.


These are among the purposes of categories as described in the documentation from Apple (and before that from NeXT—categories are an original part of Objective-C).

Comparing Other Techniques with Categories

Today, there are more tools available for managing source code and handling changes, so the issue of managing and structuring large, monolithic projects is often not the issue it was in the past. In addition, for many people, the rise of open source code has in some cases broken down the traditional confidentiality and even secrecy of code. The trade-off between the benefits of many eyes looking at the code as compared with confidentiality often tips toward a bit more openness of code as compared with the practices a few decades ago.


Note

That said, critical pieces of proprietary code, such as the Facebook algorithm for generating the news stream, remain as carefully guarded as the legendary formula for Coca-Cola.


In Cocoa and Cocoa Touch as well as many third-party apps, categories are commonly used for another purpose; they help you avoid subclassing in some cases.

Comparing Categories with Subclasses

Categories can help you manage one of the issues that often arises with subclassing objects. Many projects evolve over time as hardware, software, and user expectations change. Periodically, a major overhaul and restructuring of the code might take place. (In the world of Apple, this has happened on a grand scale with the move from Mac OS to OS X and, on a lesser scale, with the moves from Motorola chips to PowerPC chips and then to Intel chips.) Even with large-scale changes such as these, it is not always possible to substantially reconfigure an object hierarchy. (You’ll find an example in the following section.)

Modifying a Class Hierarchy

Adding a subclass at the bottom of the object hierarchy is not usually very difficult, but when you realize that you really need to insert an intermediate object at the top of the hierarchy, you might encounter problems. The evolution of AppleScript in OS X provides a case in point.

AppleScript is the scripting language used on OS X and, before that, on Mac OS. Today, it is one of several scripting languages that are available on the Mac. It has been integrated into workflows (often involving Automator from Apple), and for organizations that rely on AppleScript and Automator, their investment in these tools can be enormous. The issues involved in integrating AppleScript are not specific to AppleScript. The steps described here occur in many cases where the object hierarchy needs revision.


Note

AppleScript is used extensively in various publishing scenarios. QuarkXPress was one of the early mainstays of scripting, and InDesign likewise supports AppleScript as one of its scripting tools.


To fully integrate AppleScript with the frameworks, support code is needed at a very basic level. Modifying NSObject to provide scripting support would be simple in one sense, but it would burden NSObject with scripting code that many (perhaps most) users would never need. Another way to integrate scripting is to add new classes, and perhaps a protocol, that are only invoked when needed. In fact, that is the strategy implemented with NSScriptObjectSpecifier.

That works for many AppleScript purposes, but in order to implement certain behaviors, it is necessary to add app-specific functionality to the application object itself. This is not practical for a number of reasons that are beyond the scope of this book.

For now, just note that this is a situation in which you want to extend NSApplication for your specific app. There are other cases in which you need to add some functionality to NSObject itself. Obviously, making these changes in the frameworks themselves is not feasible: By definition, these are changes needed for specific apps. If the source code for NSObject or NSApplication was readily available, users could modify it for their specific purposes and thereby fragment the platform.

Confining Modifications to Categories

Adding the needed code in a category at runtime accomplishes the goal of modifying a class that is widely used and possibly subclassed but with an assurance that those modifications will have limited dangerous consequences. The fact that the category is compiled on its own limits potential harmful side effects. If it needs to be backed out, you do not have to make modifications in source code that was developed for other purposes. The category can be removed from the project without harm, although you have to remove any invocations of methods created in the new category.

GO TO Image Hour 4, “Using Xcode 5,” p. 41, to see how to use a branch of your project to experiment with code such as a category and then back it out.

Working with Categories

Category declarations specify the class on which they are placed. They do not specify a superclass because it is the superclass of the class on which they are placed.

Here is a typical category declaration:

@interface NSApplication (SampleCategory)
– (void)testCategory;
@end

The category name is entered in parentheses after the name of the class on which this category is placed. (The common terminology is “placing a category on a class.”)

By convention, the filenames for a category combine the class and the category name with a plus sign as in NSApplication+SampleCategory.h.

Using Class Extensions

Class extensions are also known as anonymous categories. They can be used to redefine properties, variables, and methods that you do not want to expose in the class’s interface file. Over the past several years, they have gained in popularity, and they are created by default in many of the Xcode templates. These class extensions are often empty, but they are ready for you to use them to define properties and methods that aren’t visible in the public interface.

You can redeclare properties in an anonymous category (changing readonly to readwrite for example) or declare methods that you want to totally hide from people who have access to the interface file of the class.

Class extensions have the same syntax as named categories, but instead of the name in parentheses, the parentheses are empty, as in this example:

@interface MyClass ()
...
@end

The methods in an anonymous category must be implemented in the main @implementation section for the class rather than in a separate category .m file. If they are not implemented there, the compiler warns you.

Named categories are implemented in their own .m files. If a method implementation is missing, you are not warned.

Working with Informal Protocols

The category structure was used in the past to create informal protocols in which some methods are optional. (This legacy code still exists.) As noted in the previous section, methods declared in a named category do not trigger compiler warnings if they have no definition in a .m file. As a result, you can consider the methods optional. Until the ability to specify @optional in a protocol (in Objective-C 2.0), this was the only way to implement that functionality: a named category with some missing definitions. Now that @optional is available for protocol methods, there is little need for informal protocols implemented as named categories.

Summary

This hour has shown you how to add or replace methods in a class with methods in a category that is attached to the class. You can use a category to correct a bug in an existing class without recompiling the entire class; you can also use a category to add specific functionality to framework classes.

Categories are also used to organize large projects. (The Cocoa frameworks themselves use categories extensively.)

Q&A

Q. What is the significance of an anonymous class?

A. You must have the source code for the base class.

Q. Why are protocols and categories often discussed together?

A. Both let you add specified methods to a class (categories) or several classes (protocols).

Workshop

Quiz

1. What is the convention for naming files for categories?

2. Are there limits on the number of categories you can create for a class?

Quiz Answers

1. The convention for naming files for categories is ClassName+CategoryName.

2. No, except that each category name (including a blank anonymous name) must be unique.

Activities

Two sample code projects use categories for AppleScript in a progressive way. Check out SimpleScripting and then SimpleScriptingVerbs from the sample code on developer.apple.com. Particularly if you have used AppleScript, you will find the possibility shown in those examples to be useful for future projects.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.128.198.59