Category is one of the most commonly used functions in objective-C. Category can add methods for existing classes without adding a subclass. In addition, we can add methods for a class without knowing its internal implementation. If we want to add a class method in a framework, category is very effective. For example, if you want to add a method on nsstring to determine whether it is a valid URL, you can do this:
@interface NSString (extension)- (BOOL) isURL;@end
Do you think it is very similar to the definition of a class? Indeed, there is no parent class in category, and you need to write category in parentheses.
. The implementation of isurl is as follows:
@implementation NSString(extension)- (BOOL) isURL{ if( [self hasPrefix:@"http://"] ) return YES; else return NO;}@end
Now you can call this method on any nsstring class object. The following is an example of a call:
Nsstring * str1 = @ "http://www.blog.csdn.net/iukey"; nsstring * str2 = @ "Liu Wei Lewis"; if ([str1 isurl]) nslog (@ "str1 is a URL "); if ([str2 isurl]) nslog (@ "str2 is a URL ");
The example above shows that the new method added by category becomes a part of the class. The method we add to a category also exists in its method list. The new method added to the nsstring subclass does not exist in nsstring. The new method added by category can perform any operation like other methods of this class. At runtime, the newly added method is no different from the existing method. The method added by category is inherited by its subclass like other methods.
The class interface definition looks like the class interface definition, but the difference is that the class name is listed in parentheses, they are behind the class name. Class must be imported into the interface file of its extended class. The standard syntax is as follows:
# Import "class name. H" @ Interface Class Name (Class Name) // Declaration of the new method @ end
An implementation file of the same category as a class also needs to import its interface file. A common naming convention is that the basic file name of a category is the name of the extended category class followed by the category name. Therefore, an implementation file named "Class Name" + "Class Name" + ". m" looks like this:
# Import "Class Name class name. H" @ Interface Class Name (Class Name) // new implementation method @ end
Note: A class does not declare a new instance variable for the class. It only contains methods. However, all instance variables in the class scope can be accessed by these classes. They include all instance variables declared for the class, and even those modified by @ private. You can add multiple classes for a class, but each class name must be different, and each class must be declared and implemented in a different way.
Remember, when we modify a class through category, all the objects of this class in the corresponding application work. Unlike subclass, category cannot add member variables. We can also use category to override the existing method of the class (but this is not recommended ). Finally, we provide a complete example (this example is to extend the uiimage class to add a method for converting an image into a grayscale image ):
// GrayScale.h// XOGameFrame//// Created by song on 11-1-12.// Copyright 2011 __MyCompanyName__. All rights reserved.//#import <Foundation/Foundation.h>@interface UIImage (grayscale)- (UIImage *)convertToGrayscale ;@end
//// GrayScale.m// XOGameFrame//// Created by song on 11-1-12.// Copyright 2011 __MyCompanyName__. All rights reserved.//#import "GrayScale.h"@implementation UIImage (grayscale)typedef enum { ALPHA = 0, BLUE = 1, GREEN = 2, RED = 3} PIXELS;- (UIImage *)convertToGrayscale { CGSize size = [self size]; int width = size.width; int height = size.height; // the pixels will be painted to this array uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t)); // clear the pixels so any transparency is preserved memset(pixels, 0, width * height * sizeof(uint32_t)); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); // create a context with RGBA pixels CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast); // paint the bitmap to our context which will fill in the pixels array CGContextDrawImage(context, CGRectMake(0, 0, width, height), [self CGImage]); for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x]; // convert to grayscale using recommended method: http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE]; // set the pixels to gray rgbaPixel[RED] = gray; rgbaPixel[GREEN] = gray; rgbaPixel[BLUE] = gray; } } // create a new CGImageRef from our context with the modified pixels CGImageRef image = CGBitmapContextCreateImage(context); // we're done with the context, color space, and pixels CGContextRelease(context); CGColorSpaceRelease(colorSpace); free(pixels); // make a new UIImage to return UIImage *resultUIImage = [UIImage imageWithCGImage:image]; // we're done with image now too CGImageRelease(image); return resultUIImage;}@end