您的位置:首页 > 移动开发 > Objective-C

Objective-C 学习笔记(1)——类与对象

2016-04-28 14:56 507 查看

一、Objective-C与C++的区别

Objective-C是一门面向对象的编程语言:它可以对类和对象进行管理;像在C++中一样,把头文件和实现文件分开写是非常有用的。OC使用.h作为头文件的后缀,使用.m作为实现文件的后缀。并且在OC中,使用 #import 包含头文件,而不是 #include。事实上,在c语言或者C++语言中,为了防止头文件被重复包含,需要使用头文件预处理防止头文件的重复包含。#import本身就有防止头文件被重复包含的功能。

二、类的定义

接口部分(.h文件)

@interface className:parentClass <protocol,…>
{
//instanceVariable Declarations
//实例变量的声明(相当于c++数据成员)
}
//method declarations
//方法的声明(相当于c++成员函数)
@end


ObjC定义了一个根类:NSObject。每一个新建的ObjC类都应该为NSObject的派生类。NSObject为运行时系统提供了大量的方法。

方法声明

mType (returnType) name1:(type1)param1 name2:(type2)param2...
//方法类型(返回值类型) 方法名1:(参数1类型)参数名 方法名2:(参数2类型)参数2名称..


方法分为两种:类方法和实例方法 即方法中的方法类型mType分为两种:分别用 “+” 和 “-” 标识。

• 如果类型为 +,则表示方法类方法(相当于c++中的静态成员函数)

• 如果类型为 - ,则表示方法为实例方法(相当于c++中的非静态成员函数)

三、类的实现

实现部分(.h文件)

@implementation className//类代码实现的开始
Synthesized Property//@synthesize 指示符来为类的属性生成setter和getter函数的
methodDefinition//方法的实现
methodDefinition
…
@end//类代码编写的结束


OC中方法(函数)的规则:

所有的方法在 @interface…@end 部分声明,在 @implementation…@end 部分实现。如果一个或多个协议在interface部分列出,则协议中的相的方法可以在该类中实现。

方法实现

mType (returnType) name1:(type1)param1 name2:(type2)param2...
{
variableDeclarations//局部变量声明
programStatements//程序执行语句
…
return expression;//返回一个定义的类型值
}


OC中方法实现(函数)的规则:

方法实现时,需要注意的是该方法原型必须和它在interface部分的声明保持一致;

实例方法可以通过名字引用本类或者本类中继承过来的实例变量,但是在类方法中,不可以引用实例变量;

在一个方法中,可以使用标识符 self 用作当前对象的引用,来调用当前对象的方法。类似于C++中的 this 指针。

四、消息机制

OC消息机制

消息机制:系统给对象发送消息,对象接受消息的一种方式。C++ 中函数的访问叫做对象调用函数;OC 中叫做向对象发送消息。对象收到消息做出响应(respond),接收消息的对象称为receiver,发送的消息称为selector 。

• +方法:称为类方法(大致相当于C++中的静态成员函数)
[类名 方法名];
eg. +(void)allNum;
[Circle allNum];
• -方法:称为实例方法(C++中的非静态成员函数)
[对象名 方法名];
eg. -(void)print;
Circle circle;
[circle print];


五、方法重载

在ObjC中方法的重载和C++中的重载不是一个形式;

如果当我们使用重载时必须要注意,C++重载和OC的重载有不同的特性。前者是基于参数的类型,而后者是基于参数的标签。但是OC中没有严格意义上的方法重载。

OC里标签也可以匿名(即标签名称可以省略不写);

六、属性声明

自动生成get set 方法

所用关键字:@property及@synthesize,两者需要配对使用。

具体如下:

• @property type name; (.h文件)告诉编译器:指定实例变量需要生成set()或get()方法

• @synthesize property_1,property_2, …;(.m文件)通知编译器自动生成set()或get()方法

属性设置会使编译器自动生成set/get方法,默认支持多线程。

nonatomic:该方法不需要多线程保护,节省开销。

调用get函数的两种方式

•方式1:对象名.实例变量;
receiver.property
•方式2:[对象名 实例变量名];
[receiver property];


调用set函数的两种方式

