1.如何实现一个线程安全的NSMutableArray?
NSMutableArray是线程不安全的,当有多个线程同时对数组进行操作的时候,可能会导致崩溃或者数据错误。
实现方案:
- 线程锁:使用线程锁对数组的读写操作进行加锁;
- 派发队列:使用“串行同步队列”(serial synchronization queue),将读取操作及写入操作都安排在同一个队列里,即可保证数据同步。而通过并发队列,结合GCD的栅栏块(barrier)来不仅实现数据同步线程安全,还比串行同步队列方式更高效。
2.id和instanceType有什么区别
相同点:instanceType 和id 都是万能指针,指向任意对象;
不同点:1.id在编译时不能判断对象的真实类型,instanceType在编译的时候,可以判断对象的真实类型;2.id可以用来定义变量,可以作为返回值类型,可以作为行参类型,instanceType只能作为返回值类型。
3.setNeedsDisplay和layoutIfNeeded两者有什么关系?
UIView的setNeedsDisplay和setNeedsLayout两个方法都是异步执行的。而setNeedsDisplay会自动调用drawrect方法,这样可以拿到UIGraphicsGetCurrentContext进行绘制;而setNeedsLayout会默认调用layoutSubviews,给当前的视图做了标记;layoutfNeeded查找是否有标记,如果有标记会立即刷新。
只有setNeedsLayout和layoutIfNeeded这二者结合起来使用,才会起到立即刷新的效果。
4.@property的本质是什么?ivar、getter、setter是如何生成并添加到类中的?
- @property的本质是实例变量(ivar)+存取方法(getter、setter),即@property = ivar+ getter + setter;
"属性"(property)作为OC的一项特性,主要作用在于封装对象中的数据。OC对象通常会把期所需要的书就保存为各种实例变量。实例变量一般通过存取方法来访问,其中,getter方法用于读取变量值,setter方法用户写入变量值。
- ivar、getter、setter是自动合成到类中的。
完成属性定义后,编译器会自动编写访问这些属性所需要的方法,这个过程叫做“自动合成”。需要强调的是,这个过程由编译器在编译期完成,所以你编辑器里面看不到这些合成源代码。除了生成方法代码getter、setter之外,编译器还要自动向类中添加适当类型的实例变量,并在属性名前加上下划线_,以此作为实例变量的名字。也可以在类的实现代码里通过@synthesize语法来指定实例变量的名字。
5.iOS内存分区情况
- 栈区(Stack):
由编译器自动分配和释放,存放函数的参数、局部变量的值等;栈是向低地址扩展的数据结构,是一块连续的存储区域
- 堆区(Heap):
由程序员分配和释放,是向高地址扩展的数据结构,是一个不连续的内存区域。
- 全局区:
全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量是在一块区域,未初始化的全局变量和静态变量是在相邻 的另一块区域。
- 常量区:
存放常量字符串,程序结束后由系统释放。
- 代码区:
存放函数体的二进制代码
- 注:
(1)在 iOS中,堆区的内存是应用程序共享的,堆中的内存分配是由系统负责的。
(2)系统使用一个链表来为维护所有已经分配的内存空间(系统仅仅记录,比ing不管理具体的内容)
(3)变量使用结束后,需要释放内存,OC中判断引用计数是否为0,如果是0就说明没有任何变量使用该空间,那么系统将其回收。
(4)当一个APP启动后,代码区、常量区、全局区的大小就已经固定,因此指向这些区的指针不会产生崩溃性错误。而堆区和栈区是时刻变化的(堆的创建销毁,栈的入栈出栈),所以当一个指针指向这个区里的内存时,一定要注意内存是否已经被释放,否则会产生程序崩溃(野指针)。