OC基础知识总结一

1、详述OC的内存管理机制。

OC使用引用计数(retainCount)的机制来管理对象。自己生成的对象,自己持有。非自己生成的对象自己也能处理。不在需要自己持有的对象时,释放掉。非自己持有的对象无法释放。

a、在MRC中,retain与release配对使用,retain引用计数+1,release引用计数-1。
b、与alloc配对使用的方法是dealloc,alloc是开辟内存空间,dealloc是销毁开辟的内存空间。
c、readwrite、readonly读写控制。
readwrite即声明getter方法又声明setter方法。
readonly告诉编译器之生命getter方法。
默认属性为readwrite。
d、nonatomic,atomic为原子性控制
nonatomic非原子性控制,此时setter、getter方法不会做多线程处理,提高系统性能。
atomtic为原子性,此时setter、getter方法会做多线程处理,要不断的对setter、getter方法加锁解锁来保证线程安全,但是也降低了系统的性能。

2、delegate为什么用assign或者weak?详述!

a、delegate之所以使用weak来修饰,是为了防止循环引用,weak属性的变量是不为其所属对象所持有,并且在该对象被销毁后,此weak变量的值会自动被赋值为nil。而assign属性一般是对C基本数据类型成员变量的声明,当然也可以用在对象成员变量上,只是其代表的意义只是单纯的拷贝所赋值变量的值。
场景:对某成员变量B赋值某对象A的指针,则B只是简单地保存此指针的值,并不持有对象A,那么如果A被销毁,B就会指向一个已经被销毁的对象,如果再对其发送消息会引起崩溃。
b、
扩展空指针和野指针:
空指针:没有存储任何内存地址的指针就称为空指针。如:NSString *str= nil/NULL;
野指针:指针指向一个已经被销毁的内存。
总结:使用野指针是非常危险的,容易引发崩溃。而使用空指针发消息是没有任何问题的。
c、使用weak的情况
assign是指针赋值,不对引用计数操作,使用之后如果没有置为nil,可能就会产生野指针;而weak一旦不进行使用后,永远不会使用了,就不会产生野指针!

3、Block的使用

a:为什么使用weakSelf?
因为Block是一个结构体,它会将一个全局变量保存为一个属性(__strong),而self强引用了Blcok这会造成循环引用,所以使用__weak修饰weakSelf。
b:为什么在Block里面使用strongSelf?
为了保证block在执行完毕之前self不会被释放,而strongSelf是为了保证Block内部执行的时候不会被释放,但是存在执行前就已经额比释放的情况,导致strongSelf=nil。注意判空处理,防止出现崩溃。typeof是编译时确定变量类型,所以这里写self 不会被循环引用。

总结:

外部使用了weakSelf,里面使用strongSelf却不会造成循环,究其原因就是因为weakSelf是block截获的属性,而strongSelf是一个局部变量会在“函数”执行完释放。
另外:
a:__block可以让block修改局部变量,而__weak不能。
b:MRC中__block是不会引起retain;但在ARC中__block则会引起retain,因为,block也是一个强引用,引起循环引用,会引起循环引用。所以ARC中应该使用__weak。

4、深拷贝和浅拷贝的区别?

深拷贝:是重新复制了一份数据包括内存和指针,相当于克隆
浅拷贝:只是赋值指针,指向的还是原来的内存地址。当原来的内存数据有变化,浅拷贝的数据也会改变。
扩展1:NSString使用copy和strong的区别?
1、在NSString的时候源数据为不可变时copy是浅拷贝,新的指针指向相同的内存地址,这一点和strong相同,引用计数都增加。
2、在源数据可变的时候copy是深拷贝,生成了一个新的对象。而strong还是指向原有对象。
结果:在源数据改变的时候,copy修饰的属性可以保证数据的不变。strong在源数据为可变类型时会随着源数据的变化而变化。
链接:http://www.cocoachina.com/ios/20150512/11805.html
使用copy原因

5、load和initialize有什么用处?

在Objective-C中,runtime会自动调用每个类的两个方法。+(void)load会在类初始加载时调用,+(void)initialize会在第一次调用类的类方法或实例方法之前被调用。这两个方法是可选的,且只有在实现了它们时才会被调用。
共同点:两个方法都只会被调用一次。

