Effective Objective-C 2.0读书笔记 Ⅰ

1 . 了解 Objective-C 语言的起源

Objective-C 语言使用”消息结构”而非”函数调用”.Objective-C 语言由 Smalltalk演化而来,后者	
是消息类型语言的鼻祖.编译器甚至不关心接收消息对象的何种类型.接收消息的对象问题也要
在运行时处理,其过程叫做”动态绑定”.	

Objective-C为 C 语言添加了面向对象特性,是其超类. Objective-C 使用动态绑定的消息结构,
也就是说,在运行时才会检查对象类型.接收一条消息后,究竟应执行何种代码,有运行期环境而
非编译器决定.理解 C 语言的核心有助于写好 Objective-C 程序.尤其是掌握内存模型与指针.

2.在类的头文件中尽量少引入其他头文件

  Objective-C 语言编写类的标准行为:以类名做文件名
  分别将两个文件,有文件后缀用. h,实现文件后缀用. m.
  
  == .h 文件
#import <Foundation/Foundation.h>
@interface People : NSObject    
@property (nonatomic, strong) NSString *name;
@end
== .m 实现文件
@implementation People
@end

查看People.h 文件,用Objective-C语言编写任何类几乎都需要引入Foundation.h,如果不引入这个文件的话,则需要引入预期超类所属框架相对应的"基本头文件"(base header file)。

现在创建个Person类,并引入People类

== .h 文件
#import <Foundation/Foundation.h>
#import “Person.h" //引入Person.h
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) Person *person;
@end
== .m文件
@implementation Person
@end

当系统编译Person.h 文件的时候,Person 并不可见,必须引入Person.h,常见方法为

#import "Person.h"

由于在编译 Person 类的文件时,不需要知道Person类的全部细节(Person 类中的方法),若使用 #import “Person.h” 则必须知道Person.h的全部细节,而Person类中只需要知道类名Person就可以了,可用通过以下方式告诉编译器@class Person;这种方式叫向前声明 (forward declaring)

修改后的Person.h 文件如下

== .h 文件#import <Foundation/Foundation.h>
#class Person; //引入Person.h
@interface Person : NSObject    
@property (nonatomic, strong) NSString *name;    
@property (nonatomic, strong) Person *person;
@end
== .m 文件
// Person 的实现文件则需要引入Person.h文件,需要知道Person所有接口细节。
#import "Person.h"  
@implementation Person
@end

(1) 向前引用,就是将引入头文件的时间尽量延后,只在确有需要时才引入,这样就可用减少类的使用者所需要引入的头文件数量。

(2) 向前声明解决的问题
向前声明解决了两个类互相引用的问题。
假如Dog 类中,需要添加Persion 属性,如果使用使用#import "Person.h"则会导致循环引用,当解析到Dog.h文件时,编译器会发现它引入Person.h头文件,编译器在引入Person.h头文件时,Person.h头文件反过头来引用Dog.h头文件,造成循环引用。

(3) 总结
向前声明可用降低编译时间,除非必要,则可以使用向前申明,并在实现文件中映入头文件,这样做可用尽量降低类之间的耦合。

3. 多用字面量语法,少用与之等价的方法

NSArray *arr = [NSArray arrayWithObjects:@"num1",@"num2",@"num3", nil];
NSArray *arr = @[@"num1",@"num2",@"num3”];

字面量语法创建字符串,数组,数值,字典.与穿件此类对象的常规方法相比,这么做更加简明扼要.

要点

  • 除了字符串以外,所创建的类必须属于 Foundation 框架才行,如果自定义了这些类的子类,则无法用字面量语法创建其对象.
  • 穿件的数组或字典时,若值有 nil, 则会抛出异常.因此,务必确保值中不含 nil.

4. 多用类型常量,少用# deine 预处理指令

不要用预处理指令定义常量,这样定义出来的常量不含类型信息,编译器只会在编译前根据执行查找与替换操作,即使有人重新定义了常量值,编译器也不会产生警告信息,这将导致应用程序中的常量值不一致.

5.用枚举表示状态,选项,状态码

应该用枚举来表示状态机的状态,传递给方法的选项以及状态码等值,给这些值起个易懂的名字
enum PersonEnum{
PersonEnumNum1,
PersonEnumNum2,
PersonEnumNum3,
};
typedef enum PersonEnum PersonState;

6. 理解属性这一概念

iOS属性关键字

属性是 Objective-C 的一项特性,用于封存对象中的数据.
属性特质:原子性 读写权限
内存管理语义

assign 这是方法只会执行针对纯量类型(CGFloat,NSInteger)的简单赋值操作
strong 此特质表明该属性定义一种拥有关系,为这种属性设置新值时,这只方法会先保存新值,并释放旧值
weak 此特质表明属性定义了一种”非拥有关系”,为这种属性设置新值是,设置方法既不保留新值,也不释放旧值.此特质同 assign 类似,然而在属性所指对象遭到摧毁时,属性值会清空
unsafe_unretainde 此特质与 assign 相同,它适用于对象类型,该特质表达一种"非拥有关系”,当目标对象遭到摧毁时,属性不会自动清空,因为它是不安全的,这一点与 weak 的区别
copy 此特质所表达的所属关系与 strong 类似,然而设置方法并不保留新值,而是将其拷贝,多用于 NSString.

7. 在对象内部尽量直接访问实例变量

懒加载
直接访问实例变量的速度比较快,因为不经过 Objective-C 方法派发,编译器所生成的代码会直接访问保存催下实例量的那块内存.
直接访问实例变量时,不会调用设置方法,这就绕过了相关属性所定义的内存管理语义.

发布了34 篇原创文章 · 获赞 4 · 访问量 711

猜你喜欢

转载自blog.csdn.net/weixin_44824650/article/details/103965485