Category的最初体验,iOS设计模式

作者:计算机网络

Step3: 导入Category在"ViewController.h"文件头部添加以下代码来导入Category

IOS开发:Objective-C Category的最初体验

   Step1: 创建项目

  启动Xcode -> File -> New -> Project. 然后创建一个 iOS Single View Applciation。这里我们命名为 Categories.

新葡京8455 1

  Step2: 创建Category

  现在来创建一个Category来为NSString添加扩展方法。点击 File -> New -> File 然后选择 Cocoa Touch Objective-C category. 这里我们命名为 RemoveNums。记得要从 Category on 下拉框选择 NSString,最后点击Create按钮旁的Next按钮。

新葡京8455 2

  声明Category扩展的方法。

  选择 "NSString RemoveNums.h"文件。添加以下代码:

1 @interface NSString (RemoveNums)
2 - (NSString *)removeNumbersFromString:(NSString *)string;@end

  实现Category扩展的方法

  接着来到"NSString RemoveNums.m"文件。添加以下代码。大家可以看到这个方法实际做的事情就是从整个NSString去除掉所有的数字字符。

1 - (NSString *)removeNumbersFromString:(NSString *)string
2 {
3 NSString *trimmedString = nil;
4 NSCharacterSet *numbersSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"];
5 trimmedString = [string stringByTrimmingCharactersInSet:numbersSet];
6 return trimmedString;
7 }

  Step3: 导入Category

  在"ViewController.h"文件头部添加以下代码来导入Category

1 #import "NSString RemoveNums.h"

  Step4: 测试Category

  在 ViewController.h 文件的 viewDidLoad 方法中添加以下代码。

1 NSString *stringWithNums = @"ABC 123";
2 NSLog(@"stringWithNums --> %@",stringWithNums);
3 stringWithNums = [stringWithNums removeNumbersFromString:stringWithNums];
4 NSLog(@"trimmed stringWithNums --> %@",stringWithNums);

  Step5: 使用Category的方法

  在Xcode的菜单栏点击 Product -> Run,测试过程中,请注意控制台首先输出的 "ABC 123",然后被方法去除数字后输出的"ABC"

新葡京8455 3

  结论

  我们都知道添加子类是为某一种对象添加方法的途径,但是为了整个代码更加简洁直观,我们通常会用Category的扩展方法来替代子类的添加。

Category的最初体验 Step1: 创建项目 启动Xcode - File - New - Project. 然后创建一个 iOS Single View Applciation。这里我们命名为 Categ...

@property(nonatomic,readonly,retain) UINavigationController *navigationController;

NSMutableString *reversedString =[[NSMutableString alloc]init];

Step2: 创建Category现在来创建一个Category来为NSString添加扩展方法。点击 File -> New -> File 然后选择 Cocoa Touch Objective-C category. 这里我们命名为 RemoveNum。记得要从 Category on 下拉框选择 NSString,最后点击Create按钮旁的Next按钮。

类别的第二大优点是实现了功能的局部化封装。类别定义可以放在一个已存在的类(类A)的定义文件中(.h)。这意味着这个类别只有在类A被引用的前提下才会被外部看到。如果另一个类(类B)不需要用到类A的功能(没有包含类A的.h文件),也就不会看到依附类A存在的类别。iOS SDK中广泛运用这种类别定义法来封装功能。例如,在UINavigationController.h中定义了专为UINavigationController扩展的UIViewController类别:

}

  1. 提供一种简单的方式,扩展现有类定义,不必访问类的源代码,也无须创建子类。

通过类别可以提供声明,而且,声明的方法不必要一定在类别的实现中实现,也可以在类的实现中实现

如果需要添加一个新的变量,则需添加子类。

  • 分类可以覆写该类中的另一个方法,但是通常认为这种做法是拙劣的设计习惯。因为,覆写了一个方法后,再也不能访问原来的方法。如果确实需要覆写方法,正确的选择可能是创建子类。如果要在子类中覆写方法,仍然可以通过向super发送消息来引用父类的方法。因此不必了解要被覆写方法的复杂内容,就能够调用父类的方法,并向子类的方法添加自己的功能。
  • 如果喜欢可以拥有许多分类,只要遵守此处指出的规则即可。如果一个方法定义在多个分类中,该语句不会指定使用哪个分类。
  • 记住,通过使用分类添加新方法来扩展类不仅会影响这个类,同时也会影响所有他的子类。例如,如果为根对象NSObject添加新方法,就存在潜在的危险性,因为每个人都继承这些新的方法,无论你是否愿意。
  • 通过分类为现有类添加新方法可能对你有用,但最好不要增加与该类的原始设计或意图不一致的方法。
  • 对象/分类命名对必须是唯一的。但是,在给定的Objective-C名称空间中,只能存在一个NSString Name Utilities分类。

Xcode中创建范畴文件的方法:New File-Objective-C File-File Type选择Category,Class选择需要扩展的方法,File输入文件名。

_myString.text = test;

