- 多线程有哪几种,常见的应用场景
- SDWebImage的原理和实现机制
- 事件的传递和响应机制
- UITableView的卡顿优化
- ARC原理以及和MRC区别及autoreleasePool的原理
- block、代理、通知的区别,block的用法需要注意些什么
- @property有哪些属性,它们的区别和作用
- 浅拷贝和深拷贝
- static关键字的作用
- 线程和进程的区别和联系
- 堆和栈的区别
- objc的内存管理
- 动态绑定
- ViewController的生命周期
- OC和Swift的区别和联系,各自的优缺点
- 类别、继承、扩展的区别、优缺点
- KVO和KVC
- 数据持久化方式
- 循环引用出现的场景
- 运行时机制的原理和应用场景
- Core Audio和Audio Queue、AVPlayer视频播放(http://sky-weihao.github.io/2015/10/06/Video-streaming-and-caching-in-iOS/)
- React Native
- Html5
- 沙盒机制
- 单例的写法,在单例中创建数组应该注意什么
- git和svn的简单用法以及简单的几个命令
- 友盟报错可以查看到某一行的错误,原理是什么
- 请求服务器的方式,它们之间的区别是什么
- Instruments检测电池电量和内存消耗的用法
- 自定义过的控件
- __block和__weak修饰符的区别
- UIResponder的继承链
- Http常见状态码
- frame和bounds
- nil、Nil、NULL区别
- TCP和UDP区别和联系
- Socket建立网络连接的步骤
- 防止指针越界问题
- sprintf,strcpy,memcpy使用上有什么要注意的地方
- 链表与数组的区别与联系
*多线程有哪几种,常见的应用场景
Pthreads、NSTread、GCD、NSOperation
- Pthreads:Posix threads,是线程的POSIX标准。该标准定义了创建和操纵线程的一整套API,适用于类Unix操作系统。是基于C语言的框架。手动管理线程的生命周期。
- NSTread:完全面向对象的,需手动管理线程的生命周期(一般用于调试,[NSTread currentTread]可获取当前线程类,从而获知当前线程的各种属性)。
- GCD:Grand Central Dispatch,苹果为多核的并行运算提出的解决方案,所以会自动合理的利用更多的CPU内核,可自动管理线程的生命周期(创建线程、调度任务、销毁线程)。它使用的也是c语言,但是使用了block,所以使用起来很方便、而且灵活。
任务有两种执行方式:同步和异步(是否阻塞当前线程)
主队列用于刷新UI,一般耗时的任务都要放到别的线程执行 - NSOperation和NSOperationQueue:将要执行的任务封装到一个NSOPeration(NSInvocationOperation或NSBlockOperation或自定义继承NSOperation类的Operation并实现其main和cancel方法)对象中,然后添加到NSOperationQueue中。
* SDWebImage的原理和实现机制
- 先把placeholder Image显示,然后SDWebImageManager根据URL开始处理图片;
- 接着从缓存查找图片是否已经下载,如果已下载则通过代理回调到前端展示图片;
- 如果内存缓存中没有,生成NSInvocationOperation添加到队列中开始查找硬盘中是否已经缓存,如果读取到了图片将图片添加到缓存中,进而回调展示图片;
- 否则需要由SDWebImageDownloader下载图片,NSURLConnection来做,下载完后交给SDWebImageDecoder做图片解码处理(是在NSOperationQueue中处理,如果需要对图片二次处理也在这里完成,效率会好很多),然后通知所有的下载代理下载完成,回调给需要展示的地方展示;
- 将图片保存到SDImageCache中,内存缓存和硬盘缓存同时保存。写文件时也以单独的NSInvocationOperation完成,避免拖慢主线程;
SDImageCache初始化时会注册一些消息通知,在内存警告或退到后台时清理内存图片缓存,应用结束的清理过期图片。
* 触摸事件的传递和响应者链机制
1、触摸事件的传递
- 发生触摸事件后,系统会将该事件加入到一个UIApplication管理的事件队列
- UIApplication会从事件队列中取出最前面的事件,先发送给应用程序的主窗口keyWindow
- 主窗口会在视图层级结构中找到一个最合适的视图来处理触摸事件,找到合适的视图控件,会调用touches方法作具体的事件处理
- 事件的传递即:产生触摸事件->UIApplication事件队列->[UIWindow hitTest:withEvent:]->返回更合适的view->[子控件 hitTest:withEvent:]->返回最合适的view
- 如何找到最合适的控件来处理事件:
1)首先判断主窗口自己能否接受触摸事件
2)判断触摸点是否在自己身上
3)子控件数组中从后往前遍历子控件,遍历时重复步骤1)、2)
4)找到fitview以后,把事件交给这个fitview,再遍历这个fitview的子控件,直至没有更合适的view为止
5)如果没有符合条件的子控件,那么就认为自己是最合适的view - UIView不能接收触摸事件的三种情况(UIImageView默认不允许交互,可设置成可交互):
1)不允许交互:userInteractionEnabled = NO
2)隐藏:如果父控件隐藏,那么子控件也会隐藏
3)透明度:如果设置一个控件的透明度<0.01(透明),会直接影响子控件的透明度
*寻找最合适的view底层剖析
两个重要方法:
hitTest:withEvent:方法(事件传递给该控件时调用,可重写该方法,返回指定view作为合适的view作为拦截事件的处理->建议在父控件的hitTest:withEvent:中返回子控件作为最合适的view)
pointInside方法 判断点是否在当前view上
2、响应者链
- 响应者链的事件传递过程
1)如果当前view是控制器的view,那么控制器就是上一个响应者,事件就传递给控制器;否则父视图就是上一响应者,事件就传递给它的父视图
2)如果视图层级的最顶级视图也不能处理收到的事件或消息,则将事件或消息传递给UIWindow对象进行处理
3)再者就要传递给UIApplication对象
4)如果UIApplication也不能处理该事件或消息,则将其丢弃
3、事件处理的整个流程总结:
1)触摸屏幕产生触摸事件后,触摸事件会被添加到由UIApplication管理的事件队列中(即,首先接收到事·件的是UIApplication)。
2)UIApplication会从事件队列中取出最前面的事件,把事件传递给应用程序的主窗口(keyWindow)。
3) 主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件。(至此,第一步已完成)
4)最合适的view会调用自己的touches方法处理事件
5)touches默认做法是把事件顺着响应者链条向上抛。
* ARC原理以及和MRC区别及autoreleasePool的原理
- ARC即自动引用计数,由编译器在程序需要的地方自动加入retain/release,不需要手动管理内存(iOS5/Mac OSX 10.7开始引入)
- MRC即手动管理内存,自己负责系统变量的release和retain操作,做到谁分配谁释放,alloc/retain要和release的数量相对应。函数返回对象时要autorelease
- autoreleasePool:调用autorelease的对象会加入自动释放池中,等到自动释放池drain时,池中变量收到release消息
* UITableView的卡顿优化
- cell的重用
- 避免cell的重新布局,可将cell单独放到一个自定义类,初始化时就布局好
- 提前计算并缓存cell的属性及内容
- 背景色不要使用clearcolor,透明度也不要设置为0(渲染耗时长)
- 刷新的尽量更新局部,reloadsection
- 加载网络数据或图片的时候使用异步加载,并缓存
- 按需加载,cell滚动很快时,只加载最终显示范围内的cell
- 不用实现无用的代理,tableView只遵守两个协议
- 缓存行高:estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同时存在,这两者同时存在才会出现“窜动”的bug。所以我的建议是:只要是固定行高就写预估行高来减少行高调用次数提升性能。如果是动态行高就不要写预估方法了,用一个行高的缓存字典来减少代码的调用次数即可
- Instrument里的Core animation逐项检查,滑动时的帧数等等
* block、代理、通知的区别,block的用法需要注意些什么
- 代理是一对一的关系,并且接收方可以给发送方返回值
*通知是一对多的关系,且接收方不可给发送方返回值
@property有哪些属性,它们的区别和作用
- 原子性
- 读写权限
- 方法名getter==<name>、setter==<name>属性
- 内存管理语义
- copy是复制的内容,保持属性不受外界影响,不论传入的是可变对象还是不可变对象,本身持有的都是不可变的副本
* 浅拷贝和深拷贝
- 对集合类对象的copy操作:copy是指针拷贝,mutableCopy是内容拷贝,此处的内容拷贝,数组中的元素依旧是指针拷贝
- 对非集合类对象的copy操作:对 immutable 对象进行 copy 操作,是指针复制,mutableCopy 操作时内容复制;对 mutable 对象进行 copy 和 mutableCopy 都是内容复制
* static关键字的作用
- 作用于变量:用static声明局部变量,使其变为静态存储方式(静态数据区),作用域不变;用static声明外部变量,其本身就是静态变量,这只会改变其连接方式,使其只在本文件内部有效,而其他文件不可连接或引用该变量。
- 作用于函数:对函数的连接方式产生影响,使得函数只在本文件内部有效,对其他文件是不可见的。这样的函数又叫作静态函数。使用静态函数的好处是,不用担心与其他文件的同名函数产生干扰,另外也是对函数本身的一种保护机制。使用extern关键字,表示该函数是外部函数,可供其他文件调用
- const修饰变量是表示它修饰的变量值是不可变的。
将const改为外部连接,作用于扩大至全局,编译时会分配内存,并且可以不进行初始化,仅仅作为声明,编译器认为在程序其他地方进行了定义( extend const int ValueName = value)
* 线程和进程的区别和联系
- 线程和进程都是操作系统中程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性
- 不同的操作系统资源管理方式,进程有自己独立的地址空间,一个进程崩溃后,在保护模式下,其他进程不会受到影响。而线程只是进程中的不同执行路径,线程有自己的堆栈和局部变量,但线程之间没有独立的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
* 堆和栈的区别
- 堆:手动管理生命周期,地址区块由低地址向高地址扩展,且可不连续,获得空间比较灵活也比较大
- 栈:编译器自动管理,由高地址向低地址扩展且连续,编译时已申请好内存区块的大小
* objc的内存管理
- 谁分配和初始化创建了对象,谁就拥有了该对象,从而也要负责该对象的释放
- 如果拷贝了一个对象,就拥有了拷贝得到的对象,要负责释放该对象
- 如果保持了一个对象,则在不需要的时候释放改对象
*动态绑定
- 动态绑定将调用方法的确定也推迟到运行时
* ViewController的生命周期
-init-loadView-viewDidload-viewWillAppear-viewWillLayoutSubviews-viewDidLayoutSubviews-viewDidAppear-viewWillDisappear-viewDidDisappear-viewWillUnload-viewDidUnload-dealloc
* OC和Swift的区别和联系,各自的优缺点
Swift:没有main函数,程序自上而下执行;没有分号;类型自行推断,只有常量和变量之分;BOOL值类型更严格,不再是OC的非0就是真,Swift的true才是真,false是假;可以多对多赋值;if语句必须要有大括号;一个类只有一个文件;有溢出运算符,防止数据溢出;元祖类型var point = (x:15,y:20.2);
代码简洁高效,开发效率高
高级的语法特性(类型推断、泛型、函数式语言特性、闭包)-
OC :objc优缺点:
- Cateogies
- Posing
- 动态识别
- 指标计算
5)弹性讯息传递 - 不是一个过度复杂的 C 衍生语言
- Objective-C 与 C++ 可混合编程
缺点: - 不支持命名空间
- 不支持运算符重载
3)不支持多重继承
4)使用动态运行时类型,所有的方法都是函数调用,所以很多编译时优化方法都用不到。(如内联函数等),性能低劣。
* 数据持久化方式
文件写入、数据库、Core Data、对象归档
* 循环引用出现的场景
计时器、block、delegate
* 运行时机制的原理和应用场景
*类别中动态添加属性
*获取对象的成员列表,通过kvc将数据转模型
*交换方法:在AFNetworking中,替换了NSURLSession resume,每次发送网络请求的时候,都会发送通知,截取信息。
* React Native
用javascript去写iOS的原生应用
*优点是:Native不用WebView,彻底摆脱了WebView让人不爽的交互和性能问题;
Native的原生控件有更好的体验;
Native有更好的手势识别;
Native有更适合的线程模型;
缺点是:还在试用阶段,潜在的问题尚不得而知:兼容性问题,性能问题等。还没大量普及,学习资料尚且不多,供爱折腾的朋友尝尝鲜。沙盒机制
Document、Library、tmpDocument:用于存储用户数据。iTunes备份和恢复的时候会包括此目录。程序中建立的或在程序中浏览到的文件数据
*Library:caches:用户需要缓存的文件;preferences:App的偏好设置,可通过NSUserDefaults读取和设置
*保存一些退出应用就可清除的数据
* Http常见状态码
- 302请求重定向
- 500以上服务器错误
- 400以上请求链接错误或找不到服务器
- 200以上请求成功
- 100以上是请求接受成功
*友盟报错可以查看到某一行的错误,原理是什么
dSYM UUID,这个是dSYM文件的唯一标识。dSYM 是保存 16 进制函数地址映射信息的中转文件,我们调试的 symbols 都会包含在这个文件中,并且每次编译项目的时候都会生成一个新的 dSYM 文件。根据内存地址找到对应的代码
*git和svn的简单用法以及简单的几个命令
- git clone、git pull、git log、git branch
*TCP和UDP区别和联系
- 即传输层协议
- TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
- UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快。
- TCP是一种流模式的协议,UDP是一种数据包模式的协议。
*Socket建立网络连接的步骤
socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
*数据库,数据迁移
realm,只要表的结构有变化,把当前的数据库版本加1,realm会根据schemaVersion自动迁移数据
*局部变量、实例变量的释放时机
- 局部变量出了方法就会被释放
- 实例变量取决于指向它的指针,如果没有强引用指针指向它,页面被销毁后指针被销毁,对象随之释放
*推送的原理
- 客户端把udid和bundleid发送给苹果的apns服务器,服务器生成一个deviceToken返回给客户端,客户端把deviceToken传给我们的后台服务端,服务端把deviceToken存储到数据库里,一旦有新的信息需要推送,后台服务端就会去数据库查询该deviceToken的信息,通知apns服务器给该deviceToken发送什么样的信息,apns服务器根据deviceToken找到这台设备并推送通知
*setNeedsLayout和layoutIfNeeded
setNeedsLayout:标记为需要重新布局,异步调用layoutIfNeeded,在下一轮runloop结束前刷新所有的布局和UI上的更新。
layoutIfNeeded:如果有标记,立即调用layoutSubviews进行布局,如果没有则不会调用layoutSubviews