Objective-C 入门教程
分类 编程技术
Objective-C 是一种简单的计算机语言,设计为可以支持真正的面向对象编程。
Objective-C 通过提供类定义,方法以及属性的语法,还有其他可以提高类的动态扩展能力的结构等,扩展了标准的 ANSI C 语言。类的语法和设计主要是基于 Smalltalk,最早的面向对象编程语言之一。
如果你以前使用过其他面向对象编程语言,那么下面的信息可以帮助你学习 Objective-C 的基本语法。许多传统的面向对象概念,例如封装,继承以及多态,在 Objective-C 中都有所体现。这里有一些重要的不同,但是这些不同在这文章会表现出来,而且如果你需要还有更多详细的信息存在。
如果你从来没有使用任何编程语言编过程序,那么你至少需要在开始之前,对相关概念进行一些基础的了解。对象的使用和对象对象架构是 iPhone 程序设计的基础,理解他们如何交互对创建你的程序非常重要。想了解面向对象概念的,请参看使用 Objective-C 进行面向对象编程。
Objective-C:C的超集
Objective-Objective-C是C语言的严格超集--任何C语言程序不经修改就可以直接通过Objective-C编译器,在Objective-C中使用C语言代码也是完全合法的。Objective-C被描述为盖在C语言上的薄薄一层,因为Objective-C的原意就是在C语言主体上加入面向对象的特性。
Objective-C代码的文件扩展名
扩展名 内容类型
.h 头文件。头文件包含类,类型,函数和常数的声明。
.m 源代码文件。这是典型的源代码文件扩展名,可以包含 Objective-C 和 C 代码。
.mm 源代码文件。带有这种扩展名的源代码文件,除了可以包含Objective-C和C代码以外还可以包含C++代码。仅在你的Objective-C代码中确实需要使用C++类或者特性的时候才用这种扩展名。
当你需要在源代码中包含头文件的时候,你可以使用标准的 #include 编译选项,但是 Objective-C 提供了更好的方法。#import 选项和 #include 选项完全相同,只是它可以确保相同的文件只会被包含一次。Objective-C 的例子和文档都倾向于使用 #import,你的代码也应该是这样的。
语法
Objective-C的面向对象语法源于Smalltalk消息传递风格。所有其他非面向对象的语法,包括变量类型,预处理器(preprocessing),流程控制,函数声明与调用皆与C语言完全一致。但有些C语言语法合法代码在objective-c中表达的意思不一定相同,比如某些布尔表达式,在C语言中返回值为true,但在Objective-C若与yes直接相比较,函数将会出错,因为在Objective-C中yes的值只表示为1。
第一个 Objective-C 程序,基于Xcode 4.3.1:
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
@autoreleasepool {
NSLog(@"Hello World!");
}
return 0;
}
消息传递
Objective-C最大的特色是承自Smalltalk的消息传递模型(message passing),此机制与今日C++式之主流风格差异甚大。Objective-C里,与其说对象互相调用方法,不如说对象之间互相传递消息更为精确。此二种风格的主要差异在于调用方法/消息传递这个动作。C++里类别与方法的关系严格清楚,一个方法必定属于一个类别,而且在编译时(compile time)就已经紧密绑定,不可能调用一个不存在类别里的方法。但在Objective-C,类别与消息的关系比较松散,调用方法视为对对象发送消息,所有方法都被视为对消息的回应。所有消息处理直到运行时(runtime)才会动态决定,并交由类别自行决定如何处理收到的消息。也就是说,一个类别不保证一定会回应收到的消息,如果类别收到了一个无法处理的消息,程序只会抛出异常,不会出错或崩溃。
C++里,送一个消息给对象(或者说调用一个方法)的语法如下:
obj.method(argument);
Objective-C则写成:
[obj method: argument];
此二者并不仅仅是语法上的差异,还有基本行为上的不同。
这里以一个汽车类(car class)的简单例子来解释Objective-C的消息传递特性:
[car fly];
典型的C++意义解读是"调用car类别的fly方法"。若car类别里头没有定义fly方法,那编译肯定不会通过。但是Objective-C里,我们应当解读为"发提交一个fly的消息给car对象",fly是消息,而car是消息的接收者。car收到消息后会决定如何回应这个消息,若car类别内定义有fly方法就运行方法内之代码,若car内不存在fly方法,则程序依旧可以通过编译,运行期则抛出异常。
此二种风格各有优劣。C++强制要求所有的方法都必须有对应的动作,且编译期绑定使得函数调用非常快速。缺点是仅能借由virtual关键字提供有限的动态绑定能力。Objective-C天生即具备鸭子类型之动态绑定能力,因为运行期才处理消息,允许发送未知消息给对象。可以送消息给整个对象集合而不需要一一检查每个对象的类型,也具备消息转送机制。同时空对象nil接受消息后默认为不做事,所以送消息给nil也不用担心程序崩溃。
字符串
作为C语言的超集,Objective-C 支持 C 语言字符串方面的约定。也就是说,单个字符被单引号包括,字符串被双引号包括。然而,大多数Objective-C通常不使用C语言风格的字符串。反之,大多数框架把字符串传递给NSString对象。NSString类提供了字符串的类包装,包含了所有你期望的优点,包括对保存任意长度字符串的内建内存管理机制,支持Unicode,printf风格的格式化工具,等等。因为这种字符串使用的非常频繁,Objective-C提供了一个助记符可以方便地从常量值创建NSString对象。要使用这个助记符,你需要做的全部事情,是在普通的双引号字符串前放置一个@符号,如下面的例子所示:
NSString* myString = @"My String\n";
NSString* anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"];
// 从一个C语言字符串创建Objective-C字符串
NSString* fromCString = [NSString stringWithCString:"A C string"
encoding:NSASCIIStringEncoding];
类
如同所有其他的面向对象语言,类是 Objective-C 用来封装数据,以及操作数据的行为的基础结构。对象就是类的运行期间实例,它包含了类声明的实例变量自己的内存拷贝,以及类成员的指针。Objective-C 的类规格说明包含了两个部分:定义(interface)与实现(implementation)。定义(interface)部分包含了类声明和实例变量的定义,以及类相关的方法。实现(implementation)部分包含了类方法的实际代码。
下图展现了声明一个叫做 MyClass 的类的语法,这个类继承自 NSObject 基础类。类声明总是由 @interface 编译选项开始,由 @end 编译选项结束。类名之后的(用冒号分隔的)是父类的名字。类的实例(或者成员)变量声明在被大括号包含的代码块中。实例变量块后面就是类声明的方法的列表。每个实例变量和方法声明都以分号结尾。
类的定义文件遵循C语言之惯例以.h为后缀,实现文件以.m为后缀。
类声明图
Interface
定义部分,清楚定义了类的名称、数据成员和方法。 以关键字@interface作为开始,@end作为结束。
@interface MyObject : NSObject {
int memberVar1; // 实体变量
id memberVar2;
}
+(return_type) class_method; // 类方法
-(return_type) instance_method1; // 实例方法
-(return_type) instance_method2: (int) p1;
-(return_type) instance_