新葡京8455 4

新葡京8455 5

{

@interface NSString (RemoveNums)//分类名放在圆括号中,为`RomoveNums`- (NSString *)removeNumbersFromString:(NSString *)string;@end

@end

Category模式用于向已经存在的类添加方法从而达到扩展已有类的目的,在很多情形下Category也是比创建子类更优的选择。新添加的方法同样也会被被扩展的类的所有子类自动继承。当知道已有类中某个方法有BUG,但是这个类是以库的形式存在的,我们无法直接修改源代码的时候,Category也可以用于替代这个已有类中某个方法的实体,从而达到修复BUG的目的。然而却没有什么便捷的途径可以去调用已有类中原有的那个被替换掉方法实体了。需要注意的是,当准备有Category来替换某一个方法的时候,一定要保证实现原来方法的所有功能,否则这种替代就是没有意义而且会引起新的BUG。和子类不同的是,Category不能用于向被扩展类添加实例变量。Category通常作为一种组织框架代码的工具来使用。Category的用途1.      在不创建继承类的情况下实现对已有类的扩展。2.      简化类的开发工作(当一个类需要多个程序员协同开发的时候,Category可以将同一个类根据用途分别放在不同的源文件中,从而便于程序员独立开发相应的方法集合)。3.      将常用的相关的方法分组。4.      在没有源代码的情况下可以用来修复BUG。Category的用法在Obj-C中,声明某一个已有类的Category扩展的方法如下:@interface ClassName (CategoryName)  -methodName1  -methodName2  @end  上面的声明通常是在.h文件中,然后我们在.m文件中实现这些方法@implementation ClassName (CategoryName)  -methodName1  -methodName2  @end  我们创建一个iOS Single View Applciation名为CategoryExample。然后为创建一个NSString类的category扩展。File->New->File然后选择 Cocoa Touch Objective-C category.命名为ReverseNSString.系统会自动生成一个固定格式ClassName CategoryName的.h和.m文件。声明Category打开NSString ReverseNSString.h文件,在里面添加如下代码:#import@interface NSString (ReverseNSString)

#import "NSString RemoveNums.h"

5、 使用类别创建前向引用

#import"NSString ReverseNSString.h"

Step5: 使用Category的方法在Xcode的菜单栏点击 Product -> Run,测试过程中,请注意控制台首先输出的ABC 123,然后被方法去除数字后输出的ABC

示例代码,输出字符串中的原因字母数。

return reversedString;

新葡京8455 6

新葡京8455,@property(nonatomic,readonly,retain) UINavigationItem *navigationItem;

并没有什么界限分明的判定标准来作为何时用Category何时用添加子类的方法的指导。但是有以下几个指导性的建议:

Step1: 创建项目启动Xcode -> File -> New -> Project. 然后创建一个 iOS Single View Applciation。这里我们命名为 Categories.

新葡京8455 7

如果只是添加一个新的方法,用Category是比较好的选择。

- (NSString *)removeNumbersFromString:(NSString *)string{ NSString *trimmedString = nil; NSCharacterSet *numbersSet = [NSCharacterSet characterSetWithCharactersInString:@"0123456789"]; trimmedString = [string stringByTrimmingCharactersInSet:numbersSet]; return trimmedString;}

2、 类别的局限性

}

声明Category扩展的方法。选择 "NSString RemoveNums.h"文件。添加以下代码:

@interface 类名(类别名)

charIndex--;

Categories可以为一个对象添加方法而不需要增加该类的子类或者更改当前的对象。实际上Categories通常被用来为已经存在的类添加方法,比如你可以自己为 NSString 字符串类添加你自己的方法。

Categories provide the ability to add functionality to an object without subclassing or changing the actual object. A handy tool, they are often used to add methods to existing classes, such as NSString or your own custom objects.

  1. 提供一种简单的方式,将类的定义模块化到相关方法的组或分类中;

@interface UIViewController (UINavigationControllerItem)

代码组织

Step4: 测试Category在 ViewController.h 文件的viewDidLoad方法中添加以下代码。

如果一个类不引用UINavigationController.h,也就不会看到navigationItem和navigationController这两个性质申明(declared property)。

@end

NSString *stringWithNums = @"ABC 123";NSLog(@"stringWithNums --> %@",stringWithNums);stringWithNums = [stringWithNums removeNumbersFromString:stringWithNums];NSLog(@"trimmed stringWithNums --> %@",stringWithNums);

虽然可以实现未声明的方法,但是编译器会提出警告

@end

欢迎来我的个站逛逛:

@end

