您的位置:首页 > 其它

ObjC第五节:协议和分类

2015-08-18 09:41 330 查看
协议和分类

1、协议

2、NSCoping

3、分类

4、其他特性

5、扩展

1、协议、分类、继承

MyPoint.h(主类)

#import <Foundation/Foundation.h>

@interface MyPoint : NSObject <NSCopying>  //相当于重复遵守copy协议
{
int x, y;
}
@property (nonatomic) int x, y;

- (void) print;
- (void) over;

@end
MyPoint.m

#import "MyPoint.h"

@implementation MyPoint  //如果没有实现required协议,会警告
#warning 没有实现方法
//这个就是标记此处代码有一个警告,Xcode会在此处显示黄色标记,这个作用就是给自己添加一个标记,后续在来查看
@synthesize x, y;

- (void) print
{
NSLog(@"X= %d, Y= %d", x, y);
}
- (void) over  //将要被重写的方法,不建议分类重写,因为会覆盖原方法致原方法不可用
{
NSLog(@"+++");
}

@end
ABdraw.h(协议)

#import <Foundation/Foundation.h>

@protocol ABdraw <NSObject>  //协议同样可以遵守其他协议

- (void) AB;  //默认@required

@required
- (void) draw;

@optional
- (id) copyWithZone:(NSZone *) zone;  //这里声明了一个与NSCoping一样的方法,但它是选择实现的,凡出现@optional修饰的协议均为非正式协议

@end
MyPoint+Pointe2.h(分类)

#import "MyPoint.h"
#import "ABdraw.h"
@interface MyPoint (Point2) <ABdraw>  //分类遵守的协议,相当于整个类都遵守

//- (void) draw;  //协议,不需声明
- (void) over;

@end
MyPoint+Pointe2.m

#import "MyPoint+Point2.h"

@implementation MyPoint (Point2)

- (void) over
{
NSLog(@"222");
}

#pragma mark - ABdraw
//这个作用就是做一下标记,标记后面的方法都是协议中的方法,这样就可以将一个类中的方法类别分的更细,我们在文件导航栏中进行查看
- (void) draw;
{
NSLog(@"X~~%d, y~~%d", x * x, y * y);
}
- (void) AB  //可以看到,只要实现协议方法就不会警告,即使该实现为空
{

}
- (id) copyWithZone:(NSZone *) zone
{
MyPoint * newPoint = [[MyPoint allocWithZone:zone] init];
newPoint.x = x;
newPoint.y = y;
return newPoint;
}

@end
NewPoint.h(分类)

#import <Foundation/Foundation.h>
#import "MyPoint.h"

@interface MyPoint (Rel)  //分类,建议命名按照“主类+分类”

- (void) moveTo:(int)_x :(int)_y;
- (void) over;

@end
NewPoint.m

#import "NewPoint.h"

@implementation MyPoint (Rel)

-(void) moveTo:(int)_x :(int)_y
{
x = _x;
y = _y;
}
- (void) over
{
NSLog(@"NNN");
}

@end
Circle.h(子类)

#import <Foundation/Foundation.h>
#import "MyPoint.h"

@interface Circle : MyPoint  //子类,继承主类,分类的方法同样被继承

@property (nonatomic) int radius;

- (void) print;
- (void) over;

@end
Circle.m

#import "Circle.h"

@implementation Circle

@synthesize radius;

- (void) print
{
[super print];
NSLog(@"Circle at (%d, %d) with %d", x, y, radius);
}
- (void) over  //实验,同样重写该方法,可以看到,子类可以调用到正确版本
{
NSLog(@"CCC");
}

@end
main.m

