Objective-C笔记

一、在编译一个使用了CPerson类的文件时,若是不须要知道该类的所有细节,只须要知道有一个类名叫CPerson,最好“向前声明”该类(同理于对一个协议的引用),这样作也能够避免“循环引用”问题:objective-c

例:编程

@class  CPerson多线程

例:框架

#import "CShape.h"函数

#import "CDrawable.h"性能

@interface  CRectangle : CShape <CDrawable>atom

 

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

字面量语法的限制:除了字符串之外,所建立出来的对象必须属于Foundation框架才行。若是自定义了这些类的之类,则没法用字面量语法建立其对象。.net

例:线程

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"];

 

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

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

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

 

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

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

enum Week day = Monday;

 

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

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关键字则会告诉编译器:不要自动建立实现属性所用的实例变量,也不要为其建立存取方法。

 

六、在对象内部尽可能直接访问实例变量,在对象以外访问实例变量时老是经过属性来作 

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

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

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

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

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

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

4)经过属性来访问有助于排查与之相关的错误,由于能够给“设置方法”设置断点。

 

七、理解“对象等同性”这一律念

1)按照 == 操做符比较的是两个指针自己,而不是其所指的对象;

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

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

 

八、instancetype和id的异同

1)相同点:

均可以做为方法的返回类型

2)不一样点:

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

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

 

九、@selector

1)一种类型 SEL

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

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

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

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

 

十、理解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);

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

 

十一、@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方法一样会致使崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。

十二、全局变量,和局部变量再内存占用上有什么区别?

变量能够分为:全局变量、静态全局变量、静态局部变量和局部变量。  按存储区域分,全局变量、静态全局变量和静态局部变量都存放在内存的静态存储区域,局部变量存放在内存的栈区。  

按做用域分,全局变量在整个工程文件内都有效;静态全局变量只在定义它的文件内有效;静态局部变量只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失;局部变量在定义它的函数内有效,可是函数返回后失效。  

全局变量和静态变量若是没有手工初始化,则由编译器初始化为0。局部变量的值不可知。  

静态全局变量,只本文件能够用。  

全局变量是没有定义存储类型的外部变量,其做用域是从定义点到程序结束.省略了存储类型符,系统将默认为是自动型.  

静态全局变量是定义存储类型为静态型的外部变量,其做用域是从定义点到程序结束,所不一样的是存储类型决定了存储地点,静态型变量是存放在内存的数据区中的,它们在程序开始运行前就分配了固定的字节,在程序运行过程当中被分配的字节大小是不改变的.只有程序运行结束后,才释放所占用的内存.  

自动型变量存放在堆栈区中.堆栈区也是内存中一部分,该部份内存在程序运行中是重复使用的.       

相关文章
相关标签/搜索