-(IBAction)reverseString:(id)sender {

新葡京8455 8

其实就是委托对象必须实现别的对象调用的方法,与接口类似

while (charIndex > 0) {

实现Category扩展的方法。接着来到"NSString RemoveNums.m"文件。添加以下代码。大家可以看到这个方法实际做的事情就是从整个NSString去除掉所有的数字字符。

同实现类相似,实现方法即可

Category用于大型类有效分解。通常一个大型类的方法可以根据某种逻辑或是相关性分解为不同的组,一个类的代码量越大,将这个类分解到不同的文件中就显得越有用,每个文件中分别是这个类的某些相关方法的集合。

1.将类的实现分散到多个不同文件或多个不同框架中

实现Category

特别指出的是:类别可以访问其继承的类的实例变量

NSString *test = [NSStringreverseString:_myString.text];

创建一个NSObject的类别称为“创建一个非正式协议”

NSInteger charIndex = [strSrc length];

3 类别的作用

Category VS添加子类

在使用一个方法时,对象的方法是在接口中声明、父类中声明、还是类别中声明并不重要

NSString ReverseNSString.m文件中实现reverseString方法:

7、 ITunesFinder项目

[reversedString appendString:[strSrcsubstringWithRange:subStrRange]];

@interface ClassName(CategoryName)

剩下的工作就是验证我们的Category了,在view中添加一个按钮ReverseString,并设置相应的action方法为reverseString.在view上再添加一个label,命名为myString,默认值是”HelloCategory Design Pattern!”。点击按钮反转这个字符串。主要代码如下:

//method declarations

}

1.现有类的类名位于 @interface之后

当有多个开发者共同完成一个项目时,每个人所承担的是单独的cagegory的开发和维护。这样就版本控制就更加简单了,因为开发人员之间的工作冲突更少了。

2.括号中是类别的名称(只要名称唯一,可以添加任意多的类别)

(NSString*) reverseString:(NSString*)strSrc;

NSObject提供了一个respondsToSelector的方法,询问对象以确定其是否实现某个特定消息

@implementationNSString (ReverseNSString)

2.创建私有方法的前向引用

(NSString*)reverseString:(NSString*)strSrc;

类别方法申明

NSRange subStrRange =NSMakeRange(charIndex, 1);

Objective-C提供了一个非常灵活的类(Class)扩展机制-类别(Category)。类别用于对一个已经存在的类添加方法(Methods)。你只需要知道这个类的公开接口,不需要知道类的源代码。需要注意的是,类别不能为已存在的类添加实例变量(Instance Variables)。

4 利用类别分散实现

选择器可以被传递,可以作为方法参数,甚至可以作为实例变量存储

......

委托对象接受其它对象对它的特定方法的调用

利用类别可以将类的方法分散到多个源文件中

6、 非正式协议和委托类别

3.向对象添加非正式协议

9、 响应选择器

通过使用范畴(Category),程序员可以为任何已有的类添加方法。以NSString为例,虽然没有NSString的源码,但是借助范畴就能为NSString添加新方法。

1、实现类别

类别的另一个优点是轻巧(light-weight)。很多时候,对已存在的类所需的扩展仅仅是几个新方法。这时,用类别避免了在系统中留下很多非常短小的“微”子类,使程序更加紧凑。

类别的基本语法如下:

10、 选择器的其他应用

类别不仅可以分散实现到不同源文件,也可跨框架

3.类别没有实例变量部分

2.命名冲突,如果类别中方法和类中已有方法同名,则类别具有更高优先级

新葡京8455 9

委托(delegage)是一种对象,另一个类的对象会要求委托对象执行它的某些操作

注意几点:

归纳:

8 、委托和类别

类别的语法与类的语法非常相似。类别的方法就是类的方法。类别的定义可以放在一个单独的文件中("类别名.h"), 也可以放在一个已存在的类的定义文件中(.h文件)。类别的实现则可放在一个单独的“类别名.m”文件中,或另一个类的实现文件中。这点也与类的定义相似。因为类别的方法就是类的方法,所以类别的方法可以自由引用类的实例变量(无论公有或私有)。

子类(subclassing)是进行类扩展的另一种常用方法。与子类相比,类别最主要的优点是:系统中已经存在的类可以不需修改就可使用类别的扩展功能。例如,假设系统中存在一个类A;另外一个类B中定义了一个类A类型的实例变量,并包含了类A的头文件“#import "。假设一段时间后,需要对类A扩展几个新的方法。如果用子类,就需要创建一个子类A-1。如果类B想要使用类A的新方法,就要进行如下修改:1) 将包含的头文件改为"#import"; 2)将所有用到的类A对象改为类A-1的对象。可以想象,如何有很多类需要用到类A的新功能(比如类A是iOS中的类UIViewController),随着系统的升级(iOS从1.0到5.0),你的程序需要不停地进行这种繁琐地修改。如果使用类别,即使类A升级了,系统中其它的类可以不需任何修改,直接就可以调用类A的新方法。

@end

委托和类别有什么关系?委托强调类别的另一种应用:被发送给委托对象的方法可以声明为一个NSObject的类别

选择器只是一个方法名称,可以使用@selector()预编译指令指定选择器,其中方法名位于圆括号中,但它以OC运行时使用的特殊方式编码,以快速执行查询

1.类别不能添加新的实例变量

本文由新葡京8455发布,转载请注明来源

关键词: