本人翻译的Apple Dev Center的技术资料并稍作修改。
转载请注明出处:http://blog.csdn.net/zhyzh2046/
学习Objective-C:初级读本
Objective-C是一种简单的计算机语言,支持复杂南通的面向对象编程。Objective-C从标准的ANSI C语言扩展而来,并提供了定义类、方法和属性的语法,还有其它结构来促进类的动态扩展。类的语法和设计把部分基于第一种面向对象的编程语言Smalltalk。
如果你有使用面向对象语言的经验,接下来的信息会帮你学习到Objective-C基本的语法。许多传统的面向对象概念,如封装、继承和多态,都会在Objective-C中出现。但是会存在一些重要的不同之处,不过这篇文章会讲解这些不同,而且还可以查到更加详细的信息。
如果你从来没有使用过面向对象语言,在开始之前,至少需要基本理解相关的概念。对象和面向对象结构的使用是设计iPhone程序的基础,而且理解它们是怎样交互的是创建程序的必要条件。
使用
Objective-C
进行面向对象编程中介绍了面向对象概念概述。
要了解关于Objective-C更加详细的信息和语法,请查阅Objective-C程序设计。
Objective-C:C语言的超集
Objective-C是C语言的ANSI版本的超集,支持相同的基础语法。与C语言相同,Objective-C也会定义头文件和源文件,将公共的声明和实现分离。Objective-C头文件使用的文件扩展名列在表1中。
表1 Objective-C源代码的文件扩展名
扩展名 |
代码类型 |
.h |
头文件。头文件中包含类、类型、函数和常量的声明。 |
.m |
源文件。这是源文件的一种典型扩展,可以包含C代码和Objective-C代码。 |
.mm |
源文件。这种源文件除了可以包含C代码和Objective-C代码之外,还可以包含C++代码。这种扩展名只能用于你实际引用了C++的类,或者引用了Objective-C的功能。 |
当需要在头文件包含头文件时,可以使用标准的#include预编译指令,但是Objective-C提供了更好的方法。#import指令和#include指令是一样的,除了它能保证相同的文件永远不会被引用多次。Objective-C的示例和文档都建议使用#import,你自己的代码也应该如此。
Strings
作为C的超集,Objective-C在指定字符串时,具有和C一样的约定。换句话说,单个字符使用单引号,字符串会使用双引号包围。但是,大多数Objective-C框架经常不使用C样式的字符串。取而代之,大多数框架将字符串封装在一个NSString对象中。
NSString类是字符串的对象载体,它具有希望的所有优点,包括为处理任意长度的字符串内置的内存管理、支持Unicode、Printf风格的格式化优点等等。但由于一些字符串经常使用,Objective-C提供了一个速记符号从常量创建NSString对象。使用这用速记,你所要做的仅仅是在一个正常的双引号包含的字符串之前加上一个@符号,如下示例:
NSString
*
myString
=
@"
My String
"
;
NSString
*
anotherString
=
[NSString stringWithFormat:
@"
%d %s
"
,
1
,
@"
String
"
];
//
Create an Objective-C string from a C string
//
从C字符串创建Objective-C字符串
NSString
*
fromCString
=
[NSString stringWithCString:
"
A C string
"
encoding:NSASCIIStringEncoding];
Classes
类
正如大部分其它面向对象语言一样,Objective-C中的类是一个基本的结构体,封装了一些数据以及操作这些数据的动作。对象是类运行时的实例,包含类中声明的成员变量和类方法的指针在内存中的拷贝。
Objective-C中创建一个类需要截然不同的两个部分:接口和实现。接口部分包含类的声明,还会定义成员变量和与类相关联的方法。实现部分包含类方法的实际实现代码。图1显示了声明一个叫做MyClass的类的语法,它继承了NSObject基类。类声明会以@interface预编译指令开始,以@end指令结束。类名之后(有一个冒号分开)是父类的名称。类的成员变量在大括号包含的代码中声明({和})。在成员变量之后的代码块是类声明的方法列表。每个成员变量和方法的声明之后都要以分号结尾。
图1 类的声明
![iPhone开发系列文章(三)-Objective-C语言简介_第1张图片](http://img.e-com-net.com/image/info8/b71505a4682f44b9b4265364e17ca7de.jpg)
图2显示了上例中MyClass的实现。像类的声明一样,类的实现由两个预编译指令来指示-在这里是@implementation和@end。这些指令定义了范围信息,告诉编译器需要将附上的方法和相关的类联系起来。因此,方法的定义与接口中声明的要匹配,除了代码块的包含。
图2 类的实现
![iPhone开发系列文章(三)-Objective-C语言简介_第2张图片](http://img.e-com-net.com/image/info8/f1101285f3fc4b76b8901288f850318e.jpg)
注意:尽管上述例子中,类的声明部分只声明了一些方法,类是可以在这里声明属性的。关于属性的更多信息,请看“属性”一节。
当使用变量存储对象时,经常会使用指针类型。Objective-C中,强类型和弱类型变量都可以保存对象。强类型指针的变量在声明时必须包含类名。集合类经常使用弱类型指针,因为可能还不知道集合中对象的类型。如果你习惯于使用强类型的编程语言,你可能会认为弱类型变量的使用会产生问题,但是实际上,在使用Objective-C编程时,它会带来极大的便利,同时会带来更好的扩展性。
下面这个例子演示了MyClass类的强类型和弱类型变量的声明:
MyClass
*
myObject1;
//
强类型
id myObject2;
//
弱类型
Methods
方法
Objective-C
语言中的类可以声明两种方法:实例方法和类方法。实例方法的执行者必须是类的一个特定实例。换句话说,在调用实例方法之前,必须先创建一个类的实例,之后必须使用这个实例来调用实际的方法。相比之下,类方法不需要创建类的实例,后面会有详细的解释。
方法的声明由方法类型标识符、返回类型、一个或多个署名关键字和参数的名称、类型信息组成。图
3
中声明了一个
insertObject:atIndex:
的实例方法。方法声明的前面加上了一个减法符号(-),这说明这个方法是一个实例方法。方法的实际名称(insertObject:atIndex:)是所有署名关键字串联起来的,包括冒号字符。冒号说明参数的存在。如果方法没有参数,第一个(唯一的)署名关键之后可以忽略冒号。这个例子中,方法含有两个参数。
图3
声明方法的语法
当调用一个方法时,要通过"messaging”来通知相应的对象。这个例子中的消息就是方法名和这个方法所需的参数信息。发送到对象的所有消息是动态发送的,因此这有利于Objective-C的多态特征。换句话说,如果子类定义了与父类同名的方法,子类会第一个收到消息,然后可以选择是否要将这个消息转交给它的父类。
消息都是放在方括号
([
和
])
中。在方括号中,收消息的对象放在左边,消息
(
和任何消息需要的参数
)
放在右边。例如,发送
insertObject:atIndex:
消息给myArray对象,使用的语法如下:
[myArray insertObject:anObj atIndex:
0
];
为避免声明大量局部变量来存储临时数据,
Objective-C
支持嵌套消息。每一个嵌套消息的返回值都可以作为另一个消息的参数或者是目标。例如,上例中的任何变量都可以被替换成能得到值的消息。因此,如果有另外一个对象
myAppObject
,它的方法方法可以访问数组对象,并且有另外一个数组对象,可以将上面的例子写出如下样子:
[[myAppObject getArray] insertObject:[myAppObject getObjectToInsert] atIndex:
0
];
尽管前面的例子是向一个类的实例发送消息,还可以向类本身发送消息。当向类发送消息时,调用的方法必须定义成类方法而不是实例方法。可以这样认为:类方法同
C++
语言中类的静态成员方法有些相似(但又不是完全相似)。
类方法有代表性的用法有,作为工厂方法来创建类的一个新实例,或者用来访问与类相关的一些共享信息。类方法的定义语法与实例方法是完全一样的,只有一点不同。类方法使用加法符号(+),而不是减法符号作为方法的类型标识符。
下面的例子演示了类方法的使用,这里它作为类的工厂方法。在这里,arrayWithCapacity:方法是类NSMutableArray的类方法,他会申请并初始化一个新的类实例并返回它。
NSMutableArray
*
myArray
=
nil;
//
nil 本质上与NULL相同
//
创建新的数组并赋值给myArray变量
myArray
=
[NSMutableArray arrayWithCapacity:
0
];
Properties
属性
属性是一种便利符号,用来代替存取方法(accessor methods)。属性并不是在类的声明中创建一个新的成员变量。他们仅仅为定义用来访问已经存在的变量的方法指定的快捷方式。类可以使用属性标记来公开成员变量,而不是使用getter和setter方法。类还可以使用属性来公开“virtual”(虚)的成员变量—它是动态计算的一部分数据并且并不实际存储在成员变量中。
实际点说,属性的使用减少了你的冗余代码量。应为大部分存取方法用相似的方式实现,使用属性可以不必为每一个成员变量提供截然不同的
getter
和
setter
方法。相反,你可以使用属性的声明指定具体的动作,在编译的时,会根据声明合成实际的
getter
和
setter
方法。
因为属性的声明会创建实际的方法,可以和方法的声明一起定义在类的接口中。基本的定义使用
@property
预编译指令,后边是属性的类型信息和名称。可以使用定制选项配置属性,它定义了存取方法有怎样的行为。下面的例子显示了一些简单的类型声明:
@property BOOL flag;
@property (copy) NSString
*
nameObject;
//
赋值过程中拷贝对象
@property (
readonly
) UIView
*
rootView;
//
仅创建getter方法
属性的另一个好处是在代码中可以使用点语法来访问他们,如下演示:
myObject.flag
=
YES;
CGRect viewFrame
=
myObject.rootView.frame;
尽管上面的例子中的对象和属性的名字很做作,但是他们演示了属性的灵活性。点语法实际上屏蔽了相关一系列方法的调用。每个可读属性由同名的方法支持。每个可写属性由附加的方法
set
PropertyName
:
支持,在这里属性名称的第一个字母大写了。
(
这些方法是属性的实际实现,同时也是可以在没有成员变量支持的类中包含属性定义的原因。
)
不用属性去实现上面代码完成的功能,你需要编写如下代码:
[myObject setFlag:YES];
CGRect viewFrame
=
[[myObject rootView] frame];
关于在类中如何声明属性的更多信息,请查阅
Objective-C
程序设计中
”
属性
”
一节。
Protocols and Delegates
协议和代理
协议声明的方法可以被任何一个类实现。协议不是类本身。他们仅定义了其它对象有责任实现的接口。当在自己的类中实现协议的方法时,你的类就是遵守这个协议的。
iPhone OS
中,协议经常被用作实现代理对象。代理对象是一个能代表其它对象或与其它对象合作的一个对象。学习协议、代理和其它对象相互影响的最好方法就是从例子中学习。
UIApplication
类实现了应用程序所需的功能。不是强制继承UIApplication类来接收一个简单的应用程序当前状态的通知,而是UIApplication类调用赋值给代理对象的方法来分发这些通知。实现了UIApplicationDelegate协议方法的对象可以接收这些通知并提供合适的响应。
协议的声明类似于类接口的声明,有一点不同的是,协议没有父类,并且不能定义成员变量。下面的例子演示了只有一个方法的协议的声明:
@protocol MyProtocol
-
(
void
)myProtocolMethod;
@end
很多代理协议中,采用协议只是大概实现了协议中定义的方法。一些协议需要明确声明支持的协议,但是现在假设仅实现方法就足够了。但是,如果想将更多的只是应用到你的开发中,你应该多花些时间来学习协议和他们的使用方法,可以通过查阅
Objective-C
程序设计中的
”
协议
”
一节。