1、#import 跟 #include 有什么区别,@class呢,#import<> 跟 #import<>有什么区别?
#include
C语言中引入一个头文件,但是可能出现交叉编译
#import
在OC中引入自己创建的头文件#import””
或者系统框架#import<>
。
#import
不会出现交叉编译,@class
对一个类进行声明,告诉编译器有这个类,但是类的定义什么的都不知道
@class
的作用是告诉编译器有@class
后面的内容是一个类名。只是告诉编译器存在这么一个类,类具体包含哪些方法,属性和变量的并没有告诉编译器。一般在类的头文件中使用@class
来引入其他类。
2、描述一下KVO 和 KVC?
Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。
KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。
3、类目和继承地区别
1.类别是对方法的扩展,不能添加成员变量。继承可以在原来父类的成员变量的基础上,添加新的成员变量
2.类别只能添加新的方法,不能修改和删除原来的方法。继承可以增加、修改和删除方法。
3.类别不提倡对原有的方法进行重载。继承可以通过使用super
对原来方法进行重载。
4.类别可以被继承,如果一个父类中定义了类别,那么其子类中也会继承此类别。
4、简述你对UIView、UIWindow、CALayer的理解。
CALayer是图层类,本身可以显示的,但是不能响应事件。
UIView是iOS系统中界面元素的基础,所有的界面元素都继承自它。事件的处理由它来执行,但是显示其实是由其对应的layer
层来操作的,UIView内嵌了一个layer
,layer
显示内容,UIView本身增加了事件处理的功能。
UIWindow继承自UIView,主要的作用是作为窗口呈现其他的视图。而且一个应用程序一般情况下只有一个窗口。
5、do while和while do 的区别?
while
语句是先测试条件再执行语句,条件不符后终止
do while
语句是先执行语句再测试条件,条件不符后终止,所以do while
循环至少执行一次
6、nil,NSNULL,NULL 区别
nil定义一个实例为空, 指向oc中对象的空指针.是对objective c id
对象赋空值,对于objective c
集合类对象 比如数组对象,字典对象,当我们不需要再使用他们的时候,对他们release
的同时最好也把他们赋值为nil
,这样确保安全性,如果不赋值nil
,可能导致程序崩溃
NSNull类定义了一个单例对象用于表示集合对象的空值
集合对象无法包含nil作为其具体值,如NSArray
、NSSe
t和NSDictionary
。相应地,nil值用一个特定的对象NSNull
来表示。NSNull
提供了一个单一实例用于表示对象属性中的的nil值。默认的实现方法中,dictionaryWithValuesForKeys:
和setValuesForKeysWithDictionary:
自动地将NSNull
和nil
相互转换,因此您的对象不需要进行NSNull
的测试操作。
NULL可以用在C语言的各种指针上,在Objective-C里,nil对象被设计来跟NULL空指针关联的。他们的区别就是nil是一个对象,而NULL只是一个值。而且我们对于nil调用方法,不会产生crash
或者抛出异常.
7、内存中的栈和堆的区别是什么?哪些数据在栈上哪些数据在堆上?
1.管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生 memory leak
。
2.申请大小:能从栈获得的空间较小,堆是向高地址扩展的数据结构,是不连续的内存区域。堆的大小受限于计算机系统中 有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
3.碎片问题:对于堆来讲,频繁的new/delete
势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。 对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块 从栈中间弹出
4.分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成 的,比如局部变量的分配。动态分配由 alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器 进行释放,无需我们手工实现。
5.分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈 都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的。
在函数体中定义的变量通常是在栈上,用malloc
, calloc
, realloc
等分配内存的函数分配得到的就是在堆上
8、浅复制和深复制的区别
浅层复制:只复制指向对象的指针,而不复制引用对象本身。
深层复制:复制引用对象本身。
意思就是说我有个A对象,复制一份后得到A_copy对象后,对于浅复制来说,A和A_copy指向的是同一 个内存资源,复制的只不过是是一个指针,对象本身资源 还是只有一份,那如果我们对A_copy执行了修改操作,那么发现A引用的对象同样被修改,这其实违背 了我们复制拷贝的一个思想。深复制就好理解了,内存中存在了
两份独立对象本身。
用网上一哥们通俗的话将就是:
浅复制好比你和你的影子,你完蛋,你的影子也完蛋
深复制好比你和你的克隆人,你完蛋,你的克隆人还活着。
深浅拷贝前提是:是实现NSCopying
或者NSMutableCopying
协议。
浅拷贝只是复制对象本身,对象的属性和包含的对象不做复制。
深拷贝则对对象本身复制,同时对对象的属性也进行复制。
深浅拷贝的本质区别是对象或者对象属性的内存地址是否一样,一样则为浅拷贝,不一样则为深拷贝。
Foundation
框架支持复制的类,默认是浅拷贝。其中对Foundation
中不可变的对象进行copy
时作用相当于retain
。
而如果是mutablecopy
时,无论对象是否可变,副本是可变的,并且实现了真正意义上的copy。如果对可变对象进行copy,
副本对象是不可变的,同样是真正意义上的copy。
9、UITableView的执行流程是怎么样的?
第一轮:
1、numberOfSectionsInTableView
:假如section=2,此函数只执行一次,假如section=0,下面函数不执行,默认为1
2、heightForHeaderInSection
,执行两次,此函数执行次数为section数目
3、heightForFooterInSection
,函数属性同上,执行两次
4、numberOfRowsInSection
,此方法执行一次
5、heightForHeaderInSection
,此方法执行了两次,我其实有点困惑为什么这里还要调用这个方法
6、heightForFooterInSection
,此方法执行两次,
7、numberOfRowsInSection
,执行一次
8、heightForRowAtIndexPath
,行高,先执行section=0,对应的row次数
第二轮:
1、numberOfSectionsInTableView
,一次
2、heightForHeaderInSection
,section次数
3、heightForFooterInSection
,section次数
4、numberOfRowsInSection
,一次
5、heightForHeaderInSection
,执行section次数
6、heightForFooterInSection
,执行section次数
7、numberOfRowsInSection
,执行一次
8、heightForRowAtIndexPath
,行高,先执行一次
9、cellForRowAtIndexPath
10、willDisplayCell
然后8、9、10依次执行直到所有的cell被描画完毕