//(1)当程序启动时,就会加载项目中所有的类。并且在类被加载完毕后会调用+ (void)load类方法,先加载父类load ,后加载子类的load方法,最后分类
//(2)在类首次使用时,会调用一次+initialize方法,先加载父类initialize ,后加载子类的initialize 方法
//(3)在使用分类时,分类的load方法也会被加载,而且对于initialize方法,会调用子类的initialize的方法。 这里其实还是那个分类的基本原理,调用类和分类的同名函数时是会加载分类的方法
//(4)注意:在初始化的时候,如果在分类中重写了+initialize方法,则会覆盖掉父类的。
//(5)重写+initialize方法可以监听类的使用情况。
#import <Foundation/Foundation.h>
#import "Circle.h"
//#import "NewPoint.h"  //如果不包含,会警告实例方法moveTo没找到(返回类型默认id),但正常运行,建议包含分类头文件
#import "MyPoint+Point2.h"
#import "NewPoint.h"
int main()
{
MyPoint * p = [[MyPoint alloc] init];
p.x = 1;
p.y = 1;
[p print];
[p moveTo:3 :3];  //分类方法
[p print];
[p draw];  //分类方法
[p over];  //分类重写的方法,调用分类中最后编译的那个方法(也有一种说法,编译器不知道调用哪一种方法)
if ([p respondsToSelector:@selector(copyWithZone:)])
{  //respondsToSelector:@selector(方法名),这个方法的作用是判断当前对象中是否定义了一个方法,一般情况下,当协议中有@optional修饰的方法且需要调用该方法时,都需要先判断再调用
MyPoint * p2 = [p copy];  //copy,协议
[p2 print];
[p2 release];
}
Circle * c = [[Circle alloc] init];
c.x = 2;
c.y = 2;
c.radius = 5;
[c print];
[c draw];  //分类方法
[c over];  //子类重写的方法,调用子类方法
[p release];

[c release];

return 0;
}
2、子类copy

Computer.h

#import <Foundation/Foundation.h>

@interface Computer : NSObject <NSCopying>

@property (nonatomic) int height, width;

- (id) initWithHeight:(int)_height Width:(int)width;
- (void)print;

@end
Computer.m

</pre><pre name="code" class="objc">#import "Computer.h"

@implementation Computer

@synthesize height, width;

- (id) initWithHeight:(int)_height Width:(int)_width
{
if (self = [super init])
{
height = _height;
width = _width;
}
return self;
}

- (void)print
{
NSLog(@"Height: %d, Width: %d", height, width);
}

#pragma mark --Copy
- (id)copyWithZone:(NSZone *)zone
{
Computer * c = [[[self class] allocWithZone:zone] init];  //注意[self class],获取调用该方法的对象所在的类,为子类调用父类的copy而能够创建正确空间做基础
c.height = height;
c.width = width;
return c;
}

@end


PC.h

#import <Foundation/Foundation.h>
#import "Computer.h"
@interface PC : Computer

@property (nonatomic) int num, color;

- (id) initWithHeight:(int)_height Width:(int)_width Num:(int)_num Color:(int)_color;
- (void)print;

@end
PC.m

<pre name="code" class="objc">#import "PC.h"

@implementation PC

@synthesize num, color;

- (id) initWithHeight:(int)_height Width:(int)_width Num:(int)_num Color:(int)_color
{
if (self = [super initWithHeight:_height Width:_width])
{
num = _num;
color = _color;
}
return self;
}

- (void)print
{
[super print];
NSLog(@"Num: %d, Color: %d", num, color);
}

- (id)copyWithZone:(NSZone *)zone
{
//PC * p = [[PC allocWithZone:zone] initWithHeight:self.height Width:self.width Num:num Color:color];  //1、使用初始化函数,在这里用实例变量进行赋值,此时可以一次性把子类的所有实例变量赋值(父类和子类)
//p.height = self.height;  //2、使用@property的set函数一一赋值
//p.width = self.width;
//[super copy];  //相当于创建了一个临时的父类对象,不可

PC * p = [super copyWithZone:zone];  //此时因为p1调用copy,self就是p1,(super告诉编译器到self的父类),父类调用copyWithZone:方法,而父类中,[self class]使创建空间的类是子类,而不是父类,就成功创建子类(p2)的空间,(此时父类c是子类p2中父类的部分)接着把p1中父类的部分赋值给p2,然后回到子类方法,继续把p1子类自己的部分赋值给p2
p.num = num;
p.color = color;

//p = [super initWithHeight:self.height Width:self.width];  //赋值正确运行崩溃  - -,不可
return p;
}

@end


main.m

#import <Foundation/Foundation.h>
#import "PC.h"
int main ()
{
Computer * c1 = [[Computer alloc] init];
c1.height = 1;
c1.width = 2;
[c1 print];
Computer * c2 = [c1 copy];
[c2 print];

PC * p1 = [[PC alloc] init];
p1.num = 1001;
p1.color = 1002;
p1.height = 101;
p1.width = 102;
[p1 print];
PC * p2 = [p1 copy];
[p2 print];
[c1 release];
[c2 release];
[p1 release];
[p2 release];
return 0;
}
3、代理(委托)见下节
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ObjC课程