您的位置:华清远见教育科技集团 >> 新闻动态 >> iOS资料 >> iOS开发入门:Objective-C基础语法(一)  
 
iOS开发入门:Objective-C基础语法(一)
分享到:

Objective-C 并不是一门复杂的语言,经过一段时间的接触,你就能体会到它的优雅。Objective-C 语言实现了严格的面向对象编程,它扩展了标准 ANSI C 语言,增加了定义类和方法的语法,它还推行类和接口的动态扩展性,使任何类都能适配和采用。

Objective-C是C 语言的超集

既然是 C 语言的超集,Objective-C 支持所有 C 语言的基本语法。你可以继续按你的习惯书写代码,例如原始类型(intfloat 等)、结构、函数、指针,还有过程控制语句例如 if…elsefor 语句。你可以使用标准 C 语言库,比如 stdlib.hstdio.h 中声明的内容。

Objective-C 在 ANSI C 的基础上增加了如下内容:

·定义新类的语法规约
    ·类和实例方法的规约
    ·调用方法的语法(称为消息机制)
    ·声明属性并从中合成存取方法的语法
    ·静态和动态类型的规约
    ·块对象(Block)- 封装起来的代码片段,可以在任何时候被执行
    ·对基本语言的扩展,例如协议、范畴类等

如果现在还不明白这些 Objective-C 概念也不必担心,当你继续阅读后面的内容时就会学习这些概念。如果你是初次接触面向对象概念的开发者,可以先把对象想象成一个含有函数的结构,这个比喻不算太离谱,尤其对运行时的实现而言。

类和对象

和其他大部分面向对象编程语言一样,Objective-C 中的类也支持封装数据,以及定义可以在该数据上执行的动作。对象是运行时类的一个实例。在类里声明了的实例变量和方法,它的每个实例都在内存中拥有同样的实例变量,以及指向那些方法的指针。创建一个对象时,你需要经过两个步骤:内存分配(allocation)和初始化(initialization)。

Objective-C 中的类有自己的规范要求,必须包括两个不同的部分:接口(interface)和实现(implementation)。接口部分含有类的声明、实例变量和相关方法的声明。既然是作为 C 语言,通过分别定义头文件和源文件,你就可以将公有声明和具体的实现代码给分离开来。(你可以在实现文件里放一些声明代码,因为有些情况下,它们共同构成一个公用程序里的接口部分。)下表列出了这些文件的后缀以及区别:

后缀、源文件类型:

·.h – 头文件。头文件含有类、类型、函数和常量的声明。
    ·.m – 源文件。这个后缀的源文件可以同时包含 Objective-C 和 C 语言的代码。
    ·.mm – 源文件。这个后缀的源文件可以同时包含 C++、Objective-C 以及 C 语言的代码。只有在你的 Objective-C 代码中用到了 C++ 的类或者特性时才需要使用这个后缀。

如果需要在源代码中包含头文件,你需要使用 #import 命令,和 C 语言中的 #include 命令类似。两者的区别在于,#import 能够保证头文件只被包含一次。

图 1 中是一段的类声明的语法展示,声明了一个叫做 MyClass 的类,它继承于基本类(或根类):NSObject。(根类可以被所有的其他类直接或间接继承。)类声明开头是一条编译器指令 @interface,结尾是一条 @end 指令。在类名称后边(中间用冒号分隔),是父类的名称。在 Objective-C 中,每个类只能有一个父类。类中包含的实例变量(有时被称为 ivar,在其他编程语言中有时被称为成员变量)的声明被一个花括号({ 和 })包裹起来。实例变量是可选的。在实例变量语句块下边是属性(图中没有写出来)和类的方法声明。每个实例变量和方法声明的语句结尾都要有一个分号。


图 1 一段类声明

类的实现的语法也是类似的。开头是编译器指令 @implementation(后面有类的名称),结尾是 @end 指令。方法的实现代码就在这两个指令的中间。实现代码中必须导入它的接口文件,写在代码的第一行。

#import “MyClass.h”
    @implementation MyClass
- (id)initWithString:(NSString *)aName
{
    // 在这里书写代码
}
    + (MyClass *)myClassWithString:(NSString *)aName
{
    // 在这里书写代码
}
@end

我们之前讲过,Objective-C 支持包含对象的动态类型变量,它同时也支持静态类性。静态类型变量的声明前边要有所述类的名称。而动态类型变量声明以id 来代表对象。在某些情形下,你会用到动态类型变量。比如,一个数组这样的对象集合(里面包含的对象类型可能是无法预知的)就会用到动态类型变量。这样的变量能够提供无比灵活的功能,使得 Objective-C 程序能够拥有更大的动态性。

下面的例子展示了静态类型和动态类型变量的声明方式:

MyClass *myObject1;  // 静态类性
    id       myObject2;  // 动态类型
    NSString *userName;  //曾出现在“你的第一个 iOS 应用”中(静态类型)

