自学OC的第一天

259 阅读7分钟

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就能避免这种情况。那么在实际开发中:

  1. 在.h文件中使用@class来对于某一个类进行声明。
  2. 在.m文件中用#import来将需要的类进行引入。

在java中,解决循环依赖是通过jvm实现的,jvm会将相应的.class文件加载到jvm中,并且通过双亲委派等机制完成类的加载初始化等操作。

导入和继承

如果一个类继承自其他类而非通过指针指向其他类,那么就不能通过@class指令来对其他类进行声明。

FoundationKit介绍

一些有用的数据类型

  1. NSRange

    相关事物的范围。

  2. CGPoint和CGSize

    表示点的坐标和长度和宽度。

  3. NSString

    表示OC中的字符串。(可以通过stringWithFormat函数创建NSString)

    其函数原型为:

    +(id)stringWithFormat:(NSString *)format,...;
    

    PS. “+”表示这是个静态函数。

  4. NSArray

    • 只能存储OC的对象,不能存储原始C语言数据类型。
    • 不能在其中存放null(nil)
    NSArray *array = [NSArray arrayWithObjects:@"one",@"two",@"three",nil];	//以nil作为结束标志,这也是不能存放nil的原因之一。
    
    NSArray *array = @[@"one",@"two",@"three"];
    
  5. NSMutableArray

    此为可变数组。用法更类似java中的arrayList。

  6. NSEnumerator

    数组的枚举器,但是要注意,NSArray是一个Fail-Fast的数据集合。

  7. 快速枚举

    类似foreach语法

    for(NSString *string in array){
    	NSLog(@"I found %@.",string)
    }
    
  8. 代码块

  9. NSDictionary

    在给定的关键词下存储一个数值。不能存放nil。

    类似Map,但是其中的元素不可变。

  10. NSMutableDictionary

    可变的字典。

  11. NSNumber

  12. NSValue

  13. 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...
}