黑马程序员技术交流社区
标题:
IOS基础语法-Category分类
[打印本页]
作者:
lixiaopeng
时间:
2015-7-23 21:35
标题:
IOS基础语法-Category分类
分类的语法非常好用,在我们以后的开发中也会经常使用,那么分类怎么用呢?分类的英文是Category,因为这个单词是从国外翻译过来的,所有有人叫它分类,也有人叫它类别,一般我们叫它分类。那么它使用在什么场景呢?
我们新建一个Person类,并为这个类增加一个test方法(“-”,减号就代表对象方法嘛)。
Person.h类的声明代码如下:
#import <Foundation/Foundation.h>
@interface Person : NSObject
{
int _age;
}
@property int age;
- (void)test;
@end
复制代码
Person.m类的实现代码如下:
#import "Person.h"
@implementation Person
- (void)test
{
NSLog(@"调用了test方法");
}
@end
复制代码
那么,我要求给Person这个类再新增一个方法,但前提是不准改变Person类原来的代码。应用我们之前学过的知识可以使用继承,给Person扩充方法,如果不使用继承的话,那么我们又该怎么办呢?这个时候我们就要用到分类了。分类就是用来干这个事的,分类可以在不修改原来类的代码的前提下,给某个类扩充一些方法。我们给类扩充方法,试想一下,这个分类的格式是否和类的格式一样呢?
分类的格式,如下:
① //声明
@interface 类名 (类名名称) //分类名称一般为项目的模块名
...
@end
② //实现
@implementation 类名 (类名名称)
...
@end
实际操作流程:项目右击→NEW FILE→OS X下面的Cocoa→Objective C Category,然后Category分类名写:XP(XP是我名字的缩写,告诉别人这个类是我写的),Category on(你要给哪个类添加分类),我们这里写Person,创建完之后,就如下面,会有两个文件,默认是类名+分类名,这样我们就很容易分清,这个分类是给哪个类扩充的。
Person+XP.h类的声明代码如下:
#import <Person.h> //如果去掉,就找不到Person类
@interface Person (XP)
//为Person类增加一个study方法
- (void)study;
@end
复制代码
Person+XP.m类的实现代码如下:
#import "Person+XP.h"
@implementation Person (XP)
- (void)study
{
NSLog(@"这是给Person增加的study方法");
}
@end
复制代码
那么我们就来调用一下
现在能感受到分类的好处了吗?好处就是,在以后的开发中,一个很庞大的类,庞大到一个类中有几百上千个方法,每个方法的功能都不一样,这个我们就可以把不同功能的方法,写到不同的类中。一个分类写一个功能,比如一个功能有几十个方法,我们就可以写到一个分类中,另外功能的方法,可以写到另外的分类中。每个功能都有一个名称,这样有利用团队开发。
#import <Foundation/Foundation.h>
#import "Person.h" </span>//自己写的类,我们导入的话,要用双引号,系统自带的,要用“<>”
#import "Person+XP.h"
#import "Person+XX.h"
int main()
{
Person *p = [[Person alloc] init];
[p test];//即可调用Person类中的test方法
//[p study]; 如果我们调用study方法,是没有提示的,因为我们Person类中是没有study方法的
//study方法在Person+XP.h中,所以我们的引入 #import "Person+XP.h",然后再调用的话,就会有提示
//[p study];
return 0;
}
复制代码
我们现在再创建一个分类
Person+XX.h类的声明代码如下:
#import "Person.h"
@interface Person (XX)
- (void)test2;
@end
复制代码
Person+XX.m类的实现代码如下:
#import "Person+XX.h"
@implementation Person (XX)
- (void)test2
{
NSLog(@"Person+XX的test2方法");
}
@end
复制代码
那么,我们这时候Person类就有了三个方法test、study、test2。这三个方法是在三个不同的文件里面。这个时候我们如果要调用test2方法,我们就需要在main方法中导入头文件 #import "Person+XX.h",然后使用[p test2];就可以了。
下面我们就介绍分类的使用注意,也算是总结吧!
1.分类只能增加方法,不能增加成员变量,我们可以通过继承创建子类,为父类添加变量
把我们刚才写的代码拿出来,看一下
#import "Person+XP.h"
@implementation Person (XP)
{
int _age;//这句话是会立马报错的!
}
- (void)study
{
NSLog(@"这是给Person增加的study方法");
}
@end
复制代码
2.分类方法实现中可以访问原来类中声明的成员变量
#import "Person+XP.h"
@implementation Person (XP)
- (void)study
{
NSLog(@"这是给Person增加的study方法");
NSLog(@"age = %d",_age);//分类中是可以访问原来类中声明的变量
}
@end
复制代码
如果在main方法中,给p对象的属性age赋值为10;p.age = 10;那么Person+XP.m中就会打印出 age = 10;
3.分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,导致原来的方法没法使用。
#import "Person+XP.h"
@implementation Person (XP)
- (void)study
{
NSLog(@"这是给Person增加的study方法");
NSLog(@"age = %d",_age);//分类中是可以访问原来类中声明的变量
}
- (void)test //Person类中也有一个叫test的方法
{
NSLog(@"Person+XP的test方法");//这个会覆盖掉Person类中的test方法,导致Person类中的test方法没法使用
}
@end
复制代码
4.多个Category中实现了相同的方法,只有最后一个参与编译才会有效
#import "Person+XX.h"
@implementation Person (XX)
- (void)test
{
NSLog(@"Person+XX的test方法");//这个会覆盖掉Person类中的test方法,导致Person类中的test方法没法使用
}
@end
复制代码
我们知道会覆盖掉父类中的方法,但是在Person+XP.m和Person+XX.m中都有test方法,到底会执行那个分类中的test方法呢?哪个分类最后编译,就执行那个分类的里面的test方法
优先级:优先去分类中查找,然后去原来类中找,最后再去父类中找。
分类(最后参与编译的分类优先)→原来类→父类
分类的应用
给NSString增加类方法:
之前我们都是在给Person类增加分类,Person类是我们自己定义的类,但是实际上,在以后的开发过程中,很多情况下,比一定是给自己的类增加分类,而是给系统自带的类增加分类,那为什么呢?我们学过两个系统自带的类,一个是NSObject,另一个就是NSString,系统类都提供了很多好用方法给我们,但是在实际的开发过程中,不能满足我们的需求,这个时候我们就要为系统自带的类扩充方法。
分类的好处:
1.一个庞大的类可以分模块开发;
2.一个庞大的类可以由多个人来编写,更有利于团队合作;
需求:
给NSString增加一个类方法,计算某个字符串中的阿拉伯数字的个数;
给NSString增加一个对象方法,计算当前字符串中阿拉伯数字的个数;
创建一个项目,增加一个类文件NSString+Number
NSString+Number.h类的声明代码如下:
#import <Foundation/Foundation.h>
@interface NSString (Number)
+ (int)numberCountOfString:(NSString *)str;//NSString类方法
- (int)numberCount;//NSString对象方法
@end
复制代码
NSString+Number.m类的实现代码如下:
#import "NSString+Number.h"
@implementation NSString (Number)
+ (int)numberCountOfString:(NSString *)str
{
//定义变量计算数字的个数(局部变量一定要初始化)
int count = 0;
for(int i = 0; i < str.length; i++)
{
unichar c = [str characterAtIndex:i];
if( c >= '0' && c <= '9')
{
count++;
}
}
return count;
}
- (int)numberCount
{
int count = 0;
for(int i = 0; i < self.length; i++)
{
//取出i这个位置对应的字符
unichar c = [self charcterAtIndex:i];
//如果c是阿拉伯数字,count就自增一次
if( c >= '0' && c <= '9')
{
count++;
}
}
return count;
}
@end
复制代码
main方法里面调用
#import <Foundation/Foundation.h>
int main()
{
//int count = [NSString numberCountOfString:@"54354dsd"];
//NSLog(@"%d",count); //打印出来的结果为 5
return 0;
}
复制代码
如果要算出@"542454dsd"这个对象,就直接设计成如下
[@"542454dsd" numberCount];//这样写,就可以体现面向对象的思想
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/)
黑马程序员IT技术论坛 X3.2