请注意第一个声明里的 * 星号。在 Objective-C 语言中,对象永远是通过指针来引用的。如果现在你还不能明白这句话的意思也不必担心,在学会Objective-C 基础之后再研究指针也不迟。现在你需要记住的,是在静态类型变量声明时,变量名称前面一定要有 * 星号。而 id 类型则暗示它是一个指针。

方法和消息

如果你刚刚开始接触面向对象编程,不妨先把“方法”想象成每个对象特有的一个函数。通过向一个对象发送消息,你便调用了对象的某个方法。Objective-C 中有两种方法:实例方法以及类方法。

·实例方法顾名思义,它的作用域仅在某个类的一个实例当中。换句话说,在调用某个实例方法之前,你必须先创建一个实例才行。实例方法是常见的方法。
    ·类方法则是指其作用域包括该方法所在的整个类。它不要求某个对象的实例作为消息的接收者。

方法的声明由以下几个部分构成:方法类型标识符,返回类型,一个或多个方法签名关键字,以及参数类型和名称。下面的图中是实例方法 insertObject:atIndex: 的声明语句。

在实例方法中,声明的开头是一个 – 减号;而声明类方法时前面要使用 + 加号。下文的“类方法”章节将详细讲述类方法的概念。

方法的名称(insertObject:atIndex:)是一系列方法签名关键词联结而成,包括冒号。冒号表示将会出现参数。在上面的例子中,这个方法含有两个参数。如果某个方法没有参数,则需要将第一个(也是唯一一个)方法签名关键词后面的冒号省略掉。

当你需要调用一个方法时,就是要向实现了该方法的对象发送一个消息,简而言之,就是给对象发送消息。(虽然“发送消息”常常用作“调用方法”的近义词,但是在 Objective-C 的运行时中,实际情况是发送消息。)一个消息就是一个方法的名字带上该方法所需的参数信息(要和数据类型正确对应)。你向对象发送的所有消息都是动态调度的,以此来实现 Objective-C 语言的多态性。(多态性是指:不同类型的对象都能对同一种消息做出回应。)有时,所调用的方法是由接收消息的对象的类的父类实现的。

要调度一个消息,运行时要求正确的消息表达方式。消息表达式由一对方括号([ 和 ])把消息(以及所需的参数)包裹起来,接收消息的对象写在左边括号后边。比如,要向 myArray 变量所含的对象发送一个 insertObject:atIndex: 消息,你要按下面的语法进行书写:

[myArray insertObject:anObject atIndex:0];

为了避免声明大量局部变量来存储临时结果,Objective-C 允许嵌套消息表达式。每个嵌套的表达式返回的值都会作为一个参数,或者接收消息的对象,甚至是另一个消息。比如,你可以将上一个例子中的任意一个变量替换成用消息接收数值。这样一来,如果你还有一个叫做 myAppObject 的对象,它含有访问数组对象以及将对象插入数组的方法,你可以将那个例子改造成下面这样:

[[myAppObject theArray] insertObject:[myAppObject objectToInsert] atIndex:0];

Objective-C 还提供了点语法特性,用来访问存取方法。存取方法是对象的 get 和 set 语句,这里是封装的关键,封装是所有对象的重要特性。对象把自己的状态封装(或隐藏)起来,并提供一个能让所有实例访问这个状态的通用接口。利用点语法,之前的例子又可以被改写成:

[myAppObject.theArray insertObject:myAppObject.objectToInsert atIndex:0];

点语法还可以用来赋值:

myAppObject.theArray = aNewArray;

这个语法其实是 [myAppObject setTheArray:aNewArray]; 这个语句的另一种表述方式,而且我们在之前的ios应用开发基础教程中,已经用过点语法来对变量进行赋值了:

self.userName = self.textField.text;

存取方法的使用会在明天关于“已声明的属性和存取方法”章节做详细介绍。

类方法

虽然之前的范例都是向类的实例发送消息,但你也可以向类自身发送消息。(这里的类,可以被理解为由运行时生成的 类 的对象。)向一个类发送消息时,该方法必须在之前被声明为类方法,而不是实例方法。类方法和 C++ 中的静态方法很相似。

你通常会将类方法用作工厂方法,借以创建该类的新的实例或者访问与该类相关的某些共有信息。类方法的声明语法和实例方法的十分相像,不同之处是方法类型标识符是一个 + 加号,而不是 – 减号。

下面的例子展示了如何把一个类方法当作该类的工厂方法进行调用。在本例中,array 方法是 NSArray 类的一个类方法,并且被 NSMutableArray 类继承。它会给这个类的新实例分配内存并将这个实例初始化,后把它返回给你的代码。

NSMutableArray *myArray = nil; // nil 本质上等同于 NULL

// 创建一个新数组,并将其赋值给 myArray 变量。

myArray = [NSMutableArray array];

 更多相关文章

·iOS开发入门:Objective-C基础语法串讲
·iOS开发入门:Objective-C语言简介
·iOS 应用程序开发教程:十、排除故障和检查代码
·iOS 应用程序开发教程:九、实施视图控制器
·iOS 应用程序开发教程:八、让应用程序具有辅助功能