http://blog.csdn.net/iukey/article/details/7341340
category 是Objective-C 里面最常用到的功能之一。category 可以为已经存在的类增加方法,而不需要增加一个子类。而且,我们可以在不知道某个类内部实现的情况下,为该类增加方法。如果我们想增加某个框架(framework)中的类的方法,category 就非常有效。比如,如果想在NSString 上增加一个方法来判断它是否是有效的 URL,那么就可以这样做:
- @interface NSString (extension)
- - (BOOL) isURL;
- @end
- @implementation NSString(extension)
- - (BOOL) isURL{
- if( [self hasPrefix:@"http://"] )
- return YES;
- else
- return NO;
- }
- @end
- NSString* str1 = @"http://www.blog.csdn.net/iukey";
- NSString* str2 = @"刘伟Lewis";
- if([str1 isURL])
- NSLog(@"str1 is a URL");
- if([str2 isURL])
- NSLog(@"str2 is a URL");
通过上面的例子可以看出,通过类别所添加的新方法就成为类的一部分。我们通过为类别所添加的方法也存在于他的方法列表中,而为NSstring 子类添加的新方法,NSString是不具有的。通过类别所添加的新方法可以向这个类的其他方法一样完成任何操作。在运行时,新添加的方法和已经存在的方法在使用上没有任何区别。通过类别添加的方法和别的方法一样会被他的子类所继承。
类别接口的的定义看起来很像类接口的定义,而不同的是类别名用圆括号列出,他们位于类名后面。类别必须导入他所扩展的类的接口文件。标准语发格式如下:
- #import "类名.h"
- @interface 类名(类别名)
- //新方法的声明
- @end
和类一样类别的实现文件也要导入它的接口文件。一个常用的命名约定是,类别的基本文件名是这个类别扩展的类的名字后面跟类别名。因此一个名字为 “类名”+“类别名”+“.m”的实现文件看起来就是这样:
- #import "类名类别名.h"
- @interface 类名(类别名)
- //新的实现方法
- @end
要记住,我们通过 category 来修改一个类的时候,他对应应用程序里这个类所有对象都起作用。跟子类不一样,category 不能增加成员变量。我们还可以用 category里重写类原先存在的方法(但是并不推荐这么做)。最后给出一个完整在例子(这个例子是扩展UIImage类 为其添加一个把图像变为灰度图像的方法):
- // 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