ObjectiveC: 变量和数据类型:初始化方法、外部/静态变量、枚举类型、typedef、类型转换、位运算符

初始化方法

初始化对象和设置初始值的过程通常可以合并到一个方法中,常见变成习惯是类中所有的初始化方法都以init开头。

包含很多方法和实例变量的类通常还有几个初始化方法。例如Foundation框架中的NSArray类包含6个额外的初始化方法:

initWithArray:、initWithArray:copyItems:、initWithContentsOfFile:、initWithObjects:、initWithObjects:count:。

可使用myArray[[NSArray alloc] initWithArray: myOtherArray]; 完成数组的空间分配和初始化工作。

编写初始化方法时应遵循两个策略:

1. 如果希望在类对象初始化时做一些事情(如Rectangle类初始化时需要为矩形指定XYPoint原点),可以通过重载init方法达到目的。

  //重载init方法标准模板
- (instancetype) init {
self = [super init]; //调用父类初始化方法,使继承的实例变量能够正常初始化
//注意必须将父类init方法的执行结果赋值给self,因为初始化过程改变了对象在内存中的位置(引用将要改变)
    if(self) { //如果父类初始化成功,返回值将是非空的
        //自定义初始化代码,通常可以再这个位置创建并初始化实例变量
    }
    return self
}

2. 如果你的类包含多个初始化方法,其中一个就应该是指定的(designated)初始化方法,通常是最复杂的初始化方法(一般是参数最多的初始化方法),并且其他所有初始化方法都应该使用这个方法。可以把大部分初始化代码几种到单个方法中,任何人想要从这个类派生子类,都可以重载这个指定的初始化方法,保证正确地初始化新的实例。

例:

//为Fraction类添加初始化方法initWith:over:
-(Fraction *)initWith:(int)n over:(int)d {
    self = [super init];
    if (self)
        [self setTo: n over: d];
    return self;
}
//使用初始化方法initWith:over:
a = [[Fraction alloc] initWith:1 over:3];
b = [[Fraction alloc] initWith:3 over:7];

 

为使用指定的初始化规则,需要修改Fraction类的init方法:

-(instancetype) init { //返回为instancetype类型,是编写可能会被继承的类init方法的一般规则
    return [self initWith:0 over:0];
}

 

外部变量:可以被其他任何方法或函数访问和更改的值,只要在需要访问外部变量的模块中用关键字extern声明变量,告知系统要访问其他文件中定义的全局变量。如:

int gMoveNumber = 0; /*变量必须不加关键字extern定义在源文件中的某个位置(在所有方法和函数外)*/
extern int gMoveNumber; //包含该声明的模块可以访问和改变gMoveNumber的值

如果很多方法需要访问该全局变量的值,则只在文件开始进行一次extern声明比较简便;如果只有一个或少数几个方法要访问该全局变量,则应该在其中的每个方法中单独进行extern声明(程序组织结构更清晰、不同函数可以单独使用这个变量);如果变量定义在包含访问这个变量的文件中,则不需要单独进行extern声明。

 

静态变量:如果希望定义的全局变量只在特定模块(文件)中是全局的,即除特定类中的方法外,再没有其他方法能够访问这个特定变量,可以在包含这个特定类的实现文件中将该变量定义为static。

如:

static int gGlobal;
/*如果该语句声明在任何方法(或函数)之外,则文件中所有位于该语句之后的方法或函数都可以访问gGlobalVar的值,而其他文件中的方法和函数则不行。*/

可以通过在类的实现代码文件中设定静态变量,记录类已经分配空间的对象数目。如:

在Fraction.h中添加两个新的类方法声明:

+(Fraction *) allocF;
+(int) count;

在实现文件Fraction.m中加入定义:

static int gCounter;

@implementation Fraction {
    int numerator;
    int denominator;
}

@synthesize numerator, denominator;

