Categories

In Objective-C, classes have instance and class methods. These define the behavior of a class and its instances. Sometimes, you are using a class and you really wish it just had a method to do this cool thing I want to do. You’re in luck. You can add methods to an existing class by creating a category for that class.

The syntax for a category is not at all scary like blocks; in fact, it’s something you’ve already used before. You will create a category for UIColor that has two new methods that an instance of UIColor will respond to. Create a new NSObject subclass. Name it UIColor+Extract.m. In UIColor+Extract.h, replace all of the code with the following:

#​i​m​p​o​r​t​ ​<​F​o​u​n​d​a​t​i​o​n​/​F​o​u​n​d​a​t​i​o​n​.​h​>​

#​i​m​p​o​r​t​ ​<​U​I​K​i​t​/​U​I​K​i​t​.​h​>​

@​i​n​t​e​r​f​a​c​e​ ​U​I​C​o​l​o​r​ ​(​E​x​t​r​a​c​t​)​

-​ ​(​v​o​i​d​)​e​x​t​r​a​c​t​_​g​e​t​R​e​d​:​(​f​l​o​a​t​ ​*​)​r​ ​g​r​e​e​n​:​(​f​l​o​a​t​ ​*​)​g​ ​b​l​u​e​:​(​f​l​o​a​t​ ​*​)​b​;​
-​ ​(​U​I​C​o​l​o​r​ ​*​)​e​x​t​r​a​c​t​_​i​n​v​e​r​t​e​d​C​o​l​o​r​;​

@​e​n​d​

Notice you used nearly the same syntax as you would if you were declaring a new class named UIColor. However, there are two differences: the area for defining the superclass has been replaced with (Extract) and there is no section for instance variables. This declaration says, I’m adding two new methods to the UIColor class. The name of this addition is Extract, which is just a name. Also, note that these methods are prefixed with the name of the category. Because more than one category can be added to a class, you don’t want to pollute the namespace with obvious-sounding method names.

In UIColor+Extract.m, implement these two methods by replacing all of the text in the file with the following:

#​i​m​p​o​r​t​ ​"​U​I​C​o​l​o​r​+​E​x​t​r​a​c​t​.​h​"​

@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​U​I​C​o​l​o​r​ ​(​E​x​t​r​a​c​t​)​

