iOS面试题总结
1.iOS开发常用的库有哪些?
这里不在叙述,超全iOS开发三方库
2.说说你熟悉的第三方框架,解释一下它的原理
例子1:SDWebImage
知识点一:
SDWebImage 加载图片的流程:
1.入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后 SDWebImageManager 根据 URL 开始处理图片。
2.
进入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交给 SDImageCache 从缓存查找图片是否已经下载 queryDiskCacheForKey:delegate:userInfo:.
3.先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。
4.SDWebImageManagerDelegate 回调 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示图片。
5.如果内存缓存中没有,生成 NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存。
6.根据 URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调 notifyDelegate:。
7.如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo:。进而回调展示图片。
8.如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调 imageCache:didNotFindImageForKey:userInfo:。
9.共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。
10.图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。
11.connection:didReceiveData: 中利用 ImageIO 做了按图片下载进度加载效果。
12. connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图片解码处理。
13.图片解码处理在一个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。
14.在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。
15.mageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。
16.
通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。
17.
将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。
18.SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。
19. SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。
20.SDWebImagePrefetcher 可以预先下载图片,方便后续使用。
知识点二:
清除缓存
cleanMemary
1、遍历缓存目录,删除所有过期图片(一周)
2、统计没有过期图片大小总和
3、判断没有过期的图片总大小是否超过缓存大小(getSize获得内存缓存大小)
4、如果超过就会删除没有过期的图片,从大到小删除
知识点三:
1.SDImageCache是怎么做数据管理的?
内存层面的相当是个缓存器,以Key-Value的形式存储图片。当内存不够的时候会清除所有缓存图片。
用搜索文件系统的方式做管理,文件替换方式是以时间为单位,剔除时间大于一周的图片文件。
当SDWebImageManager向SDImageCache要资源时,先搜索内存层面的数据,如果有直接返回,没有的话去访问磁盘,将图片从磁盘读取出来,然后做Decoder,将图片对象放到内存层面做备份,再返回调用层。
NSString *URLString = @"http://ww1.sinaimg.cn/bmiddle/bfc243a3gw1ezautzt7guj20ku0v978r.jpg"; [self.iconView sd_setImageWithURL:[NSURL URLWithString:URLString] placeholderImage:nil options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize) { /** receivedSize 前面总共接收了多少字节数 expectedSize 服务器上面文件的总大小 */ CGFloat progress = (CGFloat)receivedSize / expectedSize; //0 NSLog(@"下载进度---%f",progress); } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { }];
(2)使用SDManager来显示下载进度
//1.创建一个Manager SDWebImageManager *manager =[SDWebImageManager sharedManager]; //根据URLString去下载图片 NSString *URLString = @"http://imgsrc.baidu.com/forum/w%3D580/sign=1c9daa96dbb44aed594ebeec831d876a/9661edf81a4c510f437c4bc66159252dd52aa553.jpg"; __weak typeof(self) weakSelf = self; [manager downloadImageWithURL:[NSURL URLWithString:URLString] options:SDWebImageProgressiveDownload progress:^(NSInteger receivedSize, NSInteger expectedSize) { /** receivedSize 前面总共接收了多少字节数 expectedSize 服务器上面文件的总大小 */ CGFloat progress = (CGFloat)receivedSize / expectedSize; //0 NSLog(@"下载进度---%f",progress); } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { //NSLog(@"%@",image); weakSelf.iconView.image = image; }];
例子2:AFNetworking
AFNetworking由五个模块组成:
1.NSURLSession:网络通信模块(核心模块) 对应 AFNetworking中的 AFURLSessionManager和对HTTP协议进行特化处理的AFHTTPSessionManager,AFHTTPSessionManager是继承于AFURLSessionmanager的
2.Security:网络通讯安全策略模块 对应 AFSecurityPolicy
3.Reachability:网络状态监听模块 对应AFNetworkReachabilityManager
4.Seriaalization:网络通信信息序列化、反序列化模块 对应 AFURLResponseSerialization
5.UIKit:对于IOSUIKit的扩展库
1.AFNetworkReachabilityManager
这个是用来监控网络环境变化的类。
2.AFSecurityPolicy
网络连接安全方面
1). AFSSLPinningModeNone 代表无条件信任服务器的证书
2). AFSSLPinningModePublicKey 代表会对服务器返回的证书中的PublicKey进行验证,通过则通过,否则不通过
3). AFSSLPinningModeCertificate 代表会对服务器返回的证书同本地证书全部进行校验,通过则通过,否则不通过
3.AFURLRequestSerialization
4.AFURLResponseSerialization
5.AFURLSessionManager
AFURLSessionManager 创建并管理着NSURLSession这个对象。而NSURLSession又基于NSURLSessionConfiguration
6.AFHTTPSessionManager是AFURLSessionManager的子类,是专门为HTTP请求设计的。里面涉及到GET,POST,PUT,DELETE等等HTTPMehtod。
7.AFAutoPurgingImageCache
我们要写一个通用的网络框架,除了必备的请求数据的方法外,必须提供一个下载器来管理应用内的所有的下载事件。
8.AFImageDownloader
专门管理一组图片的下载任务
9.AFNetworkActivityIndicatorManager
对状态栏中网络**那个小控件的管理
10.UIActivityIndicatorView/UIRefreshControl/UIImageView +AFNetworking
尝试让一个控件的layer也能够加载网络图片。
11.UIButton/UIProgressView/UIWebView +AFNetworking
例子3:MJRefresh
默认情况下,如果下拉一个UIScrollView,在松手之后,会弹回初始的位置,而大部分的下拉刷新控件都是将自己放在scrollView的上方,起始y设置成负数,所以平时不会显示出来,只有下拉的时候才会出现,放开又回弹回去,然后在loading的时候,临时把contentInset增大,相当于把UIScrollView往下挤,于是下拉刷新的控件就会显示出来,然后刷新完成之后,再把contentInset改回原来的值,实现回弹的效果。3.BLOCK
知识点1: block分类,iOS中有三种block
- NSConcreteGlobalBlock; //没有用到外界变量或只用到全局变量、静态变量的block为_NSConcreteGlobalBlock,生命周期从创建到应用程序结束。
- NSConcreteStackBlock; //只用到外部局部变量、成员属性变量,且没有强指针引用的block都是StackBlock。
StackBlock的生命周期由系统控制的,一旦返回之后,就被系统销毁了。 - NSConcreteMallocBlock;//有强指针引用或copy修饰的成员属性引用的block会被复制一份到堆中成为MallocBlock,没有强指针引用即销毁,生命周期由程序员控制
默认情况下,block是存档在栈中,栈中的Block的生命周期是和栈绑定的,可能被随时回收,通过copy操作后Block才会在堆中,可以使其在堆中保留一份, 相当于一直强引用着, 因此如果block中用到self时, 需要将其弱化, 通过__weak或者__unsafe_unretained。由于_NSConcreteStackBlock所属的变量域一旦结束,那么该Block就会被销毁。在ARC环境下,编译器会自动的判断,把Block自动的从栈copy到堆。比如当Block作为函数返回值的时候,肯定会copy到堆上。
1.手动调用copy
2.Block是函数的返回值
3.Block被强引用,Block被赋值给__strong或者id类型
4.调用系统API入参中含有usingBlcok的方法
以上4种情况,系统都会默认调用copy方法把Block赋复制
知识点2:
自动变量是以值传递方式传递到Block的构造函数里面去的。Block只捕获Block中会用到的变量。由于只捕获了自动变量的值,并非内存地址,所以Block内部不能改变自动变量的值。需要对自动变量添加__bloclk;
知识点3:
Block中可以修改全局变量,全局静态变量,局部静态变量吗?答案:可以 底部原理
4.iOS事件响应链
第一个感知触摸事件的是操作系统,是他最先检测到屏幕上的压力,而不是你看上去触摸到的那个视图
2.响应链已经形成后,开始找事件的处理者,按照响应链往上回溯即可,一直回溯到application,也无人处理此事件,则将事件丢弃。
5.介绍下内存的几大区域
由地址排序(由低到高)
程序代码区----->常量区(数据区)----->全局区(静态区)----->堆区----->栈区
1.栈区(stack)
是个线程独有的,保存其运行状态和局部自动变量的,每个函数都有自己的栈,栈被用来在函数之间传递参数,栈在线程开始的时候初始化,每个线程的栈互相独立。栈区由编译器自动分配并释放,不会产生内存碎片,存放函数的参数值,局部变量等。栈是系统数据结构,对应线程/进程是唯一的。
优点是快速高效,缺点时有限制,数据不灵活。[先进后出]
栈空间分静态分配 和动态分配两种
1)静态分配是被编译器完成的,比如自动变量的分配。
2)动态是有alloca函数完成,栈的动态分配是没有释放函数的(自动释放),为程序的可移植性和内存泄漏方面不被鼓励使用。
2.堆区(heap)
堆区是大家共有的空间,分全局堆和局部堆。全局堆就是所有没有分配的空间,局部堆就是用户分配的空间。 由程序员分配和释放,容易产生内存碎片,如果程序员不释放,程序结束时,可能会由操作系统回收 ,比如在ios 中 alloc 都是存放在堆中。
优点是灵活方便,数据适应面广泛,但是效率有一定降低。
堆是函数库内部数据结构的一种,不一定唯一,不同堆分配的内存无法相互操作,堆的分配总是动态的。
3.全局区(静态区)(static)
全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量存放在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域(BSS),程序结束后有系统释放。
4.常量区(数据区)
存放常量字符串,程序结束后由系统释放。
5.程序代码区
存放函数体的二进制代码 , 程序结束后由系统释放。
注意的问题:
1.比如申请后的系统是如何响应的?
栈:存储每一个函数在执行的时候都会向操作系统索要资源,栈区就是函数运行时的内存,栈区中的变量由编译器负责分配和释放,内存随着函数的运行分配,随着函数的结束而释放,由系统自动完成。
注意:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:
1.首先应该知道操作系统有一个记录空闲内存地址的链表。
2.当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。
3 .由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。
2.申请大小的限制是怎样的?
栈:栈是向低地址扩展的数据结构,是一块连续的内存的区域。是栈顶的地址和栈的最大容量是系统预先规定好的,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数 ) ,如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
上一篇: HTTP请求中POST与GET的区别
下一篇: ios面试题总结1