Day1
复习
对于OC进行学习的第一天。首先对于昨天学习的知识进行复习,OC和java一样是一个面向对象的语言,在OC中,声明一个类,首先需要声明一个接口:
@interface ZACircle : NSObject{//以@interface表示声明一个接口(类)
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void)setFillColor:(ShapeColor) fillColor;
- (void)setBounds:(ShapeRect) bounds;
- (void)draw;
@end //以@end表示结束了一个接口(类)的声明
在这个例子中,声明了一个ZACircle的接口,其中有两个私有属性,fillColor和bounds。并且有三个函数。这里一定要注意声明函数的方式,和java、c都不一样。要以‘-’符号开头,在括号中填写返回类型,之后是函数名。冒号是表示有本函数需要参数,后面就是形参列表。也就是:
-(返回类型)函数名:(形参类型)形参名称......
-(方法的数据类型) 函数名: (参数1数据类型) 参数1值的名字 参数2的名字: (参数2数据类型) 参数2值的名字 …;
声明完接口之后,我们需要对它进行实现:
@implementation ZACircle //以@implementation表示对于某个接口进行实现
-(void)setFillColor:(ShapeColor)c{
fillColor=c;
}
- (void)setBounds:(ShapeRect) b{
bounds=b;
}
- (void)draw{
NSLog(@"this shape is circle.the color is %@ . ",colorName(fillColor));
}
@end //以@end表示结束了对于某个类的实现
也就是对于刚刚声明的ZACircle接口中的函数声明进行实现。
有个小小的疑问,那么OC的多态性是怎么实现的呢。既然接口名和实现的impl名是同一个(在上面的例子中,都是ZACircle)如果我要针对ZACircle接口再次实现一个具体的实现类,要怎么做呢?
然后就是实例化对象:
id shapes[3]; //指向某个对象的指针
ShapeRect rect0 = {0,0,10,30};
shapes[0]=[ZACircle new]; //对于指针进行真正的实例化 new一个ZACircle的对象
[shapes[0] setBounds:rect0]; //在OC中调用函数的方式与java和c都有所不同,需要注意
[shapes[0] setFillColor:ZARed];
ShapeRect rect1 = {10,10,20,40};
shapes[1]=[ZACircle new];
[shapes[1] setBounds:rect1];
[shapes[1] setFillColor:ZAGreen];
ShapeRect rect2 = {20,20,30,50};
shapes[2]=[ZACircle new];
[shapes[2] setBounds:rect2];
[shapes[2] setFillColor:ZAYellow];
这里的id是指向某个对象的指针。而真正的对象的实例化是在第四行。同时需要注意的是OC中进行对象函数调用的方式:
[对象名 函数名:参数列表];
以上为昨天内容的复习。今天学习的第一个内容是继承
继承
- OC不支持多继承,只能继承一个。但是可以通过category(类别)和protocol(协议)来达到多继承的效果。
继承的语法:
@interface ZACircle: Shape
@end
@interface ZARectangle: Shape
@end
@interface Shape:NSObject{
@private
ShapeColor fillColor;
ShapeRect bounds;
}
- (void)setFillColor:(ShapeColor) fillColor;
- (void)setBounds:(ShapeRect) bounds;
- (void)draw;
@end
@implementation Shape //以@implementation表示对于某个接口进行实现
-(void)setFillColor:(ShapeColor)c{
fillColor=c;
}
- (void)setBounds:(ShapeRect) b{
bounds=b;
}
- (void)draw{
}
@end //以@end表示结束了对于某个类的实现
@implementation ZACircle
- (void)draw{
NSLog(@"this shape is circle.the color is %@ . ",colorName(fillColor));
}
@end
@implementation ZARectangle
- (void)draw{
NSLog(@"this shape is rectangle.the color is %@ . ",colorName(fillColor));
}
@end
那么需要纠正一点。@interface声明的不应该被称为接口,OC中的类是由两个部分组成。第一个就是声明,这部分是通过@interface进行的。第二部分是实现,是通过@implementation实现的。继承关系等只体现在@interface的声明中,而@implementation只负责对于同名的声明的实现。
复合
即一个类中的属性也为另一个类的对象。
- 类似Java中的Object,OC中也有一个基本的父类NSObject。而description函数就类似toString函数,都是自定义控制台输出。
- OC中的构造函数不与类名相同,而是一个名为init的函数,其返回值为id类型。
@implementation Car
-(id)init{
if(self = [super init]){ //交给双亲进行优先初始化,类似类加载机制?
engine=[Engine new];
tires[0] = [Tire new];
tires[1] = [Tire new];
tires[2] = [Tire new];
tires[3] = [Tire new];
}
return (self);
}
存取方法
也就是getting和setting方法。
@interface Car:NSObject{
Engine *engine;
Tire *Tire[4];
}
-(Engine *)engine; //注意!!!!OC中的get方法不能加get,其get方法有其他的特殊含义。
-(void)setEngine:(Engine *)newEngine;
-(Tire *)tireAtIndex:(int)index; //注意!!!!OC中的get方法不能加get,其get方法有其他的特殊含义。
-(void)setTire:(Tire *)tire atIndex:(int)index;
但是有一说一,OC里多参数的函数还需要多写写代码才能慢慢适应。
源文件组织
即把接口部分的代码放入头文件中,而将具体的实现放入.m文件中。
类的@interface指令、公共struct定义、enum常量、#defines和extern全局变量等放在与类名相同的头文件中
而类的@implementation指令、全局变量的定义、私有struct则放在与类名相同的.m文件中。
@class命令
用来避免循环依赖关系。eg. A中包含B,B中也包含A(两者都是has a 关系)。这时如果使用#import,则会形成循环依赖。而这时使用@class就能避免这种情况。那么在实际开发中:
- 在.h文件中使用@class来对于某一个类进行声明。
- 在.m文件中用#import来将需要的类进行引入。
在java中,解决循环依赖是通过jvm实现的,jvm会将相应的.class文件加载到jvm中,并且通过双亲委派等机制完成类的加载初始化等操作。
导入和继承
如果一个类继承自其他类而非通过指针指向其他类,那么就不能通过@class指令来对其他类进行声明。
FoundationKit介绍
一些有用的数据类型
-
NSRange
相关事物的范围。
-
CGPoint和CGSize
表示点的坐标和长度和宽度。
-
NSString
表示OC中的字符串。(可以通过stringWithFormat函数创建NSString)
其函数原型为:
+(id)stringWithFormat:(NSString *)format,...;PS. “+”表示这是个静态函数。
-
NSArray
- 只能存储OC的对象,不能存储原始C语言数据类型。
- 不能在其中存放null(nil)
NSArray *array = [NSArray arrayWithObjects:@"one",@"two",@"three",nil]; //以nil作为结束标志,这也是不能存放nil的原因之一。 NSArray *array = @[@"one",@"two",@"three"]; -
NSMutableArray
此为可变数组。用法更类似java中的arrayList。
-
NSEnumerator
数组的枚举器,但是要注意,NSArray是一个Fail-Fast的数据集合。
-
快速枚举
类似foreach语法
for(NSString *string in array){ NSLog(@"I found %@.",string) } -
代码块
-
NSDictionary
在给定的关键词下存储一个数值。不能存放nil。
类似Map,但是其中的元素不可变。
-
NSMutableDictionary
可变的字典。
-
NSNumber
-
NSValue
-
NSNull
用于与nil区别开来
内存管理
对象的生命周期
cocoa采用的是引用计数法。
当一个对象因为其引用计数器归0而将被销毁时,会自动调用dealloc方法,我们可以通过重写这个方法来释放相应的内存。
可以通过retainCount获得计数器的值。
ios应用程序中无法使用垃圾回收器,并且苹果公司建议不要使用autorelease方法和会返回自动释放对象的一些便利方法。ios设备上有ARC,自动引用计数。
之后需要仔细学习ARC等相关知识。
对象初始化
与大部分语言不同,OC中将一个新对象的创建分为了两步。第一步是分配内存空间,第二步是对这一块内存空间进行初始化。
[[类名 alloc] init]
这里要注意一点:初始化返回的对象可能与分配的对象不同。因为有时init函数会检查其接受的参数,并且决定返回真正的类的对象。
编写初始化方法
if(self = [super init]){
//write code...
}
self = [super init];
if (nil != self){
//write code...
}