6、atomic是绝对的线程安全么?

a:atomic并不是绝对的线程安全,当使用nonatomic时,属性的setter、getter操作是非原子性的,所以当多个线程同时对某一属性读和写操作时,属性的最终结果是不能预测的。
b:当使用atomic时,虽然属性的读写是原子性的,但是仍然可能出现线程错误:当线程A进行写操作时,此时,其他线程的读写操作会因为该操作而等待。当A线程进行写操作结束后,B线程进行写操作,当A线程需要读操作时获取的是B写的值,这样就破坏了线程的安全。如果有C再A线程操作之前release了该属性,那么会导致程序崩溃。
所以,仅仅使用atomic并不会使得线程安全,我们还要添加lock确保线程的安全。
atomic所说的线程安全只是保证getter和setter存取方法的线程安全,并不能保证整个对象的安全。

7、如何处理UI的耗时操作?

a:将耗时操作的IO放到子线程中去处理,然后到主线程中更新UI。
b:采用预加载的方式,提前处理耗时操作。优点是UI更加流程,缺点耗内存。
c:采用懒加载方式,耗时操作不立即使用,采用延时加载,优点提高界面的流畅度,在需要加载时才显示,缺点需要稍稍等待。

8、优化tableView方法?

1、行高的缓存有rowheigh就不要用heightForRowAtIndexPath用方法,防止方法的多次调用消耗。每次数据源变化时例如插入删除,尽量刷新特定行,不要全局刷新。
2、加载网络数据或者从内存中取得数据要开启分线程
3、layer添加圆角比较耗时,这样会离屏渲染,需要牺牲更多的性能。比如图片显示有圆角时,可以通过coreGraphic来生成带圆角的图片。
4、重用cell,防止重复绘制,减少渲染次数,提高性能。
5、减少subView的数量,尽量在同一个view上显示。
6、尽量少动态给cell添加view,可以初始化的时候就添加,通过hide控制是否显示。

9、线程知识点?

1、线程同步的方式包括:互斥锁、读写锁、条件变量、信号量和令牌。
* 并行和并发的区别?
并行:多个任务同时执行
并发:多个任务每隔一段时间执行
2、NSOperation与GCD的关系
NSOperation是基于GCD进行封装的,面向对象的。GCD是基于C语言的。

3、 默认最大并发
NSOperation系统默认的并发数是-1,所有任务全部并发执行
GCD没有默认并发数,我们可以通过信号量来设置并发量。dispatch_semaphore。
4、线程取消
[NSOperation cancel]。一旦取消无法再恢复,正在执行的任务无法取消。

5、 [thread cancel]可以关闭线程?
[thread cancel]取消线程,不能再开始。[NSThread exit];才是关闭线程。

10、NSBlockOperation和NSInvocationOperation有什么关系和区别?

相同点:
1、NSBlockOperation和NSInvocationOperation都是NSOperation的子类。通过子类执行任务,不添加到任务中在主线程中执行任务。
不同点:
1、NSBlockOperation可以在Block中执行任务。通过addExecutionBlock:方法添加更多的操作遵循FIFO。
注只要NSBlockOperation封装的操作数>0, 就会异步执行操作。线程为串行异步执行。
2、NSInvocationOperation是使用方法执行操作。

扩展1: NSOperation可以像GCD一样设置串行并行么?
答:不可以直接设置情形执行,但是可以这是依赖来实现串行执行,NSOperation本身就是并行执行。
扩展2: NSOperation的添加进队列后可不可以追加依赖?GCD任务组添加监听后可不可以追加任务?
答:都不可以。

11、performSelector和直接调用方法的不同?

1、performSelector是运行时系统负责去找函数/方法的,在编译时候不做任何校验;但是使用performSelector的话一定是在运行时候才能发现,如果方法不存在,此时程序崩溃。
2、直接调用方法在编译是会校验,如果test2方法不存在,那么直接调用在编译时候就能够发现。
扩展:可以使用runtime来处理没有实现的方法。

猜你喜欢

转载自blog.csdn.net/xiaoxiaocode/article/details/80340638