[关闭]
@Rookie 2020-07-01T17:15:28.000000Z 字数 3459 阅读 723

iOS 面试题

找工作


iOS基础

讲讲你对noatomic & nonatomic的理解:

atomic与nonatomic内部实现的区别只是atomic对象setter和getter方法会加一个锁,而nonatomic并没有。

atomic和nonatomic的对比:
1、atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。
2、atomic:系统生成的 getter/setter 会保证 get、set 操作的完整性,不受其他线程影响。getter 还是能得到一个完好无损的对象(可以保证数据的完整性),但这个对象在多线程的情况下是不能确定的,比如上面的例子。
也就是说:如果有多个线程同时调用setter的话,不会出现某一个线程执行完setter全部语句之前,另一个线程开始执行setter情况,相当于函数头尾加了锁一样,每次只能有一个线程调用对象的setter方法,所以可以保证数据的完整性。
atomic所说的线程安全只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的。
3、nonatomic:就没有这个保证了,nonatomic返回你的对象可能就不是完整的value。因此,在多线程的环境下原子操作是非常必要的,否则有可能会引起错误的结果。但仅仅使用atomic并不会使得对象线程安全,我们还要为对象线程添加lock来确保线程的安全。
4、nonatomic的速度要比atomic的快。
5、atomic与nonatomic的本质区别其实也就是在setter方法上的操作不同。

总结:
所以atomic的作用只是保证了Property的原子性,在多线程环境下同时操作它时,无论何时取值,都可以取到一个完整值,但是并不能保证线程安全,具体例子参照上文。所以如果想要保证线程安全,单单把用atomic来标注是完全不够的,还需要通过上锁或其他方式老保证线程安全!

2.被weak修饰的对象在被释放的时候会发生什么?是如何实现的?知道sideTable么?里面的结构可以画出来么?

被weak修饰的对象在被释放时候会置为nil,不同于assign;

Runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组。

1、初始化时:runtime会调用objc_initWeak函数,初始化一个新的weak指针指向对象的地址。
2、添加引用时:objc_initWeak函数会调用 objc_storeWeak() 函数, objc_storeWeak() 的作用是更新指针指向,创建对应的弱引用表。
3、释放时,调用clearDeallocating函数。clearDeallocating函数首先根据对象地址获取所有weak指针地址的数组,然后遍历这个数组把其中的数据设为nil,最后把这个entry从weak表中删除,最后清理对象的记录。

struct SideTable {
// 保证原子操作的自旋锁
spinlock_t slock;
// 引用计数的 hash 表
RefcountMap refcnts;
// weak 引用全局 hash 表
weak_table_t weak_table;
}

struct weak_table_t {
// 保存了所有指向指定对象的 weak 指针
weak_entry_t *weak_entries;
// 存储空间
size_t num_entries;
// 参与判断引用计数辅助量
uintptr_t mask;
// hash key 最大偏移值
uintptr_t max_hash_displacement;
};

3.block 用什么修饰?strong 可以?

block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈上的,而不是在堆上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。因为栈区的特点就是创建的对象随时可能被销毁,一旦被销毁后续再次调用空对象就可能会造成程序崩溃,在对block进行copy后,block存放在堆区.
使用retain也可以,但是block的retain行为默认是用copy的行为实现的,
因为block变量默认是声明为栈变量的,为了能够在block的声明域外使用,所以要把block拷贝(copy)到堆,所以说为了block属性声明和实际的操作一致,最好声明为copy。

4.block 为什么能够捕获外界变量? __block做了什么事?

默认情况下,block里面的变量,拷贝进去的是变量的值,而不是指向变量的内存的指针。
使用__block修饰后的变量,拷贝到block里面的就是指向变量的指针,所以我们就可以修改变量的值。

5.谈谈你对事件的传递链和响应链的理解?

https://www.jianshu.com/p/776f9ffc2622

6.谈谈 KVC 以及 KVO 的理解?

kvc即键值编码,在iOS中的应用主要体现在开发者通过key访问对象的属性或给对象的属性赋值。这样做最主要的好处是把访问和改变属性的动作放在了运行时,不需要再编译时确定。

KVO其实是一种观察者模式,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,不过幸运的是NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO。

7.RunLoop 的作用是什么?它的内部工作机制了解么?

1.使程序一直运行并接受用户输入 程序一启动就会开一个主线程,主线程一开起来就会跑一个主线程对应的RunLoop,RunLoop保证主线程不会被销毁,也就保证了程序的持续运行。
2.决定程序在何时应该处理哪些Event 比如:触摸事件,定时器事件,Selector事件等。
3.节省CPU时间 程序运行起来时,什么操作都没有做的时候,RunLoop就告诉CPU,现在没有事情做,我要去休息,这时CPU就会将其资源释放出来去做其他的事情,当有事情做的时候RunLoop就会立马起来去做事情。

8.可以说几个重构的技巧么?你觉得重构适合什么时候来做?

重复代码的提炼
冗长方法的分割
嵌套条件分支的优化
去掉一次性的临时变量
消除过长参数列表
提取类或继承体系中的常量
让类提供应该提供的方法
拆分冗长的类
提取继承体系中重复的属性与方法到父类

作者:玉思盈蝶
链接:https://www.jianshu.com/p/ba1196fbaaa4
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Runtime

2:谈谈三次握手,四次挥手!为什么是三次握手,四次挥手?
3:socket 连接和 Http 连接的区别
4:什么时候POP网路,有了 Alamofire 封装网络 URLSession为什么还要用Moya ?
5:如何实现 dispatch_once
6:能否写一个读写锁?谈谈具体的分析
7:什么时候会出现死锁?如何避免?
8:有哪几种锁?各自的原理?它们之间的区别是什么?最好可以结合使用场景来说

数据结构

1.数据结构的存储一般常用的有几种?各有什么特点?
2.集合结构 线性结构 树形结构 图形结构
3.单向链表 双向链表 循环链表
4.数组和链表区别
5.堆、栈和队列
6.输入一棵二叉树的根结点,求该树的深度?
7.输入一课二叉树的根结点,判断该树是不是平衡二叉树?

算法

1.时间复杂度
2.空间复杂度
3.常用的排序算法
4.字符串反转
5.链表反转(头差法)
6.有序数组合并
7.查找第一个只出现一次的字符(Hash查找)
8.查找两个子视图的共同父视图
9.无序数组中的中位数(快排思想)
10.给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。

架构设计

1:设计模式是为了解决什么问题的?
2:看过哪些第三方框架的源码,它们是怎么设计的?
3:可以说几个重构的技巧么?你觉得重构适合什么时候来做?
4:开发中常用架构设计模式你怎么选型?
5:你是如何组件化解耦的?

性能优化

1:tableView 有什么好的性能优化方案?
2: 界面卡顿和检测你都是怎么处理?
3:谈谈你对离屏渲染的理解?
4:如何降低APP包的大小
5:日常如何检查内存泄露?
6:APP启动时间应从哪些方面优化?

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注