前言:
这几篇文章是《Effective Objective-C 2.0》的知识产出,做下笔记拓展自己的知识层面。
iOS 编写高质量Objective-C代码(一)
1.第一章:熟悉Objective-C
第1条:了解Objective-C语言的起源
OC
由语言Smalltalk
演化而来, Smalltalk
是消息传递型语言的鼻祖。
消息传递
OC
与C++
、 Java
等面向对象语言类似,不过很多方面有所差别,因为OC
使用 “消息传递”
机制 而C++
、 Java
使用“函数调用”
机制
// Objective-C : messaging (消息传递)
Object *obj = [Object new];
[obj performWith:parameter1 and:parameter2];
// C++: function calling(函数调用)
Object *obj = new Object;
obj->perform(parameter1, parameter2);
区别:
消息传递:运行时所执行的代码由运行时
环境决定(runtime)
函数调用:运行时所执行的代码由编译器
决定
简单来说,OC总在运行时才会去查找真正所要调用的方法,编译器并不用关心接收消息的对象是什么类型,接收消息的对象也是在运行时才工作,其过程叫做动态绑定(dynamic binding)。而其他大部分面向对象语言,会在运行时查找“虚方法表”(virtual table)来查出执行的方法(是调用子类的方法?还是父类的方法?)。
指针
OC
是C
语言的“超集”,在 C
语言的基础上添加了面向对象的特性。C语言里的大部分知识在编写OC代码时依然适用。
OC
里的指针主要用来指示对象,基本语法和C
语言类似。
- 例如:声明一个字符串
NSString *someString = @"The String";
NSString *anotherString = someString;
语法解释:声明了一个名为someString
的变量,其类型为NSString *
。是一个指向NSString
的指针。
- 错误案例:
NSString str;
报错:error:interface type cannot be statically allocated
解释:对象不允许声明在栈空间上
不能在栈中分配OC对象,因为OC对象所占的内存会被分配在堆空间(heap space)上,由程序员来控制
它的内存分配。而栈空间的临时基本数据由编译器控制
。
- 再举一个典型案例:
xxxClass *Qi = [[xxxClass alloc] init];
xxxClass *Share = Qi;
这里有两个分配在栈空间的xxxClass指针:Qi和Share指向了堆空间中的同一块内存地址。
内存结构,图解如下:
分配在堆中的对象,内存必须由开发者管理。而分配在栈空间上的指针会在其栈帧弹出时自动清理。
OC将堆内存的管理抽象成了一个机制:ARC(Automatic Reference Counting)。在OC中,不需要用malloc
及free
来分配或释放对象所占的内存。OC在运行期环境中把这部分工作抽象为一套内存管理架构,我们称之为“引用计数”
。
第2条:在类的头文件中尽量少引用其他头文件
如果需要引用一个类文件时,只是需要使用类名,不需要知道其中细节,可以用
@class xx.h
,这样做的好处会减少一定的编译时间。如果是用的#import全部导入的话,会出现a.h
import了b.h
,当c.h
又importa.h
时,把b.h
也都导入了,如果只是用到类名,真的比较浪费,也不够优雅。有时候无法使用@class向前声明,比如某个类要遵循一项协议,这个协议在另外一个类中声明的,可以将协议这部分单独放在一个头文件,或者放在分类当中,以降低引用成本
第3条:多用字面量语法,少用与之等效的语法
传统创建数组方法:
NSArray *languages = [NSArray arrayWithObjects:@"PHP", @"Objective-C", someObject, @"Swift", @"Python", nil];
NSString *Swift = [languages objectAtIndex:2];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"key", @"value", nil];
NSString *value = [languages objectForKey:@"key"];
字面量:
NSArray *languages = @[@"PHP", @"Objective-C", someObject, @"Swift", @"Python"];
NSString *Swift = languages[2];
NSDictionary *dict = @{@"key" : @"value"};
NSString *value = languages[@"key"];
应该使用字面量语法来创建字符串、数值、数组、字典。与创建此类对象的常规方法相比,这么做更加简明扼要。
应用通过取下标操作来访问数组下标或字典中的键所对应的元素。
用字面量语法创建数组或者字典时,若值中有nil,则会抛出异常。务必确保值里不含nil。"arrayWithObjects"会依次处理各个参数直到nil为止,不管后面还有没有值,该方法都会提前结束。
字面量语法有一个小缺点就是创建的数组,字符串等等对象都是不可变的,如果想要可变的对象需要自己多执行一步mutableCopy
,例如
NSMutableArray *languages = [@[@"PHP", @"Objective-C", @"Swift", @"Python"] mutableCopy];