/*allocF类方法分配一个新的Fraction对象,同时记录分配了多少Fraction*/
+(Fraction *) allocF {
    extern int gCounter;
    ++gCounter;
    return [Fraction alloc];
}

/*count类方法返回记录的数值*/
+(int) count {
    extern int gCounter;
    return gCounter;
}
...
@end

在main.m中测试:

        Fraction *a, *b, *c;
        NSLog(@"Fractions allocated: %i", [Fraction count]); //output: 0 
/*程序开始时gCounter自动置零,如果需要设定特定计数可在类中添加setter方法*/
        a = [[Fraction allocF] init];
        b = [[Fraction allocF] init];
        c = [[Fraction allocF] init];
        NSLog(@"Fractions allocated: %i", [Fraction count]); //output: 3

 

枚举数据类型

 

enum flag {false, true} //定义数据类型flag,只能赋为true或false
enum flag endofDate, matchFound; /*声明enum flag类型的变量 (关键字enum-枚举类型名称-变量序列)*/

 

 

如果希望一个枚举标识符对应一个特定整数值,可在定义数据类型时给标识符指定整数值,列表中随后出现的枚举标识符依次+1赋整数值。如:

enum direction {up, down, left = 10, right}; //up=0, down=1, left=10, right=11

枚举标识符也可以共享相同的值。

 

Objective-C编译器实际上将枚举标识符作为整型常量处理。如:

enum month {January = 1, feburary, march, april, may, june, july, august, september, october, november, december};
enum month thisMonth;
thisMonth = feburary; //赋给thisMonth的值为整数2

但尽量不要依赖枚举值被作为整数的事实,应该将枚举数据类型当做独立的数据类型。

 

定义枚举类型时可以将一个整数类型和一个枚举名称对应起来。如:

enum iPhoneModels : unsigned short int {iPhone, iPhone3G, iPhone3GS, iPhone4, iPhone4s, iPhone5,
                            iPhone5C, iPhone5S); /*使用unsigned short int作为相关数据类型*/

 

定义枚举类型时也允许省略数据类型名称,将变量声明为特定枚举数据类型中的一个。如:

/*定义未命名枚举数据类型(包含值为east、west、south和north),同时声明该类型的变量direction*/
enum {east, west, south, north} direction; 

 

 

typedef语句

使用typedef语句可为数据类型另外指派一个名称。

 

typedef int Counter; //定义名称Counter等价于数据类型int,随后变量可声明为Counter类型
Counter j, n; //编译器实际上将变量j和n的声明当做普通整型int变量声明

typedef Number *NumberObject; //定义名为NumberObject的类型,是Number对象
NumberObject myValue1, myValue2, myResult; 
//等价于
Number *myValue1, *myValue2, *myResult;

typedef enum {east, west, south, north} Direction; //定义名为Direction的枚举数据类型
Direction step1, step2; //声明Direction类型的变量

 

 

 

数据类型转换

表达式求值过程中不同类型操作数发生转换的先后顺序(简化):

1. 如果其中一个操作数是long double型,则另一操作数被转换为long double型,计算结果也是。

2. 如果其中一个操作数是double型,则另一操作数被转换为double型,计算结果也是。

3. 如果其中一个操作数是float型,则另一操作数被转换为float型,计算结果也是。

4. 如果其中一个操作数是Bool、char、short int、bit field或枚举数据类型,则全部转换为int型。

5. 如果其中一个操作数是long long int型,则另一操作数被转换为long long int型,计算结果也是。

6. 如果其中一个操作数是long int型,则另一操作数转换为long int型,计算结果也是。

7. 如果到达这一步,则可知两个操作数均为int型,计算结果也是。

 

 

位运算符

 

 

位运算符除一次求反运算符(~)外都是二元运算符。

位运算符可处理任何类型的整型值,但不能处理浮点值。

按位与运算符&的优先级高于按位或运算符|。

 

posted @ 2017-10-16 13:38  丹尼尔奥利瓦  阅读(669)  评论(0编辑  收藏  举报