1:分类
给某一个类扩充一些方法,并且不修改原来的代码。
格式
@interface 类名(分类名)
@end
@implementation 类名
@end
使用注意:
1: 分类只能增加方法,不能增加成员变量。
2:分类方法实现中可以访问原来类中声明的成员变量。
3:分类可以重新实现原来类中的方法,但是会覆盖掉原来的方法,会导致原来类中的方法没法使用。
如果原先类中实现了某个方法,分类中又实现了这个方法,当调用方法时。会优先调用分类中的方法。没有的话再去原类,再者是父类。如果一个类有多个分类,并且每个分类中都有这个方法的实现,则最后编译的那个分类会覆盖掉原来所有的方法。调用时,则调用最后编译的那个。
分类的好处:
一个庞大的类可以分模块开发。可以由多人来写。有利于团队开发 。
分类可以访问原类的成员变量,但不能添加新的成员变量,只能添加方法,如果想添加变量,可以考虑通过继承创建子类。
例如:
给系统自带的NSString 字符串扩充一个方法。使它可以计算对象自身中所含的阿拉伯数字个数。
- (int) number
{
for (int i = 0; i< self.length ; i++)
// 遍历整个字符串
{
unichar c = [self characterAtIndex : i ];
// 取出字符串中的某个字符
}
if (c >='0'&& c<='9')
// 判断字符的范围
{
count ++;
// 计算加1
}
return count ;
}
2: 类的本质
类本身也是一个对象,是Class 类型的数据,简称类对象。
当利用一个类创建对象时,先利用class 这个类创建出一个类对象,再用创建出来的类对象创建新的类对象。
例如:
Person * p = [[person alloc ] init ];
Person * p2 = [[person alloc ] init ];
Person * p3 = [[person alloc ] init ];
获取p,p2,p3 的内存地址
class c = [p class ];
class c2 = [p class ];
NSLog(@"%@,%@,c,c2");
输出结果是一样的,这说明p 与P2 在内存中指向同一个类。
也可以用 : Class c3 = [ person class ];
出c3 的结果也是相同的。
Class 定义为:
typedef struct objc class * class ;
类名就代表着一个类对象。每个类只有一个类对象。
此时 c 与 person 等价,都代表着类。
Person * p4 = [ [c alloc ] init ];
3: + load 和 + initialize 方法
1:+load
1>: 在程序启动时会加载所有的类和分类,并调用所有类的+ load 方法。
2>:先加载父类,在加载子类,也就是先调用父类的+ load 方法,在调用子类的+ load 方法。
3>: 先加载原类,在加载分类。
4>:不管程序如何运行有没有用到这个类,都会调用类的+ load 方法。
2: + initialize 方法
1>: 在第一次使用这个类时,就会调用这个类的 initialize 方法。
2>:一个类只会调用一次 initialize 方法,先调用父类的在调用子类的;先初始化父类,在初始化子类。
3>:如果类和分类都有 initialize 方法,则优先使用分类中的 initialize 方法。
4: description 方法
可分为- description 方法和 + description 方法
1>: 使用NSLog 和%@ 输出某个对象时,会调用对象的- description 方法,并拿到返回值输出。
默认的输出是< 类名: 内存地址>
2>: 使用NSLog 和%@ 输出某个类对象时,会调用类对象的+ description 方法,并拿到返回值输出。
默认的输出是< 类名>
例如:
@interface Person : NSObject
{
int age ;
double weight;
}
- void test ;
@end
@implementation Person
- void test
{
NSLog (@'' 调用 test 函数");
}
@end
int main ()
{
Person * p = [ [person alloc ] init ];
p.age = 10;
p.weight = 50;
NSLog(@"%@,p");
// 本来是想输出整个p 对象,可是默认输出为< 类名: 内存地址>。
// 所以此时我们要想输出自己想要的结果,必须要重写- description方法。
注意:
- (id) description
{
NSLog(@"%@,self ");
}
这个是死循环,自己调用自己。
+ description 方法 与上述相似,不过它是类方法,要由类名调用。
例如:
int main ()
{
Class c = [ person class ];
NSLog(@"%@, c");
return 0;
}
默认输出为 : 类名
SEL
Person * p = [ [person alloc ] init ];
[ p test ] ;
// 调用对象方法,给它发送一条 test 消息,本质就是发送一个SEL类型的数据。
分为三步:
1:把test 包装成SEL 类型的数据。
2: 根据 SEL 数据 在类中找到相应的内存地址。
3: 根据方法地址调用相应的方法。
调用方法的两种方法:
1: 直接调用
[ p test ]
2:间接调用
[p performSelector :@ selector (test)]
3:如果有参数
[p performSelector :@ selector (test2:) WihObject : 实参 ]
方法的存贮位置:
每个类的方法列表都存贮在类对象中
每个方法都有一个与之对应的SEL 数据。
根据一个SEL数据就可以找到方法的地址,然后调用方法。
SEL类型的定义:
typedef struct objc select * SEL;
网友评论