Objective-C 学习笔记(二)

最近开始学习 Objective-C 夯实基础,并尝试在学习基础上开发出简单的 iOS 应用程序。在此处总结可以方便本人更好地整理学习内容,此文为本系列的第二篇文章。

示例代码

先给出第二课学习的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//main.m
#import <Foundation/Foundation.h>
#import "Calculator.h"

int main(int argc, char* argv[]){
@autoreleasepool {
double value1, value2;
char operator;

SubCalculator *subCalculator = [[SubCalculator alloc]init];
[subCalculator print];
scanf("%lf %c %lf",&value1,&operator,&value2);

subCalculator.accumulator = value1;
switch (operator) {
case '+':
[subCalculator add: value2];
break;
case '-':
[subCalculator subtract: value2];
break;
case '*':
[subCalculator multiply: value2];
break;
case '/':
[subCalculator divide: value2];
break;
default:
NSLog(@"The operator is unknown!\n");
break;
}
NSLog(@"The result is %.2f",subCalculator.accumulator); //点运算符
NSLog(@"The result is %.2f", [subCalculator accumulator]); //getter方法
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//Calculator.h
#import <Foundation/Foundation.h>

@interface Calculator : NSObject

@property double accumulator;

-(void) add: (double) value;
-(void) subtract: (double) value;
-(void) multiply: (double) value;
-(void) divide: (double) value;
-(void) print;

@end

@interface SubCalculator : Calculator

-(void) print;

@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Calculator.m
#import "Calculator.h"

@implementation Calculator

@synthesize accumulator;

-(void) add: (double) value{
accumulator += value;
}
-(void) subtract: (double) value{
accumulator -= value;
}
-(void) multiply: (double) value{
accumulator *= value;
}
-(void) divide: (double) value{
accumulator /= value;
}

-(void) print{
NSLog(@"Type in your expression.\n");
NSLog(@"Method from Class Calculator.\n");
}

@end

@implementation SubCalculator

-(void) print{
NSLog(@"Type in your expression.\n");
NSLog(@"Method from Sub Class subCalculator.\n");
}

@end

运行结果如下:

1
2
3
4
5
2020-03-26 18:21:58.865631+0800 DemoProgram[17447:519699] Type in your expression.
2 * 5
2020-03-26 18:22:23.471596+0800 DemoProgram[17447:519699] The result is 10.00
2020-03-26 18:22:23.471696+0800 DemoProgram[17447:519699] The result is 10.00
Program ended with exit code: 0

代码解释

相比上一次实验,接口与实现文件得到了分离,这一点与C++是类似的。
类的声明,即@interface 部分,用于描述类和类的方法,放在自己的名字为class.h的文件中;类的实现,即@implementation 部分,用于描述类对象的实例变量存储的数据,实现了接口中声明的方法,放在同名的.m文件中;main.m实现了简易计算器的功能。
该程序简单验证了继承、覆写的概念,可以在程序基础上做出更改验证

点运算符

1
[calculator setAccumulator: value1]

1
calculator.accumulator = value1;

都完成了赋值操作,需要注意的是编码风格,点运算符通常运用在属性上,用于设置或取得实例变量的值,其他的工作通常使用传统的方括号形式的消息表达式作为首选语法。

@property 与 @synthesize

合成存取

使用synthesize的存取方法,属性前面不要用new、alloc、copy或者init等作为开头,编译器会合成相关方法。

1
@property double accumulator;

如果使用了@property指令,就不需要在实现部分声明相应的实例变量。

1
@synthesize accumulator;

这句话告诉Objective-C编译器,为accumulator属性生成一对设值方法和取值方法,即设值方法accumulator与取值方法setAccumulator
如果只使用@property且并未使用@synthesize,编译器也会生成相应的 setter 和 getter,但是生成的实例变量以下划线(_)作为其名称第一个字符,如此处会生成”_accumulator”。

继承中存在的问题

在子类中使用实例变量,必须现在接口部分声明变量,而不是在实现部分声明变量。在实现部分声明和合成(@synthesize)的实例变量为私有,无法在子类中访问。

其他总结

关于多态

使不同的类共享相同方法名称的能力叫多态。

多态让你可以开发一组类,这组类中的每一个类都能响应相同的方法名。每个类的定义都封装了响应特定方法所需的代码,这就使得它独立于其他的类定义。多态还允许你以后添加新的类,这些新类能够响应相同的方法名。

关于动态类型

  • id 可以用来存储属于任何类的对象,且id对象类型的声明中无需使用星号(*)。
  • Objective-C 总是跟踪对象所属的类。系统先判定对象所属的类,然后在运行时确定需要动态调用的方法,而不是在编译的时候。
  • 静态类型能够在程序编译阶段而不是运行阶段标明错误
  • 静态类型相比动态类型能够提高程序可读性

如果存在id变量dataValue 1dataValue2,那么

1
result = [dataValue1 add: dataValue2] ;

会导致编译器生成代码,将参数传递给add:方法,并通过假设来处理其返回值。
在运行时,Objective-C 运行时系统仍然会检查存储在dataValue1中对象所属的类选择相应的方法来执行。然而,在大多数情况下,编译器可能生成不正确的代码来向方法传递参数或处理返回值。
当一个方法选取对象作为它的参数,而另一个方法选取浮点数作为参数时,很有可能发生这种情况。如果这两个方法之间的不一致仅在于对象类型的不同,编译器仍然能够生成正确的代码,因为传递给对象的引用是内存地址(即指针)。

关于类的问题

NSObject类支持的基本方法

isMemberOfClassisKindOfClassisSubclassOfClassrespondsToSelectorinstancesRespondToSelector的用法与意义应熟稔于心。

关于异常处理

Objective-C中对于异常处理的机制与C++Java等均为类似。格式如下:

1
2
3
4
5
6
7
8
9
10
@try {
statement
statement
...
}
@catch (NSException *exception) {
statement
statement
...
}

一般来说,你并不希望程序在运行时发生异常。这就需要考虑更好的编程实践,在错误发生之前做测试,而不是错误发生后捕获它。测试方法的错误并返回一些值作为错误的标识,而不是抛出异常。抛出异常通常会使用大量的系统资源,Apple 反对非必要的使用异常(例如,你不希望因为一一个文件无法打开而抛出异常)。

参考

Objective-C 程序设计 (第六版)