深入理解Objective-C

1、在编译一个使用了CPerson类的文件时,如果不需要知道该类的全部细节,只需要知道有一个类名叫CPerson,最好“向前声明”该类(同理于对一个协议的引用),这样做也可以避免“循环引用”问题:

例:

@class  CPerson

例:

#import "CShape.h"

#import "CDrawable.h"

@interface  CRectangle : CShape <CDrawable>


2、多用字面量语法,少用与之等价的方法 (NSString/NSNumber/NSArray/NSDictionary)

字面量语法的限制:除了字符串以外,所创建出来的对象必须属于Foundation框架才行。如果自定义了这些类的之类,则无法用字面量语法创建其对象。

例:

NSString *someString = @"Effective Objective-C 2.0";

NSNumber *someNumber = @1 ;

NSNumber *floatNumber = @2.5f;

NSNumber *boolNumber = @YES;

NSNumber *charNumber = @'a';


NSArray *animals = @[@"cat", @"dog",@"pig"];//若@“dog”为空,程序会抛出异常令应用程序终止执行,达到检查是否含空字符串的目的

NSArray *dog = animals[1];


NSDictionary *personData = @{@"firstName" : @"Matt", @"lastName" : @"Galloway", @"age" : @28};//一旦有值为nil也会抛出异常

NSDictionary *firstName = personData[@"firstName"];


3、多用类型常量const static,少用#define预处理指令,这样创建出来的常量有类型信息,便于差错。

1)若不打算公开某个常量,则应将其定义在使用该常量的实现文件里;

2)在头文件中使用extern来声明全局常量,并在相关实现文件中定义其值。


4、用枚举表示状态、选项、状态码

enum Week {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday};

enum Week day = Monday;


5、理解“属性” (属性用于封装对象中的数据,保存着数据的实例变量一般通过“存取方法”来访问)

1)atomic(原子性),如果属性具备nonatomic特质,则不使用同步锁;(开发iOS程序中所有的属性都声明为nonatomic,原因是:在iOS中使用同步锁的开销较大,这会带来性能问题;但是在开发Mac OS X程序时,使用atomic属性通常都不会有性能瓶颈。所以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)

2)readwrite(读写),拥有“获取方法”和“设置方法”,由@synthesize实现;

3)readonly(只读),仅拥有“获取方法”,由@synthesize实现;

4)assign,“设置方法”只会执行针对“纯量类型”(CGFloat、NSInteger等)的简单赋值操作,不更改索引计数,即setter方法直接赋值,不进行任何retain操作(对基础数据类型 (NSInteger)和C数据类型(int, float, double, char, 等)使用,否则可能导致内存泄露)

5)strong,设置方法会保留新值,并释放旧值,然后再将新值设置上去;使用ARC机制时,等同于retain

6)weak,设置方法既不保留新值,也不释放旧值。此特质同assign类似;使用ARC机制时,等同于assign,对象被释放时,属性的值会被设置为nil

7)copy,设置方法并不保留新值,而是将其“拷贝”,建立一个索引计数为1的对象,然后释放旧对象,即setter方法进行Copy操作,与retain处理流程一样,先旧值release,再Copy出新的对象,retainCount为1,为了减少对上下文的依赖而引入的机制(对NSString )

例:-(void)setOne:(NSObject *) other

{

if(one != other)

{

[one release];

one = [other copy];

}

}

8)retain,释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1,即setter方法对参数进行release旧值再retain新值,为了解决原类型与环循引用问题(对其他NSObject和其子类)

例:-(void)setOne:(NSObject *) other

{

if(one != other)

{

[one release];

one = [other retain];

}

}

(copy与retain的区别:

copy是创建一个新对象,retain是创建一个指针,引用对象计数加1

copy 到另外一个NSString 之后,地址为不同 ,内容相同,新的对象retain为1 ,旧有对象没有变化

retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1)


a、property,他可以提供的功能有:提供成员变量的访问方法的声明、控制成员变量的访问权限、控制多线程时成员变量的访问环境

b、synthesize的理解是:实现property所声明的方法的定义

c、使用属性的话,编译器会自动生成存取方法,并自动向类中添加适当类型的实例变量,并在属性名前面加下划线。

d、可用@synthesize语法来指定实例变量的名字;用@dynamic关键字则会告诉编译器:不要自动创建实现属性所用的实例变量,也不要为其创建存取方法。


6、在对象内部尽量直接访问实例变量,在对象之外访问实例变量时总是通过属性来做 

(笔者强烈建议在读取实例变量的时候采用直接访问的形式,而在设置实例变量的时候通过属性来做)

(在初始化方法及dealloc方法中,总是应该直接通过实例变量来读写数据)

直接访问(_name) 与 属性访问(self.name) 的区别:

1)直接访问速度快,编译器所生成的代码会直接访问保存对象实例变量的那块内存;

2)直接访问不会调用“设置方法”,这就绕过了为相关属性所定义的“内存管理语义”;

3)直接访问实例变量不会触发“键值观测”(KVO)通知;

4)通过属性来访问有助于排查与之相关的错误,因为可以给“设置方法”设置断点。


7、理解“对象等同性”这一概念

1)按照 == 操作符比较的是两个指针本身,而不是其所指的对象;

2)应该使用NSObject协议中声明的“isEqual”:方法来判断两个对象的等同性。(“isEqualToString:”、“isEqualToArray:”、“isEqualToDictionary:”)

3)相同的对象必须具有相同的哈希码,但是两个哈希码相同的对象却未必相同。


8、instancetype和id的异同

1)相同点:

都可以作为方法的返回类型

2)不同点:

instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;

instancetype只能作为返回值,不能像id那样作为参数。


9、@selector

1)一种类型 SEL

2)代表你要发送的消息(方法), 跟字符串有点像, 也可以互转.: NSSelectorFromString() / NSSelectorFromString()

3)可以理解为类似函数指针的东西–是能让Objective-C动态调用方法的玩意.–是 object-c 的动态后绑定技术 可以通过字符串 访问的函数指针

4)其实就是消息响应函数—选一个消息响应的函数地址给你的action

5)@selector(function_name) 即取得一个function的id


10、理解objc_msgSend的作用(“传递消息”)

1)消息由接收者、选择子(方法)及参数构成。给某对象“发送消息”也就是相当于在该对象上“调用方法”;

2)发给某对象的全部消息都要由“动态消息派发系统”来处理,该系统会查出对应的方法,并执行其代码;

3)C语言使用“静态绑定”(编译期就能决定运行时所应调用的函数),而objective-c则使用“动态绑定”(所要调用的函数直到运行期才能确定)

4)编译器看到消息后,会将其转换为一条标准的C语言函数调用,这个核心函数叫做:objc_msgSend:

id returnValue = [someObject messageName:parameter];

==> id returnValue = objc_msgSend(someObject, @selector(messageName:), parameter);

(该方法需要在接收者所属的类中搜寻其“方法列表”,如果能找到与选择子名称相符的方法,就跳至其实现代码。若是找不到,那就沿着继承体系继续向上查找,等找到合适的方法之后再跳转。如果最终还是找不到相符的方法,那就执行“消息转发”操作。)


11、@synthesize和 @dynamic

@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;

@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。

@dynamic诉编译器,属性的settergetter方法由用自己实现,不自生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var =someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。


(更新中。。。)

你可能感兴趣的:(深入理解Objective-C)