Objective-C类和对象 – Objective-C开发教程

上一章Objective-C开发教程请查看:Objective-C命令行参数?
Objective-C是C语言的超集或一个扩展,这意味着你可以在OC中进行C语言风格的编程,同时OC对C的扩展是为了实现OOP面向对象编程。OOP编程是以类class为中心,类通常是对数据成员和操作算法的封装,这个对于C语言也是可以做到的,但是OC的风格相对更方便而已。
OOP编程仅仅有数据封装是不够的,加入之后你对某个算法有不同的实现,究竟是删了/注释这份代码还是另外重新实现更好,当然后者更好了,这就是多态的功能。这章我们先讨论OC的类和对象的使用,接着的章节我们会讨论到类的继承以及多态的使用。
Objective-C类和对象的基本特点

  • OC使用@interface声明一个类,使用@implementation实现一个类。
  • 所有的数据和操作算法都可以封装在一个类中。
  • OC中的对象用于接收消息,获取属性和调用方法都相当于向对象发送消息。
  • 实例对象包含所有实例变量。
  • 实例对象和实例变量的使用都有对应的范围限制。
  • 类隐藏一个对象的实现。
  • 属性用于提供类的实例对象在其它地方访问。
定义类定义一个类就是定义一个新的数据类型,但是定义类不占用任何内存,它告诉编译器这个类有某些属性和操作方法,只有实例化一个类型的对象,这个对象会占用内存空间,也就是说,定义类和和之前说的声明变量和函数是类型的。
定义一个类使用@interface开始,以@end结束,中间是类的声明部分,主要是属性声明和方法声明。OC中定义任何一个类都要显式使用(:)继承一个指定的基类/父类,如果没有目标类要继承,则默认使用NSObject,这个类是所有类的超类,这个类提供所有类的一些基本操作,例如申请内存alloc以及初始化init。
下面定义一个Box类:
@interface Box:NSObject { // 实例变量, 私有属性, 只能在类中访问 double length; double breadth; } @property(nonatomic, readwrite) double height; // 属性,可以使用点操作符@end

分配内存和初始化OC对象一个类提供对象的基本框架,对象是一个实例,根据类的形式进行创建。一般来说,NSObject基类提供alloc方法来给对象分配内存(类似C语言的malloc),init方法用来初始化对象(在没有使用其它初始化函数的时候,这两步等价于使用一个new),如下例子:
Box *box1 = [[Box alloc]init]; Box *box2 = [Box new];

访问数据成员可以使用直接成员访问操作符(.)访问类的对象属性。让我们用下面的例子来说明一下:
#import < Foundation/Foundation.h>@interface Box:NSObject { double length; // 长度 double breadth; // 宽度 double height; // 高度 }@property(nonatomic, readwrite) double height; // 属性 -(double) volume; @end@implementation Box@synthesize height; -(id)init { self = [super init]; // 调用父类初始化方法, self为当前对象指针 length = 1.0; breadth = 1.0; return self; }-(double) volume { return length*breadth*height; }@endint main() { Box *box1 = [[Box alloc]init]; Box *box2 = [[Box alloc]init]; double volume = 0.0; box1.height = 5.0; box2.height = 10.0; volume = [box1 volume]; NSLog(@"Volume of Box1 : %f", volume); volume = [box2 volume]; NSLog(@"Volume of Box2 : %f", volume); return 0; }

OC中的属性在Objective-C中引入了属性,以确保类的实例变量可以在类之外访问。
各个部分的属性声明如下:
  • 属性以@property开头,它是一个关键字
  • 然后是访问说明符,可用的说明符有:nonatomic或atomic、readwrite或readonly和strong、unsafe_unretain或weak。这取决于变量的类型。对于任何指针类型,我们都可以使用strong、unsafe_unretain或weak。类似地,对于其他类型,我们可以使用readwrite或readonly。
  • 然后是变量的数据类型。
  • 最后,属性名以分号结束。
  • 我们可以在实现类中添加synthesize语句,但是在最新的XCode中,合成部分由XCode负责,不需要包含synthesize语句。
只有使用属性我们才能访问类的实例变量,实际上,在内部为属性创建了getter和setter方法。
例如,假设我们有一个属性@property (nonatomic, readonly) BOOL isDone,在底层,创建了如下所示的setter和getter。
-(void)setIsDone(BOOL)isDone; -(BOOL)isDone;

属性声明解释第一个中是实例属性,只在@interface{}中进行声明,称为私有实例成员属性,只能在类内部使用,如果需要在外部使用可以使用一个方法实现间接访问,如果最好使用第二种属性的声明方式。
第二种是OC提供某些特殊处理的成员属性,声明语法为:
@property(参数说明符)类型 变量名; 例如: @property(nonatomic, readwrite)int age;

其中参数说明符主要分为三类:
  • 1、储存特性:readwrite/readonly(读写/只读),readwrite产生setter/getter方法,readonly只产生getter方法,默认为readwrite。
  • 2、内出特性:assign/retain/copy/strong/weak(赋值/保留/复制/强/弱),assign是默认的方式,setter方法直接赋值。
  • retain是浅拷贝,复制对象地址,让目标对象和源对象同指向一个内存空间。
  • copy是深拷贝,从源对象复制多一份同样的内存空间。
  • strong,类似retain,多个指针指向同一个内存时,只要有一个指向该内存,内存就不会被释放。
  • weak,类似assign,多个指针指向同一个内存时,只要有一个不指向该内存,内存就会被释放。
  • 3、原子性:nonatomic/atomic(非原子性/原子性),默认为atomic。nonatomic禁止多线程,提高性能。atomic给getter和setter加锁,使多个线程能准确同步。
  • 4、可null性:默认unll_unspecified未指定,nullable对象可为空,nonnull对象不可为空,null_resettable,调用setter可传入nil,getter为空。
另外要注意的地方,使用默认值atomic有额外的性能耗费,若无必要,请使用nonatomic效率更高。
对应属性生成的getter和setter方法后,其属性名变成_name,如果要重写相关方法需要使用加下划线的属性。在类中使用属性也可以直接使用_name更方便,而使用self.访问属性相对耗时。
非ARC时assign是默认值,ARC下strong是默认值,可以忽略掉retain,因为retain和strong类似,这样我们只需关注strong、weak、assign和copy。
strong和retain都是指针拷贝,还有人在使用内存就不会被释放,对象引用计数加1。强制置为nil可以释放。
weak也是指针拷贝,对象引用计数不增加,但是只要有一个人不用了就被释放,不手动设置,自动销毁。
assign一般只用于修饰基本数据类型。
特别地,copy用于如NSString、NSArray、NSDictionary等,而NSMutableArray、NSMutablestring、NSMutableDictionary声明类型用strong。
【Objective-C类和对象 – Objective-C开发教程】如果所有属性都不为null,可以使用下面两个宏:
NS_ASSUME_NONNULL_BEGIN @interface App : NSObject@end NS_ASSUME_NONNULL_END

    推荐阅读