现在 是 时候 在objective-c当中 创建 某一类物件了。假设 你 想 在程序中 创建 比例这类物件。汽车这类物件 通常 是 由外壳、发动机、油箱等 组成的。同样的道理 比例 应该 是 由分子、分母 和 斜杠 组成的。当你 去买 汽车的时候,你 先 去买 外壳,然后 去买 发动机,再然后 去买 油箱 等等,最后 你 在家里 把 它们 组装起来,这 看似 是 一个不可能完成的任务。于是 你 最好的办法 就是 直接 买 一辆组装好了的汽车。每当你 需要使用 比例的时候,你 都必须 用到 分子、分母 和 斜杠。虽然 这 并非 不可完成,但是 使用比例的次数 一旦 变 多,这样 就 非常 麻烦。于是 我们 可以 像 组装汽车那样 将 分子、分母 和 斜杠 组装起来 批量生产。
下面这个例子 就展示了 如何创建 组装 和 批量生产 “比例”这种物件:
上面这个程序 从逻辑上 分成了 三个部分,它们 分别 是
1、接口部分:@interface
2、实施部分:@implementation
3、程序部分。
其中的接口部分 包含了 新的一类物件的名称,这类物件 属于 哪一类物件,这类物件 由哪些数据 组成,你 可以对 这类物件中的某一个 采取 什么种类的措施。比如 这个程序中 接口部分开头的
表明 我 新创建的这类物件 叫做 Fraction,而 Fraction这类物件 属于 NSObject这类物件。这 就 好比 轿车这类事物 属于 汽车这类事物,而 汽车这类事物 又属于 交通工具这类事物,而 在objective-c当中 所有的物件 都属于 NSObject这类物件。每一类物件的名称 最好 用 大写字母 开头,这样 可以 跟 其他类型的名称 区分开来。
接下来的
则是 组成Fraction这类物件的数据。其中 包含了 整数类型的变量numerator 和 denominator,变量numerator 用来存储 分子;变量denominator 用来存储 分母。这些变量 属于 个体变量,因为 Fraction这类物件中的每一个 都拥有 这些变量,而且 Fraction这类物件中的每一个物件所拥有的这些变量 都只属于 每个这些物件自己。比如 fraction_one 和 fraction_two这两个物件 都属于 Fraction这一类,而 fraction_one所拥有的变量numerator 和 fraction_two所拥有的变量numerator 是 两个不同的变量 而且 由这两个物件 各自 拥有。
最后的
说明了 对属于Fraction这类事物的物件 可以采取 哪些措施。每项措施 开头的减号 表明 这项措施 只能针对 某个物件;与此相反 如果 某项措施 以加号 开头,就表明 这项措施 只能针对 某类事物。
跟c语言中函数相似的 是 接下来的圆括号里的内容 说明了 每项措施的返回值类型,而 void 表明 这项措施 什么 也不返回。紧接着返回值类型的 是 措施名称。措施名称紧接着的冒号 表明 这项措施 附带了 参数。冒号后面的小括号 说明了 参数的类型,比如 这里的int 就表明 这项措施的参数 属于 整数类型。参数类型 紧接着 参数名称,参数名称 同样 代表了 变量的名称,参数 会存储 在这些变量里面。
接口部分 一定要用 @end 结尾,就像 这样:
这 不需要 分号 结尾。
实施部分包含的 是 每项措施的具体内容。实施部分 总是 用 @implementation 开头,用 @end 结尾。紧接着@implementation的 是 某类物件的总称。
第一项措施setNumerator:的具体内容 是 将 变量n当中的参数 存储 在变量numerator当中 作为 分子。第二项措施setDenominator:的具体内容 是 将 变量d当中的参数 存储 在变量denominator当中 作为 分母。最后一项措施print的具体内容 是 将 变量numerator 和 denominator的值(也就是 分子 和 分母)以及 斜杠 显示 在屏幕上。
程序部分的代码 用来解决 某个具体的问题。其中的
创建了 一个Fraction *类型的变量myFraction,这 表明 变量myFraction 可以用来存储 Fraction这类物件中的某一个。
这里的alloc 是 英文“分配”一词的缩写。alloc这项措施 是 为 一个新的Fraction类型的物件 分配 内存空间 并且 创建 一个新的Fraction类型的物件。
会把 alloc这个消息 传递给 Fraction,然后 Fraction这类物件 会采取 alloc这项措施。一个新的Fraction类型的物件 创建后 就存储 在变量myFraction当中。这时 我们 就可以说 myFraction 是 一个单独的物件了。
myFraction这个物件 创建好了 并不意味着 这个物件 已经 正确地 初始化了。所以 在使用 这个物件之前,你 必须将 其 初始化。下面这个语句 就能完成 初始化这项任务:
需要注意的 是 alloc这项措施 是 由Fraction这类物件采取的,而 init这项措施 是 针对myFraction这个物件采取的。 init这项措施 采取过后 会返回 一个结果,那就是 一个初始化过后的Fraction类型的物件,这个结果 存储 在变量myFration当中。
创建 一个新物件 并且 将 其 初始化的两条语句 通常 可以合并为 一条,就像 这样:
首先执行的 是
这条语句。这条语句执行的结果 就是 一个未经初始化的Fraction类型的物件。这个未经初始化的Fraction类型的物件 并 没有 直接 存储 变量myFraction,而是 对 其 采取了 init这项措施(也就是 对 其 进行 初始化)。 这个Fraction类型的物件 经过 初始化后 就被存储 在变量myFraction当中了。
其实 创建 Fraction *类型的变量、创建 一个Fraction类型的物件 和 初始化 这个物件 这三个步骤 可以合并成 一个:
在以后的博文当中,我 会 始终 使用 这样的代码风格。因此 理解 这样的代码风格 非常 重要。
和
这两个语句 对 myFraction这个物件 分别 实施了 setNumber: 和 setDenominator:这两项措施。实施 setNumerator:这项措施时 附带的参数 是 3,也就是 将 myFraction这个物件所包含的分子 设定为 3。实施 setDenominator:这项措施时 附带的参数 是 10,也就是 将 myFraction这个物件所包含的分母 设定为 10。
这个语句 通过调用 函数NSLog() 将 其参数”比例为:” 显示 在屏幕上。
这个语句 是 对myFraction这个物件 采取 print这项措施。而 print这项措施的具体内容 就是 将 myFraction这个物件所代表的比例的分子、分母(也就是 变量numerator 和 denominator的值)连同中间的斜杠 显示 在屏幕上。
这个语句 对myFraction这个物件 采取了 release这项措施。release这项措施 会将 myFraction这个物件所占用的内存空间 腾空。 这 是 形成 良好编程习惯的关键之一。当你 创建 一个新的物件时,它 就会占用 额外的内存空间。当你 使用完 这个物件后,你 就必须负责将 这个物件所占用的内存空间 腾出来。虽然 一个程序 退出过后,这个程序的所有物件所占用的内存空间 就会被腾空,但是 当你 开发的程序 变得 越来越 复杂时,你的程序 可能会包含 成百上千的物件,这些物件 会占用 大量的内存空间。如果 你 指望 等程序 退出的时候,这些物件所占用的内存空间 自动 腾空,那么 就会浪费 大量的内存空间,使 程序的执行 变 慢。而且 这 不是 良好的编程习惯。所以 必须养成 习惯 在使用完 一个物件后 就将 这个物件占用的内存空间 腾空。