•方式1:对象名.实例变量 = 表达式;
receiver.property = expression;
•方式2:[对象名 属性设置函数 : 实例变量名];
[receiver setProperty: expression];
set后跟的实例变量名,其默认首字母要大写


属性声明的修饰类型

@property (属性参数1,属性参数2,...)类型 名字;
代码:
@property (attributes) type name;


其中参数主要分为4类:
•  **数据读写访问属性**:readwrite(默认为读写)/readonly(只有get方法)
•  **内存设置属性**:assign (default), retain or copy
•  **多线程原子性属性**:atomic(default)/nonatomic(防止线程安全:非原子化操作,该方法不需要多线程保护,节省开销,提高程序性能)
•  **自定义设置访问方法名称属性**:getter=..., setter=... (用于改变默认名称)
参数意义:
•  **readwrite**:产生setter/getter方法;
•  **readonly**:只产生简单的getter方法,没有setter方法;
•  **assign**:默认类型,setter方法中适用于基本数据类型的实例变量直接赋值,而不进行引用计数加1操作;
•  **retain**:setter方法中会对实例变量旧空间释放(release),使得新旧两个指针变
量指向同一个对象(新对象),再进行retain操作,新空间引用计数再次加1;
•  **copy**:setter方法中会对实例变量旧空间释放(release),再对新对象进行copy
操作,赋值给旧对象(两个指针变量分别指向各自的对象,互不影响);
•  **atomic**:支持多线程,如果使用多线程,有时会出现两个线程相互等待对方导致“死锁”,使用atomic会防止出现此情况,但是会消耗指定的资源;
•  **nonatomic**:禁止多线程,提高性能;
•  **实例变量起别名**:在类外对类变量访问起保护作用(封装性);
•  **getter=访问方法名**:用户自定义访问变量的方法名;
•  **setter=设置方法名**:用户自定义设置变量的方法名;


七、类的组合

组合的概念

在ObjC中,你可以使用像C++中的类与类的关系来实现代码的复用,并提高程序的编写速率,即OC中类的组合关系。

假设有一个圆,该圆由一个中心坐标点(x,y)和半径radius组合而成。你可以把这个点的(x,y)坐标单独用一个对象保存。或许你可以意识到,在开发的图形应用程序中,总会与许多坐标打交道,所以最好先定义一个点类表示这一类事物,取名为:XYPoint。然后再定义一个圆类取名为:Circle。二者关系如下:

Circle = XYPoint + radius;

即圆类由点类组合而成(这是一种 “has-a” 的关系)

• 先定义XYPoint类的接口

• 再定义Circle类的接口

/*** XYPoint.h ***/
#import <Foundation/Foundation.h>
@interface XYPoint : NSObject
{
intx;
inty;
}
@property int x, y;
-(void) setX: (int) xVal andY: (int) yVal;
@end

/*** XYPoint.m ***/
#import "XYPoint.h"
@implementation XYPoint
@synthesize x, y;
-(void) setX: (int) xVal andY: (int) yVal
{
x = xVal;
y = yVal;
}
@end


/*** Circle.h ***/
@interface Circle : NSObject
{
int radius;
XYPoint *origin;
}
@property int radius;
@property XYPoint *origin;

-(void)setOrigin:(XYPoint *) pt;
-(XYPoint *) origin;
-(int) area;
-(int) perimeter;

@end

/*** Circle.m ***/
@implementation Circle
@synthesize radius;
@synthesize origin;

-(void) setOrigin: (XYPoint *) pt //function name must be this
{
origin = pt;//形参pt为实例对象origin赋值
}
-(XYPoint *) origin//to use .origin, this func must provide
{
return origin;//返回实例变量
}
-(int) area
{
return radius*radius*3.14;
}
-(int) perimeter
{
return radius*3.14*2;
}
@end


为避免数据混乱和内存泄露的问题,对setOrigin函数做以下修改:

/*** Circle.m ***/
-(void) setOrigin: (XYPoint *) pt {
if (origin){//如果原始对象存在
[origin release];//释放旧对象
}
origin = [[XYPoint alloc] init]; //开辟新空间
[origin setX: pt.x andY: pt.y];
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: