Objective C 中的面向对象


Objective C 中的面向对象

内容概述

  • 对象、类简介
  • Objective C中类的定义
  • 实例变量、实例方法、类方法
  • 类的实例化及方法的调用
  • 类的初始化
  • 属性

1.1 对象和类的简介

任何面向对象的计算机语言都离不开讨论类和对象的感念,这也是初学者学习面向对象语言的一个屏障。有了对基本感念的理解,才能深入面向对象的精髓。

类是同一类型的抽象,例如:房子、汽车。有句话这样讲"物以类聚",类是一个静态概念,是一种自定义变量类型。类一般由属性、初始化方法和普通方法组成。

而对象是类的一个具体实现,例如我家的房子和我家的汽车就是房子和汽车类的对象。类和对象的关系是,类是对象的一个模板,而对象是类的一个实例。

1.2 Objective C中类的定义

Objective C中类的定义分为两个部分,声明部分和实现部分,并且一般分为两个文件,分别是.h文件和.m文件。下面是一个Person类的定义。

Person.h

#import \<Foundation/Foundation.h\>

@interface Person : NSObject

@end

Person.m

#import "Person.h"

@implementation Person

@end

在上述代码的Person.h头文件中 #import \<Foundation/Foundation.h\>是导入头文件语句,因为这里使用的NSObject类在该头文件中,关键字@interface和@end 表示声明的开始和结尾,中间可以定义属性和方法。Person是类名称,:表示继承关系,这里继承NSObject。

Person.m 实现文件中,@implementation和@end是实现文件的开始和结尾,中间部分是方法的实现。

下面代码定义了一个Person类,有两个实例变量和一个方法。

#import \&lt;Foundation/Foundation.h\&gt;

@interface Person : NSObject

{

    int age;

    NSString \*name;

}

-(void)printMsg;

@end

#import &quot;Person.h&quot;

@implementation Person

-(void)printMsg{

    NSLog(@&quot;%@,%d&quot;,name,age);

}

@end

1.3 实例变量、实例方法、类方法

在类中定义的变量可以分为实例变量、类变量和局部变量。每个对象的实例变量都是不相同的,例如,我的姓名和你的姓名是不同。类变量是所有对象共享的。局部变量在方法中声明或者是函数的参数。

在类中定义的方法分为类方法和实例方法,类方法以"+"号开始,实例方法以"-"号打头。类方法无需实例化,通过类名称可以直接调用。实例方法必须实例化类才能调用。

下面代码定义了两个实例变量,并定义一个实例方法一个类方法。

Employee.h头文件

#import \&lt;Foundation/Foundation.h\&gt;

@interface Employee : NSObject

{

    // 实例变量员工编号

    int eid;

    // 实例变量员工姓名

    NSString \*name;

}

// 实例方法

-(void)instanceMethod;

// 类方法

+(void)classMethod;

@end

Employee.m实现文件

#import &quot;Employee.h&quot;

@implementation Employee

-(void)instanceMethod{

    NSLog(@&quot;This is a instance method...&quot;);

}

+(void)classMethod{

    NSLog(@&quot;This is a class method...&quot;);

}

@end

测试文件main.m

#import \&lt;Foundation/Foundation.h\&gt;

#import &quot;Employee.h&quot;

int main(int argc, const char \* argv[])

{

    @autoreleasepool {

        Employee \*emp = [[Employee alloc]init];

        // 必须实例化才能调用

        [emp instanceMethod];

        // 通过类名称就可以调用

        [Employee classMethod];

    }

    return 0;

}

1.4 类的实例化及方法的调用

类的实例化是由类创建对象的过程,由一个类可以创建若干个对象。实例化一个类可以使用NSObject的new关键字也可以使用NSObject的alloc和init,new方法实例化对象几乎很少用到,alloc表示分配内存区域,而init表示初始化,例如,给实例变量赋值。

关于Objective C中方法的调用和其它编程语言有所不同,Objective C中方法的调用使用[]语法格式。下面我们定义一个Student类,实例化两个学生,并调用他们的赋值和取值方法。

Student.h头文件声明

#import \&lt;Foundation/Foundation.h\&gt;

@interface Student : NSObject

{

    // 实例变量,学生编号

    int sid;

    // 实例变量,学生姓名

    NSString \*name;

}

// 赋值方法,传递int类型的参数mySid

-(void)setSid:(int)mySid;

// 取值方法,返回int类型的学生编号

-(int)sid;

// 赋值方法,传递NSString类型的参数myName

-(void)setName:(NSString\*)myName;

// 取值方法,返回NSString类型的学生姓名

-(NSString\*)name;

@end

Student.m实现文件

#import &quot;Student.h&quot;

@implementation Student

// 实现姓名的赋值方法

-(void)setName:(NSString \*)myName{

    name = myName;

}

// 实现姓名取值方法

-(NSString\*)name{

    return name;

}

// 实现sid的赋值方法

-(void)setSid:(int)mySid{

    sid = mySid;

}

// 实现sid的取值方法

-(int)sid{

    return sid;

}

@end

方法的调用

// 实例化第一个学生

Student \*s1 = [[Student alloc]init];

// 调用赋值方法赋值

[s1 setSid:1];

[s1 setName:@&quot;tom&quot;];

// 调用取值方法取值

int sid1 = [s1 sid];

NSString \*name1 = [s1 name];

// 输出sid和name

NSLog(@&quot;%d,%@&quot;,sid1,name1);

// 实例化第二个学生

Student \*s2 = [[Student alloc]init];

[s2 setSid:2];

[s2 setName:@&quot;kite&quot;];

NSLog(@&quot;%d,%@&quot;,[s2 sid],[s2 name]);

多参数方法的定义和调用,和无参数和单参数方法的定义和调用有所不同。下面看一个例子。

// 多参数方法定义

-(void)setSid:(int)mySid andName:(NSString\*)myName;

这里setSid和andName组合形成方法名称,而mySid和myName是参数,:将方法名称和参数名称分隔开来,空格分隔多个不同参数。调用方法如下:

// 多参数方法的调用

Student \*s3 = [[Student alloc]init];

[s3 setSid:3 andName:@&quot;rose&quot;];

1.5 类的初始化

像其他面向对象语言,例如,c++、java都有构造方法,该方法一般在实例化对象时调用,作业是初始化实例化变量。Objective C也有对应的概念,那就是初始化init方法。

init方法是NSObject对象的方法,一般我们自己定义的类,都要通过覆盖该方法来实现对实例变量的初始化。下面我们定义一个客户类Customer,该类有三个实例变量分别是cid、name和email。我们通过覆盖init方法初始化这几个变量。

Customer.h代码

#import \&lt;Foundation/Foundation.h\&gt;

@interface Customer : NSObject

{

    // 实例变量cid、name和email

    int cid;

    NSString \*name;

    NSString \*email;

}

// 打印客户信息

-(void)printMsg;

@end

Customer.m 代码

@implementation Customer

// 打印信息

-(void)printMsg{

    NSLog(@&quot;%d,%@,%@&quot;,cid,name,email);

}

// 初始化方法

-(id)init{

    // 调用父类的初始化方法

    self = [super init];

    // 如果父类初始化成功

    if (self) {

        // 初始化子类

        cid = 1;

        name = @&quot;tom&quot;;

        email = @&quot;tom@gmail.com&quot;;

    }

    return self;

}

@end

这里我们覆盖init方法,该方法返回id类型。我们先调用父类的init方法,如果父类初始化成功,再来初始化子类。并且返回self(self代表当前对象)。

我们也可以定义带参数的初始化方法,在实例化时动态初始化对象。

// 多参数初始化方法的定义

-(id)initWithCid:(int)myCid andName:(NSString\*)myName andEmail:(NSString\*)myEmail;

// 多参数初始化方法的实现

-(id)initWithCid:(int)myCid andName:(NSString \*)myName andEmail:(NSString \*)myEmail{

    self = [super init];

    if (self) {

        cid = myCid;

        name = myName;

        email = myEmail;

    }

    return self;

}

初始化方法的调用

 // 多参数初始化方法

 Customer \*c = [[Customer alloc]initWithCid:1 andName:@&quot;tom&quot; andEmail:@&quot;tom@gmail.com&quot;];

 [c printMsg];

1.5 属性

当我们在类中定义了实例变量之后,我们经常需要定义针对这些实例变量的赋值和取值方法。这些方法的定义都是一致的,而且枯燥乏味。所有Objective C定义了@property标记来动态生产赋值和取值方法。而且可以使用@synthesize标记来生产赋值和取值方法的实现。下面代码我们定义了一个Teacher类,并定义了三个实例变量和三个属性,并通过@synthesize生产赋值和取值方法实现。

@interface Teacher : NSObject

{

    // 实例变量

    int tid;

    NSString \*name;

    int age;

}

// 属性,生产赋值和取值方法

@property(nonatomic)int tid;

@property(nonatomic,strong)NSString \*name;

@property(nonatomic)int age;

@end

#import &quot;Teacher.h&quot;

@implementation Teacher

// 生产赋值和取值方法

@synthesize tid;

@synthesize name;

@synthesize age;

@end

我们看到在属性声明的()中有nonatomic和stong等关键字。这里nonatomic表示线程非安全的,strong表示强引用(这和内存管理有关,后续章节将详细讲述)。另外,括号中可以出现的关键字和表示的含义如下:

assign:直接赋值

atomic:线程安全的

copy:赋值时拷贝对象

readonly:属性是只读的(没有set方法)

readwrite:读写的(默认)

retain:保留引用,引用计数+1

strong:强引用同retain

weak:弱引用,应用在循环引用中

unsafe_unretained:非安全引用

另外,我们可以通过点操作法来访问属性,例如:

Teacher \*t = [[Teacher alloc]init];

t.tid = 1;

t.name = @&quot;kite&quot;;

t.age = 30;

NSLog(@&quot;%d,%@,%d&quot;,t.tid,t.name,t.age);