10.1 对象的初始化
之前我们出现过这种模式,创建新的实例后初始化。
Fraction * myFract = [[Fraction alloc]init];
然后设置初始值
[myFract setTo: 1 over :3];
通常可以合并到一个方法中,例如:
可以定义一个initWith: over: 方法。常见的编程习惯是类中所有的初始化方法都以init开头。
如果希望在类对象初始化时做一些事情,如引用一个或者多个变量,可以通过重载init方法。标准“模板”看起来是这样的:
-(instancetype)init
{
self = [super init];
if (self){
//初始化代码
}
return 0;
}
所谓的“指定的”初始化方法就是那些能确保所有继承而来的实例变量都能被初始化的方法(通常都是向super发送消息来调用超类的初始化方法)。这种方法是进行初始化的核心,其他的初始化方法通常都会调用这种方法。在Cocoa编程中有这样的一个传统:“指定”的初始化方法通常是最能决定新对象特性的方法(通常情况下它和其他的初始化方法相比较而言参数最多,但也有例外)。
重要的一点是需要确保继承而来的初始化方法必须也能正确地对派生类的对象进行初始化。这点通常都是通过重写(override)这些继承而来的初始化方法来实现的。例如,类C作为B的派生类,实现了一个初始化方法:initWithName:fromfile:。那么C类必须确保从B中继承的init和initWithName:这两个方法也能正确地对C类的对象进行初始化。此时,只要在C类中重写继承而来的这两个方法即可:
-(instancetype)init
{
return [self initWith:0 over: 0];
}
10.2 作用域的回顾
10.2.1 关于属性 存取方法,实例变量
引用实例变量的变量名字是以“_”开头的。
遇到的@synthesize 指令如下:
@synthesize window = _window;
表明合成属性window的取值方法和设值方法,并将属性与实例变量_window(实例变量并没有显示声明)关联起来。
[self.window makeKeyAndVisible];
在实现部分显示声明实例变量是私有的,意味着并不能在子类中通过名字直接获取到实例变量,在子类中只能使用继承的存取方法获取实例变量的值。
10.2.2 全局变量
如下语句:
int gMoveNumber = 0;
这样的定义使得其他文件也可以访问变量gMoveNumber的值。前面的语句不仅将gMoveNumber定义为全局变量,还将其定义为外部全局变量。
外部变量可以被其他任何方法或函数改变值和访问的变量。在访问外部变量的时候变量声明和普通方法一样,值需要在声明前加上extern,这就告知系统,要访问其他文件中定义的全局变量。
例如:
extern int gMoveNumber;
10.2.3 静态变量
如语句:
static int gGlobalVar = 0;
声明在任何方法(或者函数)之外,静态变量不是外部变量,话句话说我们希望声明的全局变量只是在特定的模块中是全局的。
类的分配器方法,记录已经分配的空间数目,实现的方式就是在类的实现代码中设定静态变量。由于它不是实例变量,所以分配器方法可以访问它,作用域是文件内部。
static int gCounter;
@implementation Fraction
+(Fraction *) allocF
{
extern int gCounter;
++gCounter;
return [Fraction alloc];
}
+(int) count
{
extern int gCount;
return gCount;
}
声明gCounter 为静态变量,执行文件中的方法可以访问它,allocF方法仅仅递增gCounter变量,然后使用alloc方法创建一个新的Fraction。count方法只返回计数器的值。
#import"Fraction.h"
int main(int argc,char *argv[])
{
@autoreleasepool {
Fraction *a , *b ,*c;
NSLog (@"Fraction allocated: %i",[Fraction count]);
a = [[Fraction allocF]init];
b = [[Fraction allocF]init];
c = [[Fraction allocF]init];
NSLog(@"Fraction allocated:%i",[Fraction count]);
}
return 0;
}
10.3 枚举数据类型
#import<Foundation/Foundation.h>
int main (int argc,char *argv[])
{
@autoreleasrpool {
enum month { january = 1,february,march,april,may,june,july,august,september,october,november,december };
enum month amonth;
int days;
NSLog (@"Enter month number:");
scanf ("%i",&amonth);
switch (amonth){
case january:
case march:
case may:
case july:
case august:
case october:
case december:
days = 31;
break;
case april:
case june:
case september:
case november:
days = 30;
break;
case february;
days = 28;
break;
default:
NSLog(@"bad month number");
days = 0;
break;
}
if (days != 0)
NSLog(@"Number of days is %i",days);
if (amonth == february)
NSLog(@"...or 29 if it's a leap year");
}
return 0;
}
枚举类型提供了一种方法使你能把整数值和有象征意义的名称对应起来。
10.4 typedef语句
为数据类型指派另一个名称,语句:
typedef int Counter;
定义名称Counter等价于Objective-C数据类型int . 随后变量可以声明为Counter类型,语句
Counter j,n;
定义一个名为Direction的枚举数据类型,它包含4个方向,东,南,西,北。写出枚举类型的声明。出现变量的地方用Direction代替。
typedef enum { east, west, south, north } Direction;
声明Direction类型的变量:
Direction step1 ,step2;