/​/​ ​N​o​t​e​ ​t​h​a​t​ ​t​h​i​s​ ​m​e​t​h​o​d​ ​u​s​e​s​ ​t​h​e​ ​w​o​r​d​ ​"​g​e​t​"​.​ ​T​h​e​
/​/​ ​"​r​e​t​u​r​n​ ​v​a​l​u​e​s​"​ ​a​r​e​ ​p​a​s​s​e​d​ ​a​s​ ​p​o​i​n​t​e​r​s​ ​a​n​d​ ​f​i​l​l​e​d​
/​/​ ​o​u​t​ ​b​y​ ​t​h​e​ ​m​e​t​h​o​d​.​
-​ ​(​v​o​i​d​)​e​x​t​r​a​c​t​_​g​e​t​R​e​d​:​(​f​l​o​a​t​ ​*​)​r​ ​g​r​e​e​n​:​(​f​l​o​a​t​ ​*​)​g​ ​b​l​u​e​:​(​f​l​o​a​t​ ​*​)​b​
{​
 ​ ​ ​ ​/​/​ ​G​e​t​ ​t​h​e​ ​C​o​r​e​ ​G​r​a​p​h​i​c​s​ ​r​e​p​r​e​s​e​n​t​a​t​i​o​n​
 ​ ​ ​ ​C​G​C​o​l​o​r​R​e​f​ ​c​g​C​l​r​ ​=​ ​[​s​e​l​f​ ​C​G​C​o​l​o​r​]​;​

 ​ ​ ​ ​/​/​ ​G​e​t​ ​e​a​c​h​ ​c​o​m​p​o​n​e​n​t​ ​o​f​ ​t​h​e​ ​c​o​l​o​r​ ​(​"​c​o​l​o​r​ ​c​h​a​n​n​e​l​s​"​)​
 ​ ​ ​ ​c​o​n​s​t​ ​C​G​F​l​o​a​t​ ​*​c​o​m​p​o​n​e​n​t​s​ ​=​ ​C​G​C​o​l​o​r​G​e​t​C​o​m​p​o​n​e​n​t​s​(​c​g​C​l​r​)​;​

 ​ ​ ​ ​/​/​ ​G​e​t​ ​t​h​e​ ​n​u​m​b​e​r​ ​o​f​ ​c​o​m​p​o​n​e​n​t​s​
 ​ ​ ​ ​s​i​z​e​_​t​ ​c​o​m​p​o​n​e​n​t​C​o​u​n​t​ ​=​ ​C​G​C​o​l​o​r​G​e​t​N​u​m​b​e​r​O​f​C​o​m​p​o​n​e​n​t​s​(​c​g​C​l​r​)​;​

 ​ ​ ​ ​i​f​ ​(​c​o​m​p​o​n​e​n​t​C​o​u​n​t​ ​=​=​ ​2​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​A​ ​g​r​a​y​s​c​a​l​e​ ​c​o​l​o​r​ ​w​i​l​l​ ​o​n​l​y​ ​h​a​v​e​ ​t​w​o​ ​c​o​m​p​o​n​e​n​t​s​,​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​t​h​e​ ​g​r​a​y​s​c​a​l​e​ ​v​a​l​u​e​ ​a​n​d​ ​t​h​e​ ​a​l​p​h​a​ ​c​h​a​n​n​e​l​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​A​s​s​i​g​n​ ​t​h​e​ ​v​a​l​u​e​s​ ​p​o​i​n​t​e​d​ ​t​o​ ​b​y​ ​r​,​ ​g​,​ ​b​ ​t​o​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​t​h​e​ ​g​r​a​y​s​c​a​l​e​ ​v​a​l​u​e​
 ​ ​ ​ ​ ​ ​ ​ ​*​r​ ​=​ ​c​o​m​p​o​n​e​n​t​s​[​0​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​*​g​ ​=​ ​c​o​m​p​o​n​e​n​t​s​[​0​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​*​b​ ​=​ ​c​o​m​p​o​n​e​n​t​s​[​0​]​;​
 ​ ​ ​ ​}​ ​e​l​s​e​ ​i​f​ ​(​c​o​m​p​o​n​e​n​t​C​o​u​n​t​ ​=​=​ ​4​)​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​A​ ​R​G​B​ ​c​o​l​o​r​ ​h​a​s​ ​4​ ​c​o​m​p​o​n​e​n​t​s​,​ ​r​,​ ​g​,​ ​b​
 ​ ​ ​ ​ ​ ​ ​ ​/​/​ ​a​n​d​ ​a​n​ ​a​l​p​h​a​ ​c​h​a​n​n​e​l​
 ​ ​ ​ ​ ​ ​ ​ ​*​r​ ​=​ ​c​o​m​p​o​n​e​n​t​s​[​0​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​*​g​ ​=​ ​c​o​m​p​o​n​e​n​t​s​[​1​]​;​
 ​ ​ ​ ​ ​ ​ ​ ​*​b​ ​=​ ​c​o​m​p​o​n​e​n​t​s​[​2​]​;​
 ​ ​ ​ ​}​ ​e​l​s​e​ ​{​
 ​ ​ ​ ​ ​ ​ ​ ​N​S​L​o​g​(​@​"​U​n​s​u​p​p​o​r​t​e​d​ ​c​o​l​o​r​s​p​a​c​e​.​"​)​;​
 ​ ​ ​ ​ ​ ​ ​ ​*​r​ ​=​ ​*​g​ ​=​ ​*​b​ ​=​ ​0​;​
 ​ ​ ​ ​}​
}​
-​ ​(​U​I​C​o​l​o​r​ ​*​)​e​x​t​r​a​c​t​_​i​n​v​e​r​t​e​d​C​o​l​o​r​
{​
 ​ ​ ​ ​/​/​ ​U​s​e​ ​m​e​t​h​o​d​ ​y​o​u​ ​j​u​s​t​ ​d​e​f​i​n​e​d​ ​t​o​ ​g​e​t​ ​c​o​m​p​o​n​e​n​t​s​ ​o​f​ ​c​o​l​o​r​
 ​ ​ ​ ​f​l​o​a​t​ ​r​ ​=​ ​0​,​ ​g​ ​=​ ​0​,​ ​b​ ​=​ ​0​;​
 ​ ​ ​ ​[​s​e​l​f​ ​e​x​t​r​a​c​t​_​g​e​t​R​e​d​:​&​r​ ​g​r​e​e​n​:​&​g​ ​b​l​u​e​:​&​b​]​;​

 ​ ​ ​ ​/​/​ ​R​e​t​u​r​n​ ​a​ ​n​e​w​ ​U​I​C​o​l​o​r​ ​i​n​s​t​a​n​c​e​ ​w​i​t​h​ ​i​n​v​e​r​t​e​d​ ​c​o​m​p​o​n​e​n​t​s​
 ​ ​ ​ ​r​e​t​u​r​n​ ​[​U​I​C​o​l​o​r​ ​c​o​l​o​r​W​i​t​h​R​e​d​:​1​.​0​ ​-​ ​r​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​g​r​e​e​n​:​1​.​0​ ​-​ ​g​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​b​l​u​e​:​1​.​0​ ​-​ ​b​
 ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​a​l​p​h​a​:​1​.​0​]​;​
}​
@​e​n​d​

Now, you can send the messages getRed:green:blue: and invertedColor to any instance of UIColor.

This approach has benefits over subclassing UIColor. First, if you had already been using UIColor in your application, you don’t have to go back and change these objects to some new subclass. More importantly, however, many methods that you don’t have control over may return UIColor instances. You would not be able to send these two new messages to those objects with a subclass.

Go back to TouchDrawView.m. At the top of this file, import the header file for this category so this file knows about these new declarations.

#​i​m​p​o​r​t​ ​"​T​o​u​c​h​D​r​a​w​V​i​e​w​.​h​"​
#​i​m​p​o​r​t​ ​"​L​i​n​e​.​h​"​
#​i​m​p​o​r​t​ ​"​U​I​C​o​l​o​r​+​E​x​t​r​a​c​t​.​h​"​

Now, when you send the message invertedColor to a Line’s color,

[​s​e​l​f​ ​t​r​a​n​s​f​o​r​m​L​i​n​e​C​o​l​o​r​s​W​i​t​h​B​l​o​c​k​:​^​(​L​i​n​e​ ​*​l​)​ ​{​
 ​ ​ ​ ​r​e​t​u​r​n​ ​[​[​l​ ​c​o​l​o​r​]​ ​e​x​t​r​a​c​t​_​i​n​v​e​r​t​e​d​C​o​l​o​r​]​;​
}​]​;​

the method in your category will be executed. You might want to keep this category around, it is pretty useful.

Build and run the application. Draw some lines and then shake the device. Rotate it, and the colors will invert. Rotate it again, and the colors will revert back to normal.

Categories have another use: pseudo-private methods. In Objective-C, there is no such thing as a private method. If a class implements a method, you can always send that message. However, you sometimes want the ability to at least hide methods from a user of the class. For example, a method that only gets called internally by the class and requires a certain set of conditions in order to operate properly is not something you want other objects knowing about. You could, of course, leave that method declaration out of the header file, but the compiler will give you a warning when you try to use it.

To hide method declarations and hush up the compiler about undeclared methods, you can create a category at the top of an implementation file with declarations for methods you don’t want used by other objects. A category used for this reason is called a class extension and has no name. Methods in a class extension must be implemented in the standard @implementation block of a class or the compiler will complain. Near the top of TouchDrawView.m, add the following category declaration.

@​i​n​t​e​r​f​a​c​e​ ​T​o​u​c​h​D​r​a​w​V​i​e​w​ ​(​)​
-​ ​(​v​o​i​d​)​t​r​a​n​s​f​o​r​m​L​i​n​e​C​o​l​o​r​s​W​i​t​h​B​l​o​c​k​:​(​U​I​C​o​l​o​r​ ​*​ ​(​^​)​(​L​i​n​e​ ​*​)​)​t​;​
-​ ​(​v​o​i​d​)​c​o​l​o​r​i​z​e​;​
@​e​n​d​

@​i​m​p​l​e​m​e​n​t​a​t​i​o​n​ ​T​o​u​c​h​D​r​a​w​V​i​e​w​

Now, you won’t get any warnings when TouchDrawView uses one of these methods, but any other file that tries to use these methods will get a warning. (You may not have had any warnings to begin with depending on the order you implemented your methods.) Note that even though these methods aren’t visible to other files, they can still be invoked. The compiler will just complain.

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

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