2019-02-15

2019-02-20  本文已影响0人  蚂蚁揍蜗牛

1.http请求方式?

1.HTTP的请求方式有3种,分别是:POST、GET、HEAD。POST和GET方法是用于数据发送的。
2.POST:它将要发送的数据单独放在一个流中进行发送,
而不是附加在URL地址后面,好处是这些数据不会出现在URL地址中。
3.GET:它将要发送的数据直接添加在URL后面,
这样的好处是可以直接将数据加在URL后,而不需在用另外的流来发送这些数据,
但是缺点也显而易见,它将用户的信息显示出来了。
4.HEAD:它是请求资源的元数据方法。在具体的应用中,我暂时还没遇到过,

2.socket编程简述

1.socket是基于TCP/IP的协议,Socket可以支持数据的发送和接收,
它会定义一种称为套接字的变量,发送数据时首先创建套接字,
然后使用该套接字的sendto等方法对准某个IP/端口进行数据发送;
接收端也首先创建套接字,然后将该套接字绑定到一个IP/端口上,
所有发向此端口的数据会被该套接字的recv等函数读出。如同读出文件中的数据一样。
2.TCP/IP的socket提供下列三种类型套接字。 流式套接字、数据报式套接字、原始式套接字。
3.客户端编程步骤:
3.1.加载套接字库,创建套接字(WSAStartup()/socket());
3.2.向服务器发出连接请求(connect());
3.3.和服务器端进行通信(send()/recv());
3.4.关闭套接字,关闭加载的套接字库(closeSocket()/WSACleanup())。

3.App需要加载超大量的数据,给服务器发送请求,但是服务器卡住了如何解决?

1.设置超时时间
2.给用户提示请求超时
3.根据用户操作再次请求数据

4.HTTP的通信的 发送请求、接收响应 包含哪些内容?OC中是怎样实现的?

1.一个请求包含如下内容:
1.1.请求头:包含了对客户端的环境描述、客户端请求的主机地址等信息
1.2.包含了请求方法、请求资源路径、HTTP协议版本
1.3.客户端发给服务器的具体数据,比如文件数据
2.一个响应包括:
2.1.状态行:包含了HTTP协议版本、状态码、状态英文名称 HTTP/1.1 200 OK
2.2.响应头:包含了对服务器的描述、对返回数据的描述
2.3.实体内容:服务器返回给客户端的具体数据,比如文件数据

5.什么是三次握手与四次挥手?

1.三次握手实现的过程:
第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),
同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包
ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

2.四次挥手:

第一次: 客户端向服务器发送一个带有结束标记的报文。
第二次:服务器收到报文后,向客户端发送一个确认序号,同时通知自己相应的应用程序:对方要求关闭连接
第三次: 服务器向客户端发送一个带有结束标记的报文。
第四次: 客户端收到报文后,向服务器发送一个确认序号。链接关闭。

6.分析json、xml的区别?json、xml解析方式的底层是如何处理的?

1. json与xml的区别:
可读性方面:基本相同,xml的可读性比较好
可扩展性方面:都具有很好的扩展性
编码难度方面:相对而言:JSON的编码比较容易
解码难度:json的解码难度基本为零,xml需要考虑子节点和父节点
数据体积方面:json相对于xml来讲,数据体积小,传递的速度跟快些
数据交互方面:json与JavaScript的交互更加方面,更容易解析处理,更好的数据交互
数据描述方面:xml对数据描述性比较好
传输速度方面:json的速度远远快于xml

2.JSON底层原理:
遍历字符串中的字符,最终根据格式规定的特殊字符,比如{}号,[]号, : 号 等进行区分,
{}号是一个字典 的开始,[]号是一个数组的开始, : 号是字典的键和值的分水岭,
最终乃是将json数据转化为字典,字典中值可能是字典,数组,或字符串而已。

3.XML底层原理:
XML解析常用的解析方法有两种:DOM解析和SAX解析。
DOM 采用建立树形结构的方式访问 XML 文档,而 SAX 采用的事件模型。
DOM 解析把 XML 文档转化为一个包含其内容的树,并可以对树进行遍历。
使用 DOM 解析器的时候需 要处理整个 XML 文档,所以对性能和内存的要求比较高。
SAX在解析 XML 文档的时候可以触发一系列的事件,当发现给定的tag的时候,
它可以激活一个回调方法,告诉该方法制定的标签已经找到。
SAX 对内存的要求通常会比较低,因为它让开发人员自己来决定所要处理的tag。
特别是当开发人员只需要处理文档中所包含的部分数据时,SAX 这种扩展能力得到了更好的体现。

4.HTTP协议的组成和特性?

1.http 请求由三部分组成,分别是:请求行、消息报头、请求正文.
2.HTTP协议的主要特点可概括如下:
2.1.支持客户/服务器模式。
2.2.简单快速:客户向服务器请求服务时,只需传送请求方法和路径。方法有 GET、HEAD、POST。
每种方法规定了客户与服务器联系的类型不同。由于 HTTP 协议简单,
使得 HTTP 服务器的程序规模小,因而通信速度很快。
2.3.灵活:HTTP 允许传输任意类型的数据对象。正在传输的类型由 Content-Type 加以标记
2.4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,
并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间
2.5..无状态:HTTP 协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。
缺少状态意味着如果后续处理需要前面的信息,则它必须重传,
这样可能导致每次连接传送的数据量增大。另一方面,
在服务器不需要先前信息时它的应答就较快。
  1. TCP/UDP 区别?
TCP: 是传输控制协议:是面连接的,那么运行环境必然要求其可靠性不可丢包有
良好的拥塞控制机制如http ftp telnet 等
UDP: 是用户数据报协议: 主要用在实时性要求高以及对质量相对较弱的地方,
但面对现在高质量的线路不是容易丢包除非是一些拥塞条件下, 如流媒体

6.http和scoket通信的区别?socket连接相关库,TCP,UDP的连接方法,HTTP的几种常用方式?

1.http和scoket通信的区别:
http是客户端用http协议进行请求,发送请求时候需要封装http请求头,并绑定请求
的数据,服务器一般有web服务器配合(当然也非绝对)。 http请求方式为客户端
主动发起请求,服务器才能给响应,一次请求完毕后则断开连接,以节省资源。服
务器不能主动给客户端响应(除非采取http长连接技术)。

scoket是客户端跟服务器直接使用socket“套接字”进行连接,并没有规定连接后
断开,所以客户端和服务器可以保持连接通道,双方都可以主动发送数据。一般在
游戏开发或股票开发这种要求即时性很强并且保持发送数据量比较大的场合使
用。主要使用类是CFSocketRef。

7.卡顿优化

1.在CPU层次:
1.1.尽量用轻量级的对象,比如用不到事件处理的地方,可以考虑使用CALayer取代UIView
1.2.尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性
1.3.Autolayout会比直接设置frame消耗更多的CPU资源
1.4.图片的size最好刚好跟UIImageView的size保持一致
1.5.控制一下线程的最大并发数量
1.6.尽量把耗时的操作放到子线程:文本处理(尺寸计算、绘制),图片处理(解码、绘制)

2.GPU层次:
2.1.尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示
2.2.GPU能处理的最大纹理尺寸是4096x4096,一旦超过这个尺寸,就会占用
CPU资源进行处理,所以纹理尽量不要超过这个尺寸
2.3.尽量减少视图数量和层次
2.4.减少透明的视图(alpha<1),不透明的就设置opaque为YES
2.5.尽量避免出现离屏渲染

关于离屏渲染:
GPU有2种渲染方式,当前屏幕渲染:在当前用于显示的屏幕缓冲区进行渲染操作,
离屏渲染:在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作

离屏渲染消耗性能的原因:需要创建新的缓冲区,离屏渲染的整个过程,需要
多次切换上下文环境,先是从当前屏幕(On-Screen)切换到离屏(Off-
Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,
又需要将上下文环境从离屏切换到当前屏幕

哪些操作会触发离屏渲染?
1.光栅化: layer.shouldRasterize = YES
2.遮罩: layer.mask
3.圆角:同时设置layer.masksToBounds = YES、layer.cornerRadius大于0
4.阴影,layer.shadowXXX ,如果设置了layer.shadowPath就不会产生离屏渲染
  1. APP的启动流程
APP启动分为两种:
冷启动:从零开始启动app
热启动:APP已经在内存中,在后台存活着,再次点击图标启动APP
app启动时间的优化主要针对 冷启动进行优化

app冷启动 可以概括为3大类,dyld,runtime,main
1.dyld:app的动态链接器,可以装载Mach-o文件(可执行文件,动态库)
1.2.启动app时,dyld所做的事情有:
1.2.1.装载app的可执行文件,同时递归加载所有依赖的动态库。
1.2.2.当dyld把可执行文件和动态库加载完毕,会通知runtime进行下一步处理。

2.app启动-runtime所做的事:
2.1.调用map_images进行可执行文件内容的解析和处理。
2.2.在load_images中调用 call_load_methods,调用Class和Category的+load方法。
2.3.进行各种objc结构的初始化。(注册objc类,初始化类对象)
2.4.调用C++静态初始化器和attribute((constructor))修饰的函数
2.5.到此为止,可执行文件和动态库中所有的符号(Class,Protocol,
Selector,IMP,…)都已经按格式成功加载到内存中,被runtime 所管理

3.app启动-main()的事情
3.1.APP的启动由dyld主导,将可执行文件加载到内存,顺便加载所有依赖的动态库
3.2.runtime负责加载成objc定义的结构
3.3.所有初始化工作结束后,dyld就会调用main函数
3.4.UIApplicationMain函数,AppDelegate的
application:didFinishLaunchingWithOptions:方法

9.APP的启动优化

1.dyld阶段:
1.1.减少动态库、合并一些动态库(定期清理不必要的动态库)
1.2.减少Objc类、分类的数量、减少Selector数量(定期清理不必要的类、分类)
1.3.减少C++虚函数数量

2.runtime阶段:
2.1.用+initialize方法和dispatch_once取代所有的attribute((constructor))、
C++静态构造器、ObjC的+load

3.main()阶段
3.1.在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部都放在
finishLaunching方法中。
3.2.资源的按需加载。

10.安装包瘦身

1.安装包主要由 可执行文件和资源组成
2.资源主要包含,图片,音频,视频,采取无损压缩的方式压缩资源。去除无效的资源。
3.可执行文件瘦身:
3.1.编译器优化:Strip Linked Product、Make Strings Read-Only、
Symbols Hidden by Default等参数设置为YES
3.2.去掉异常支持,Enable C++ Exceptions、Enable Objective-C Exceptions
设置为NO, Other C Flags添加-fno-exceptions
3.3.检测出重复代码、未被调用的代码

11.iOS提升性能

1. 在正确的地方使用reuseIdentifier
为了性能最优化,UICollectionViewCell和UITableViewCell应该使用标识符进行复用,
也应该在header和footer views中使用reuseIdentifiers。

2. 尽可能使Views透明
如果你有透明的Views你应该设置它们的opaque(不透明)属性为YES。(opaque)
这个属性给渲染系统提供了一个如何处理这个view的提示。如果设为YES, 渲
染系统就认为这个view是完全不透明的,这使得渲染系统优化一些渲染过程和
提高性能。如果设置为NO,渲染系统正常地和其它内容组成这个View。默认值
是YES。,如果一个图层是完全不透明的,则系统直接显示该图层的颜色即可。而
如果图层是带透明效果的,则会引入更多的计算,因为需要把下面的图层也包括进
来,进行混合后颜色的计算。

3.避免过于庞大的XIB
加载一个XIB的时候所有内容都被放在了内存里,包括任何图片。如果有一个不
会即刻用到的view,你这就是在浪费宝贵的内存资源了。

4. 不要阻塞主线程
UIKit在主线程上做所有工作,渲染,管理触摸反应,回应输入等都需要在它上
面完成。如果你的代码真的阻塞了主线程,app会失去反应,大部分阻碍主进程
的情形是app在做一些牵涉到读写外部资源的I/O操作,比如存储或者网络。或
者使用像 AFNetworking这样的框架来异步地做这些操作。
如果你需要做其它类型的需要耗费巨大资源的操作(比如时间敏感的计算或者存
储读写)那就用 Grand Central Dispatch,或者 NSOperation 和 
NSOperationQueues.

5. 在Image Views中调整图片大小
如果要在UIImageView中显示一个来自bundle的图片,你应保证图片的大小和
UIImageView的大小相同。在运行中缩放图片是很耗费资源的,特别是
UIImageView嵌套在UIScrollView中的情况下。
如果图片是从远端服务加载的你不能控制图片大小,比如在下载前调整到合适
大小的话,你可以在下载完成后,最好是用background thread,缩放一次,然
后在UIImageView中使用缩放后的图片。

6. 选择正确的Collection
Arrays: 有序的一组值。使用index来lookup很快,使用value lookup很慢, 插入/删除很慢。
Dictionaries: 存储键值对。 用键来查找比较快。
Sets: 无序的一组值。用值来查找很快,插入/删除很快。

7. 打开gzip压缩
大量app依赖于远端资源和第三方API,你可能会开发一个需要从远端下载XML, 
JSON, HTML或者其它格式的app。减小文档的一个方式就是在服务端和你的
app中打开gzip。这对于文字这种能有更高压缩率的数据来说会有更显著的效
用。好消息是,iOS已经在NSURLConnection中默认支持了gzip压缩,当然
AFNetworking这些基于它的框架亦然。

8. 重用和延迟加载Views

9. Cache, Cache, 还是Cache!
缓存所需要的,也就是那些不大可能改变但是需要经常读取的东西。
比如远端服务器的响应,图片,甚至计算结果,比如UITableView的行高。
NSCache和NSDictionary类似,不同的是系统回收内存的时候它会自动删掉它的内容。

10. 权衡渲染方法
11. 处理内存警告

12. 重用大开销的对象
一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。然而,你又
不可避免地需要使用它们,比如从JSON或者XML中解析数据。
想要避免使用这个对象的瓶颈你就需要重用他们,可以通过添加属性到你的
class里或者创建静态变量来实现。

13. 避免反复处理数据
许多应用需要从服务器加载功能所需的常为JSON或者XML格式的数据。在服
务器端和客户端使用相同的数据结构很重要。在内存中操作数据使它们满足你
的数据结构是开销很大的。比如你需要数据来展示一个table view,最好直接从服
务器取array结构的数据以避免额外的中间数据结构改变。类似的,如果需要从
特定key中取数据,那么就使用键值对的dictionary。

14. 选择正确的数据格式(JSON还是XML)
15. 正确地设定Background Images
在View里放背景图片使用UIColor的 colorWithPatternImage来设置背景色;
如果你使用全画幅的背景图,你就必须使用UIImageView因为UIColor的
colorWithPatternImage是用来创建小的重复的图片作为背景的。这种情形下使
用UIImageView可以节约不少的内存:
如果你用小图平铺来创建背景,你就需要用UIColor的colorWithPatternImage来
做了,它会更快地渲染也不会花费很多内存:

16. 减少使用Web特性
UIWebView很有用,用它来展示网页内容或者创建UIKit很难做到的动画效果是
很简单的一件事。UIWebView并不像驱动Safari的那么快,想要更高的性能你
就要调整下你的HTML了。第一件要做的事就是尽可能移除不必要的
javascript,避免使用过大的框架。能只用原生js就更好了。另外,尽可能异步
加载例如用户行为统计script这种不影响页面表达的javascript。

17. 设定Shadow Path
使用shadow path的话iOS就不必每次都计算如何渲染,它使用一个预先计算好
的路径。但问题是自己计算path的话可能在某些View中比较困难,且每当view
的frame变化的时候你都需要去update shadow path.

18. 优化你的Table View
为了保证table view平滑滚动,确保你采取了以下的措施:
正确使用reuseIdentifier来重用cells
尽量使所有的view 不透明(opaque),包括cell自身
避免渐变,图片缩放,
缓存行高
如果cell内现实的内容来自web,使用异步加载,缓存请求结果
使用shadowPath来画阴影
减少subviews的数量
尽量不使用cellForRowAtIndexPath:,如果你需要用到它,只用一次然后缓存结果
使用正确的数据结构来存储数据
尽量使用rowHeight, sectionFooterHeight 和 sectionHeaderHeight来设定固定
的高,不要请求delegate。

19. 选择正确的数据存储选项
NSUserDefaults它只适用于小数据,比如一些简单的布尔型的设置选项。
XML这种结构化档案需要读取整个文件到内存里去解析,这样是很不高效的。
使用SAX又是一个很麻烦的事情。
NSCoding也需要读写文件,所以效率也不是很好。
当存储大块数据时,以上的方法都不适用. 在这种应用场景下,使用SQLite 或者 Core Data比较好。

20. 加速启动时间
尽可能做更多的异步任务,比如加载远端或者数据库数据,解析数据。
避免过于庞大的XIB,因为他们是在主线程上加载的。
减少或者合并动态库。

21. 使用Autorelease Pool
NSAutoreleasePool负责释放block中的autoreleased objects。一般情况下它会
自动被UIKit调用。但是有些状况下你也需要手动去创建它。
假如你创建很多临时对象,你会发现内存一直在减少直到这些对象被release的
时候。这是因为只有当UIKit用光了autorelease pool的时候memory才会被释
放。
好消息是你可以在你自己的@autoreleasepool里创建临时的对象来避免这个行
为:
    NSArray *urls = <# An array of file URLs #>;
    for(NSURL *url in urls) {
        @autoreleasepool {
            NSError *error;
            NSString *fileContents = [NSString stringWithContentsOfURL:url
                              encoding:NSUTF8StringEncoding error:&error];

       }
    }

22. 选择是否缓存图片
常见的从bundle中加载图片的方式有两种,一个是用imageNamed,二是用
imageWithContentsOfFile,第一种比较常见一点。imageNamed的优点是当加
载时会缓存图片。imageWithContentsOfFile仅加载图片。如果你要加载一个大
图片而且是一次性使用,那么就没必要缓存这个图片,用
imageWithContentsOfFile足矣,这样不会浪费内存来缓存它。
然而,在图片反复重用的情况下imageNamed是一个好得多的选择。

23. 尽量避免日期格式转换

12.KVO、KVC 是什么,各自底层的实现原理?

KVC底层原理:
 当一个对象调用setValue:forKey: 方法时,方法内部会做以下操作:
 1.判断有没有指定key的set方法,如果有set方法,就会调用set方法,给该属性赋值
 2.如果没有set方法,判断有没有跟key值相同且带有下划线的成员属性(_key).如果有,直接给该成员属性进行赋值
 3.如果没有成员属性_key,判断有没有跟key相同名称的属性.如果有,直接给该属性进行赋值
 4.如果都没有,就会调用 valueforUndefinedKey 和setValue:forUndefinedKey:方法
KVO 的底层实现原理:
1.KVO 是基于 runtime 机制实现的
2.当一个对象(假设是person对象,对应的类为 JLperson)的属性值age发
生改变时,系统会自动生成一个继承自JLperson的类NSKVONotifying_JLPerson,
在这个类的 setAge 方法里面调用
    [super setAge:age];
    [self willChangeValueForKey:@"age"];
    [self didChangeValueForKey:@"age"];
 三个方法,而后面两个方法内部会主动调用
 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
方法,在该方法中可以拿到属性改变前后的值.

13.消息转发机制原理?

消息发送和转发流程可以概括为:消息发送(Messaging)是 Runtime 
通过 selector 快速查找 IMP 的过程,有了函数指针就可以执行对应的
方法实现;消息转发(Message Forwarding)是在查找 IMP 失败后执
行一系列转发流程的慢速通道,如果不作转发处理,则会打日志和抛出异常。

14.说说你理解的weak属性,什么情况下使用 weak 关键字,相比 assign 有什么不同??

1.weak只能用于修饰对象类型,基本数据类型不能使用
2.assign修饰对象和基本数据类型都可以,但是只是简单地进行赋值操作而已
注意:assign修饰的对象,在释放之后,指针的地址还是存在的,也就
是说指针并没有被置为nil,造成野指针。对象一般分配在堆上的某块内
存,如果在后续的内存分配中,刚好分到了这块地址,程序就会崩溃。
weak修饰的对象在释放之后,指针地址会被置为nil。所以现在一般弱
引用就是用weak。

15.项目中网络层如何做安全处理?

1.判断API的调用请求是否来自于经过授权的APP。如若不是则拒绝请求访问
2.在数据请求的过程中进行URL加密处理:防止反编译,接口信息被静态分析。
3.数据传输加密:对客户端传输数据提供有效的加密方案,以防止网络接口的拦截。
4.尽量使用HTTPS,可以有效的避免接口数据在传输中被攻击。

16.main()之前的过程有哪些?

1.dyld 开始将程序二进制文件初始化
2.交由Image_loader 读取 image,其中包含了我们的类,方法等各种符号
(Class、Protocol 、Selector、 IMP)
3.由于runtime 向dyld 绑定了回调,当image加载到内存后,dyld会通知runtime进行处理
4.runtime 接手后调用map_images做解析和处理
5.接下来load_images 中调用call_load_methods方法,遍历所有加载
进来的Class,按继承层次依次调用Class的+load和其他Category的+load方法
6.至此 所有的信息都被加载到内存中
7.最后dyld调用真正的main函数

17.怎么高效的实现控件的圆角效果?

通常label.layer.cornerRadius=x就可以设置圆角,但是cornerRadius只会影响
视图的背景颜色和border,对于内部还有子视图的控件就会设置不成功(如
UILabel),对于内部还有子视图的控件还需要设置
label.layer.masksToBounds=true才能使cornerRadius属性生效,此时会造成离屏渲染。
使用贝塞尔曲线绘制圆角。

18.NSIRLConnection 和NSLRLSession 的区别是 么? NSURLProtocol是做什么的?

1.下载
NSURLConnection下载文件时,先是将整个文件下载到内存,然后再写入到沙
盒,如果文件比较大,就会出现内存暴涨的情况。
而使用NSURLSessionUploadTask下载文件,会默认下载到沙盒中的tem文件
中,不会出现内存暴涨的情况,但是在下载完成后会把tem中的临时文件删除,
需要在初始化任务方法时,在completionHandler回调中增加保存文件的代码。
2.请求方法的控制
NSURLConnection实例化对象,实例化开始,默认请求就发送(同步发送),不需
要调用start方法。而cancel可以停止请求的发送,停止后不能继续访问,需要
创建新的请求。
NSURLSession有三个控制方法,取消(cancel)、暂停(suspend)、继续
(resume),暂停以后可以通过继续恢复当前的请求任务。
使用NSURLSession进行断点下载更加便捷.
NSURLSession的构造方法中有一个NSURLSessionConfiguration类的参数可
以设置配置信息,其决定了cookie,安全和高速缓存策略,最大主机连接数,
资源管理,网络超时等配置。NSURLConnection不能进行这个配置,相比较与
NSURLConnection依赖与一个全局的配置对象,缺乏灵活性而言,
NSURLSession有很大的改进

3.NSURLProtocol:使用它可以轻松地重定义整个URL Loading System。当你
注册自定义NSURLProtocol后,就有机会对所有的请求进行统一的处理
3.1.自定义请求和响应
3.2.提供自定义的全局缓存支持
3.3.重定向网络请求
3.4.提供HTTP Mocking (方便前期测试)
3.5.其他一些全局的网络请求修改需求

19.AutoLayout 中的优先级是什么? UIScrollView 中使用Autolayout 会出现什么问题?

 代码计算frame -> autoreszing(父控件和子控件的关系) -> autolayout(任何控件
都可以产生关系) -> sizeclass

注意点:
1.子控件的尺寸不能通过关联UIScrollView的来计算(UIScrollView的子控件和
其关联的约束是用来计算UIScrollView的contentsize的),可以考虑通过以下方式计算:
1.1.可以设置固定值,width=100,height=200
1.2.可以相对于UIScrollView以外的其他控件关联约束来计算。

2.UIScrollView的frame应该通过子控件以外的其他控件来计算。
3.UIScrollView的contentsize通过子控件来计算,原则是:根据子控件的尺寸以
及子控件与UIScrollView之间的间距。

20.如何处理UITableVier 中Cell 动态计算高度的问题,都有哪些方案?

1、你的Cell要使用AutoLayout来布局约束这是必须的;
设置tableview的estimatedRowHeight为一个非零值,这个属性是设置一个预估
的高度值,不用太精确。
设置tableview的rowHeight属性为UITableViewAutomaticDimension
2.第三方 UITableView+FDTemplateLayoutCell

21.UIView和CALayer是什么关系?

创建UIView对象时,UIView内部会自动创建一个层(CALayer对象),通过
UIView的layer属性可以访问这个层。当UIView需要显示到屏幕上时,会调用
drawRect:方法进行绘图渲染,并且会将所有内容绘制在自己的层上,绘图完毕
后,系统会将层拷贝到屏幕上,于是就完成了UIView的显示

UIView相比CALayer最大区别是UIView继承自UIResponder,可以响应用户事
件,而CALayer不可以;UIView侧重于对显示内容的管理,CALayer侧重于对
内容的绘制。

UIView本身,更像是一个CALayer的管理器,访问它的和绘图、坐标相关的属
性,如frame,bounds等,实际上内部都是访问它所在CALayer的相关属性
UIView和CALayer是相互依赖的关系。UIView依赖CALayer提供的内容,
CALayer依赖UIView提供的容器来显示绘制的内容。归根到底CALayer是这一
切的基础,如果没有CALayer,UIView自身也不会存在,UIView是一个特殊的
CALayer实现,添加了响应事件的能力。

使用例子:向UIView的layer上添加子layer,来使目标View上敷上一层黑色的透明薄膜。 

22.你在什么场景下会选择使 Category ?类别有什么作用?

1.分类就是对一个类的功能进行扩展,Category提供了一种比继承更为简洁的方
法来对类进行扩展,无需创建对象类的子类就能为现有的类添加新的方法,可
以为任何已经存在的类添加方法,包括系统框架UIKit等。
2.可以把类的实现分开在不同的文件里面,这样做的好处:可以将类的实现分
散到多个不同的文件或者不同的框架中,方便代码的管理。也可以对框架提供类的扩展。
3.创建对私有方法的前向引用:如果其他类中的方法未实现,在你访问其他类
的私有方法时编译器报错这时使用类别,在类别中声明这些方法(不必提供方
法实现),编译器就不会再产生警告

4.category局限性
category只能给某个已有的类扩充方法,不能扩充成员变量。
category中也可以添加属性,只不过@property只会生成setter和getter的声明,
生成setter和getter的实现以及成员变量。
如果category中的方法和类中原有方法同名,运行时会优先调用category中的方法

23.讲讲iOS事件响应链的原理?

1.大多数事件的分发都是依赖响应链的。响应链是由一系列链接在一起的响应
者(UIResponse子类)组成的。一般情况下,一条响应链开始于第一响应者,结
束于application对象。如果一个响应者不能处理事件,则会将事件沿着响应链传到下一响应者。
2.一般情况下,一条响应链开始于第一响应者,结束于application对象。因此我
们只要确定第一响应者,就可以确定整条响应链了。

3.当用户触发某一事件(触摸事件或运动事件)后,UIKit会创建一个事件对象
(UIEvent),该对象包含一些处理事件所需要的信息。然后事件对象被放到一个
事件队列中。这些事件按照先进先出的顺序来处理。当处理事件时,程序的
UIApplication对象会从队列头部取出一个事件对象,将其分发出去。通常首先
是将事件分发给程序的主window对象,对于触摸事件来讲,window对象会首先
尝试将事件分发给触摸事件发生的那个视图上。这一视图通常被称为hit-test视
图,而查找这一视图的过程就叫做hit-testing。

系统使用hit-testing来找到触摸下的视图,它检测一个触摸事件是否发生在相应
视图对象的边界之内(即视图的frame属性,这也是为什么子视图如果在父视图
的frame之外时,是无法响应事件的)。如果在,则会递归检测其所有的子视
图。包含触摸点的视图层次架构中最底层的视图就是hit-test视图。在检测出hit-
test视图后,系统就将事件发送给这个视图来进行处理

事件传递链:

initial view若不能处理事件,则传到其父视图view,
view若不能处理,则传到其父视图,因为它还不是最上层视图,
这里view的父视图是view controller的view,因为这个view也不能处理事件,因
此传给view controller,若view controller也不能处理此事件,则传到window,若
window也不能处理此事件,则传到app单例对象Application,若UIApplication单
例对象也不能处理,则表示无效事件

initial view一直传递直到最上层view, topmost view传递事件到它所在的控制器
view controller传递事件到topmost view的父视图,重复前三步,走到到达root 
controller由root控制器传递事件到window,若window也不能处理此事件,则传
到app单例对象Application若UIApplication单例对象也不能处理,则表示无效事件

24.什么是 method swizzing ? 讲讲你的使场景以及使时的注意事项?

Method Swzzling,是指runtime的一个API方法,用于方法交换,使用runtime的
这个交换方法结合分类category可以改变系统本身的方法,在系统本身方法的基础上增加代码操作。
Method swizzing配合类别可以实现在不干扰其它工程代码的情况下为系统的方法添加功能。
使用runtime的API时,注意调用顺序,一般在 文件的 +load 方法使用。

25.写个“标准“宏 MIN ,这个宏输两个参数并返回较小的那个?

 #define MIN(A,B) ((A) <= (B) ? (A) : (B))

26.介绍下 layoutSubview 和 drawRect?

UIView的setNeedsDisplay和setNeedsLayout方法。首先两个方法都是异步执
行的。setNeedsDisplay会调用自动调用drawRect方法,这样可以拿到
UIGraphicsGetCurrentContext,就可以画画了。而setNeedsLayout会默认调用
layoutSubViews,就可以处理子视图中的一些数据。

layoutSubviews在以下情况下会被调用:
1、init初始化不会触发layoutSubviews。
2、addSubview会触发layoutSubviews。
3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
4、滚动一个UIScrollView会触发layoutSubviews。
5、旋转Screen会触发父UIView上的layoutSubviews事件。
6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。
7、直接调用setLayoutSubviews。
8、直接调用setNeedsLayout。

drawRect在以下情况下会被调用:

1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调
用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 两方法
之后掉用的.所以不用担心在 控制器中,这些View的drawRect就开始画了.这样可
以在控制器中设置一些值给View
2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然
后系统自动调用drawRect:方法。
3.通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次
设置或更改frame的时候自动调用drawRect:。
4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,
但是有个前提条件是rect不能为0。

27.runloop 和线程有什么关系?

Runloop表示app运行循环。runloop和线程是紧密相连的,Runloops是线程的
基础架构部分, Cocoa 和 CoreFundation 都提供了 run loop 对象方便配置和
管理线程的 run loop 。每个线程,包括程序的主线程( main thread )都有与
之相应的 run loop 对象。
runloop 和线程的关系:
主线程的run loop默认是启动的。iOS的应用程序里面,程序启动后会有一个
main()函数,UIApplicationMain()函数,这个方法会为main thread设置一个
NSRunLoop对象,这就解释了:为什么我们的应用可以在无人操作的时候休
息,需要让它干活的时候又能立马响应。

对其它线程来说,run loop默认是没有启动的,如果你需要更多的线程交互则可
以手动配置和启动,如果线程只是去执行一个长时间的已确定的任务则不需要。
可以通过以下代码来获取到当前线程的 run loop 。
NSRunLoop *runloop = [NSRunLoop currentRunLoop];

28.重写-个NSString类型的,retain 式声明name属性的 setter和getter 法(MRC)

属性的三大特性:语义特性,原子特性,读写特性.
同时重写setter和getter方法,@synchronized name = _name,关联属性和实例变量
-(void)setName:(NSString *)name{
    if(_name != name){
      [_name retain];
      [_name release];
      _name = name;
    }
}
-(NSString *)name{
  return [[_name retain] autorelease]
}

29.请用预处理指令#define声明一个常数,用以表明1年中有多少秒(忽略闰年问题)

#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)_U_LONG
#define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)

30.IBOutlet 连出来的视图属性为什么可以被设置成weak?

因为其父视图数组已经强引用了。

30.指针与数组名的关系?

数组: 有序的元素序列,数组名有限个类型相同的变量的集合命名。数组在内
存中所占的大小由数组长度以及成员类型大小决定。
指针: 又称指针变量,在32位系统内存下占4个byte(64位系统内存下占8个
byte),其中保存的值是某一块内存的地址。

31.OC中创建线程的方法是什么? 如果在主线程中执行代码,方法是什么? 如果想延时执行代码,方法是什么?

1.线程创建有三种方法:使用NSThread创建、使用GCD的dispatch、使用子类
化的NSOperation,然后将其加入NSOperationQueue; 
2.在主线程执行代码,方法是performSelectorOnMainThread:withObject:waitUntilDone:; 
3.如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:;

32.堆和栈的区别

1.栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量等值。其
操作方式类似于数据结构中的栈。栈是向低地址扩展的数据结构,是一块连续
的内存区域。栈有两种分配方式:静态分配和动态分配。静态分配是编译器完
成的,动态分配是有alloc函数进行分配的,栈的效率比较高。
2.堆区(heap):一般由程序员分配释放,若程序员不释放,则可能会引起内存泄
漏。注 堆和数据结构中的堆栈不一样,其类似于链表。堆是向高地址扩展的数
据结构,是不连续的内存区域。堆都是动态分配的,没有静态分配的堆。

33.设计模式是什么? 你知道哪些设计模式,并简要叙述?

设计模式是一种编码经验,就是用比较成熟的逻辑去处理某一种类型的事情。
1). MVC模式:Model View Control,把模型 视图 控制器 层进行解耦合编写。
2). MVVM模式:Model View ViewModel 把模型 视图 业务逻辑 层进行解耦和编写。
3). 单例模式:通过static关键词,声明全局变量。在整个进程运行期间只会被赋值一次。
4). 观察者模式:KVO是典型的通知模式,观察某个属性的状态,状态发生变化时通知观察者。
5). 委托模式:代理+协议的组合。实现1对1的反向传值操作。
6). 工厂模式:通过一个类方法,批量的根据已有模板生产对象。

34.@property 的本质是什么?ivar、getter、setter 是如何生成并添加到这个类中的

@property = ivar + getter + setter;
“属性” (property)有两大概念:ivar(实例变量)、存取方法(access method 
= getter + setter)。
“属性” (property)作为 Objective-C 的一项特性,主要的作用就在于封装对象中
的数据。 Objective-C 对象通常会把其所需要的数据保存为各种实例变量。实
例变量一般通过“存取方法”(access method)来访问。其中,“获取方法” (getter)
用于读取变量值,而“设置方法” (setter)用于写入变量值。

每次在增加一个属性,系统都会在 ivar_list 中添加一个成员变量的描述,在 
method_list 中增加 setter 与 getter 方法的描述,在属性列表中增加一个属性的
描述,然后计算该属性在对象中的偏移量,然后给出 setter 与 getter 方法对应的
实现,在 setter 方法中从偏移量的位置开始赋值,在 getter 方法中从偏移量开始取值

35.声明的对象有什么特性?

id类型的对象可以是任意类型的OC对象,与C中的void*万能指针相似。具有运
行时的特点,在程序运行时才确定对象的类型。

36.Objective-C 如何对内存管理的,说说你的看法和解决方法?

Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
1). 自动内存计数:这种方式和java类似,在你的程序的执行过程中,你不用考
虑它什么时候开始工作,怎样工作。
解决:通过alloc – initial方式创建的,创建后引用计数+1,此后每retain一次引用计
数+1,那么在程序中做相应次数的release就好了.
2). (NSAutoRealeasePool)内存池:可以通过创建和释放内存池控制内存申请和回收的时机.
解决:是由autorelease加入系统内存池,内存池是可以嵌套的,每个内存池都需要
有一个创建释放对,就像main函数中写的一样.使用也很简单
,比如[[[NSString alloc]initialWithFormat:@”Hey you!”] autorelease],即将一个
NSString对象加入到最内层的系统内存池,当我们释放这个内存池时,其中的对象都会被释放.

37.Category(类别)、 Extension(扩展)和继承的区别

1.分类: iOS中,当原有类的方法不够用时,这时候分类就出现了。category是
在现有类的基础上添加新的方法,利用objective-c 的动态运行时分配机制,可
以为现有类添加新方法。可以在分类中添加方法和成员变量,但是添加的成员
变量不会自动生成setter和getter方法,需要在实现部分给出实现。

2.扩展: iOS中的extension就是匿名的分类,只有头文件没有实现文件。只能
扩展方法,不能添加成员变量。扩展的方法只能在原类中实现。例如你扩展
NSString,那么你只能在NSString的.m实现(这是不可能的),所以尽量少用扩
展。用分类就可以了。

3.继承:学习objective-c语言没有人是不知道继承,继承在面向对象语言是非常
重要的。在iOS中继承是单继承,既只能有一个父类。在继承中,子类可以使用
父类的方法和变量,当子类想对本类或者父类的变量进行初始化,那么需要重
写init()方法 。父类也可以访问子类的方法和成员变量。

38.你是否接触过OC中的反射机制?简单聊一下概念和使用

class反射
    通过类名的字符串形式实例化对象。
        Class class = NSClassFromString(@"student"); 
        Student *stu = [[class alloc] init];
    将类名变为字符串。
        Class class =[Student class];
        NSString *className = NSStringFromClass(class);
SEL的反射
    通过方法的字符串形式实例化方法。
        SEL selector = NSSelectorFromString(@"setName");  
        [stu performSelector:selector withObject:@"Mike"];
    将方法变成字符串。

39.如何对iOS设备进行性能测试?开发项目时你是怎么检查内存泄露?

1.Profile-> Instruments ->Time Profiler
2.静态分析 Analyze。
3.instruments工具里面有个leak可以动态分析。

40.类变量的 @public,@protected,@private,@package 声明各有什么含义?

@public 任何地方都能访问;
@protected 该类和子类中访问,是默认的;
@private 只能在本类中访问;
@package 本包内使用,跨包不可以。

41.什么是谓词?

谓词就是通过NSPredicate给定的逻辑条件作为约束条件,完成对数据的筛选。
//定义谓词对象,谓词对象中包含了过滤条件(过滤条件比较多)
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"age<%d",30];
//使用谓词条件过滤数组中的元素,过滤之后返回查询的结果
NSArray *array = [persons filteredArrayUsingPredicate:predicate];

42.isa指针问题

isa:是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而
Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。
当类方法被调 用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查
找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指
针,它的isa指针最终指向的是一个根元类(root meteClass)。根元类的isa指针指
向本身,这样形成了一个封闭的内循环。

43.iOS中常用的数据存储方式有哪些?

数据存储有四种方案:NSUserDefault、KeyChain、file、DB。
其中File有三种方式:plist、Archive(归档)
DB包括:SQLite、FMDB、CoreData

44.iOS的沙盒目录结构是怎样的?

1). Application:存放程序源文件,上架前经过数字签名,上架后不可修改。
2). Documents:常用目录,iCloud备份目录,存放数据。(这里不能存缓存文
件,否则上架不被通过)
3). Library:
        Caches:存放体积大又不需要备份的数据。(常用的缓存路径)
        Preference:设置目录,iCloud会备份设置信息。
4). tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。

45.dispatch_barrier_async(栅栏函数)的作用是什么?

函数定义:dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
作用:
    1.在它前面的任务执行结束后它才执行,它后面的任务要等它执行完成后才会开始执行。
    2.避免数据竞争

46.Runtime实现的机制是什么,怎么用,一般用于干嘛?

1). 使用时需要导入的头文件 <objc/message.h>或者<objc/runtime.h>
2). Runtime 运行时机制,它是一套C语言库。
3). 实际上我们编写的所有OC代码,最终都是转成了runtime库的东西。
    比如:
        类转成了 Runtime 库里面的结构体等数据类型,
        方法转成了 Runtime 库里面的C语言函数,
        平时调方法都是转成了 objc_msgSend 函数(所以说OC有个消息发送机制)
4). 因此,可以说 Runtime 是OC的底层实现,是OC的幕后执行者。

一般用于:
(1)获取类里面的所有成员变量。
(2)为类动态添加成员变量。
(3)动态改变类的方法实现。
(4)为类动态添加新的方法等。

47.什么是 Method Swizzle(黑魔法),什么情况下会使用?

1). 在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承
它重写、和借助类别重名方法暴力抢先之外,还有更加灵活的方法 Method Swizzle。
2). Method Swizzle 指的是改变一个已存在的选择器对应的实现的过程。OC中
方法的调用能够在运行时通过改变,通过改变类的调度表中选择器到最终函数间的映射关系。
3). 在OC中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据
是selector的名字。利用OC的动态特性,可以实现在运行时偷换selector对应的方法实现。
4). 每个类都有一个方法列表,存放着selector的名字和方法实现的映射关系。
IMP有点类似函数指针,指向具体的方法实现。
5). 我们可以利用 method_exchangeImplementations 来交换2个方法中的IMP。
6). 我们可以利用 class_replaceMethod 来修改类。
7). 我们可以利用 method_setImplementation 来直接设置某个方法的IMP。

48._objc_msgForward 函数是做什么的,直接调用它将会发生什么?

_objc_msgForward是 IMP 类型,用于消息转发的:当向一个对象发送一条消
息,但它并没有实现的时候,_objc_msgForward会尝试做消息转发。

49.什么是 TCP / UDP ?

TCP:传输控制协议。
UDP:用户数据协议。

TCP 是面向连接的,建立连接需要经历三次握手,是可靠的传输层协议。
UDP 是面向无连接的,数据传输是不可靠的,它只管发,不管收不收得到。
简单的说,TCP注重数据安全,而UDP数据传输快点,但安全性一般。

50.HTTP协议中 POST 方法和 GET 方法有那些区别?

1.用于向服务器请求数据,POST用于提交数据
2.GET请求,请求参数拼接形式暴露在地址栏,而POST请求参数则放在请求体
里面,因此GET请求不适合用于验证密码等操作
3.GET请求的URL有长度限制,POST请求不会有长度限制

51.请简单的介绍下APNS发送系统消息的机制

APNS优势:杜绝了类似安卓那种为了接受通知不停在后台唤醒程序保持长连
接的行为,由iOS系统和APNS进行长连接替代。
APNS的原理:
1). 应用在通知中心注册,由iOS系统向APNS请求返回设备令牌(device Token)
2). 应用程序接收到设备令牌并发送给自己的后台服务器
3). 服务器把要推送的内容和设备发送给APNS
4). APNS根据设备令牌找到设备,再由iOS根据APPID把推送内容展示

52.AFNetworking 底层原理分析

AFNetworking主要是对NSURLSession和NSURLConnection(iOS9.0废弃)的封装,其中主要有以下类:
1). AFHTTPRequestOperationManager:内部封装的是 NSURLConnection, 负
责发送网络请求, 使用最多的一个类。(3.0废弃)
2). AFHTTPSessionManager:内部封装是 NSURLSession, 负责发送网络请
求,使用最多的一个类。(新的)
3). AFNetworkReachabilityManager:实时监测网络状态的工具类。当前的网
络环境发生改变之后,这个工具类就可以检测到。
4). AFSecurityPolicy:网络安全的工具类, 主要是针对 HTTPS 服务。
5). AFURLRequestSerialization:序列化工具类,基类。上传的数据转换成
JSON格式(AFJSONRequestSerializer).使用不多。
6). AFURLResponseSerialization:反序列化工具类;基类.使用比较多:
7). AFJSONResponseSerializer; JSON解析器,默认的解析器.
8). AFHTTPResponseSerializer; 万能解析器; JSON和XML之外的数据类型,直
接返回二进制数据.对服务器返回的数据不做任何处理.
9). AFXMLParserResponseSerializer; XML解析器;

53.描述下SDWebImage里面给UIImageView加载图片的逻辑

SDWebImage 中为 UIImageView 提供了一个分类UIImageView+WebCache.h, 
这个分类中有一个最常用的接口sd_setImageWithURL:placeholderImage:,会
在真实图片出现前会先显示占位图片,当真实图片被加载出来后再替换占位图片。
加载图片的过程大致如下:
1.首先会在 SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为
数据的索引先在内存中寻找是否有对应的缓存
2.如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数
据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来
3.如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片
4.下载后的图片会加入缓存中,并写入磁盘中
5.整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来

SDWebImage原理:
调用类别的方法:
1. 从内存(字典)中找图片(当这个图片在本次使用程序的过程中已经被加载过),找到直接使用。
2. 从沙盒中找(当这个图片在之前使用程序的过程中被加载过),找到使用,缓存到内存中。
3. 从网络上获取,使用,缓存到内存,缓存到沙盒。

54.不用中间变量,用两种方法交换 A 和 B 的值?

void swap(int a, int b) {
  a = a + b;
  b = a - b;
  a = a - b;
}

55.求最大公约数?


/** 1.直接遍历法 */
int maxCommonDivisor(int a, int b) {
    int max = 0;
    for (int i = 1; i <=b; i++) {
        if (a % i == 0 && b % i == 0) {
            max = i;
        }
    }
    return max;
}

/** 2.辗转相除法 */
int maxCommonDivisor(int a, int b) {
    int r;
    while(a % b > 0) {
        r = a % b;
        a = b;
        b = r;
    }
    return b;
}

56.排序算法?

/** 
 *  【选择排序】:最值出现在起始端
 *  
 *  第1趟:在n个数中找到最小(大)数与第一个数交换位置
 *  第2趟:在剩下n-1个数中找到最小(大)数与第二个数交换位置
 *  重复这样的操作...依次与第三个、第四个...数交换位置
 *  第n-1趟,最终可实现数据的升序(降序)排列。
 *
 */
void selectSort(int *arr, int length) {
    for (int i = 0; i < length - 1; i++) { //趟数
        for (int j = i + 1; j < length; j++) { //比较次数
            if (arr[i] > arr[j]) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

/** 
 *  【冒泡排序】:相邻元素两两比较,比较完一趟,最值出现在末尾
 *  第1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推
进,最值最后出现在第n个元素位置
 *  第2趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推
进,最值最后出现在第n-1个元素位置
 *   ……   ……
 *  第n-1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推
进,最值最后出现在第2个元素位置 
 */
void bublleSort(int *arr, int length) {
    for(int i = 0; i < length - 1; i++) { //趟数
        for(int j = 0; j < length - i - 1; j++) { //比较次数
            if(arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        } 
    }
}

57.折半查找(二分查找)


/**
 *  折半查找:优化查找时间(不用遍历全部数据)
 *
 *  折半查找的原理:
 *   1> 数组必须是有序的
 *   2> 必须已知min和max(知道范围)
 *   3> 动态计算mid的值,取出mid对应的值进行比较
 *   4> 如果mid对应的值大于要查找的值,那么max要变小为mid-1
 *   5> 如果mid对应的值小于要查找的值,那么min要变大为mid+1
 *
 */ 
 
// 已知一个有序数组, 和一个key, 要求从数组中找到key对应的索引位置 
int findKey(int *arr, int length, int key) {
    int min = 0, max = length - 1, mid;
    while (min <= max) {
        mid = (min + max) / 2; //计算中间值
        if (key > arr[mid]) {
            min = mid + 1;
        } else if (key < arr[mid]) {
            max = mid - 1;
        } else {
            return mid;
        }
    }
    return -1;
}

58.避免使用C语言中的基本数据类型,建议使用 Foundation 数据类型,对应关系?

int -> NSInteger
unsigned -> NSUInteger
float -> CGFloat
动画时间 -> NSTimeInterval 等

59 如何让计时器调用一个类方法

计时器只能调用实例方法,但是可以在这个实例方法里面调用静态方法。
使用计时器需要注意,计时器一定要加入RunLoop中,并且选好model才能运
行。scheduledTimerWithTimeInterval方法创建一个计时器并加入到RunLoop中
所以可以直接使用。
如果计时器的repeats选择YES说明这个计时器会重复执行,一定要在合适的时
机调用计时器的invalid。不能在dealloc中调用,因为一旦设置为repeats 为
yes,计时器会强持有self,导致dealloc永远不会被调用,这个类就永远无法被
释放。比如可以在viewDidDisappear中调用,这样当类需要被回收的时候就可
以正常进入dealloc中了。

60.id和NSObject*的区别

id是一个 objc_object 结构体指针,定义是 typedef struct objc_object *id
id可以理解为指向对象的指针。所有oc的对象 id都可以指向,编译器不会做类
型检查,id调用任何存在的方法都不会在编译阶段报错,当然如果这个id指向的
对象没有这个方法,该崩溃还是会崩溃的。
 
NSObject *指向的必须是NSObject的子类,调用的也只能是NSObjec里面的方
法否则就要做强制类型转换。
 
不是所有的OC对象都是NSObject的子类,还有一些继承自NSProxy。
NSObject *可指向的类型是id的子集。

61.你实现过一个框架或者库以供别人使用么?如果有,请谈一谈构建框架或者库时候的经验;如果没有,请设想和设计框架的public的API,并指出大概需要如何做、需要注意一些什么方面,来使别人容易地使用你的框架。

抽象和封装,方便使用。首先是对问题有充分的了解,比如构建一个文件解压
压缩框架,从使用者的角度出发,只需关注发送给框架一个解压请求,框架完
成复杂文件的解压操作,并且在适当的时候通知给是哦难过者,如解压完成、
解压出错等。在框架内部去构建对象的关系,通过抽象让其更为健壮、便于更
改。其次是API的说明文档。

62.对于Objective-C,你认为它最大的优点和最大的不足是什么?对于不足之处,现在有没有可用的方法绕过这些不足来实现需求。

最大的优点是它的运行时特性,不足是没有命名空间,对于命名冲突,可以使
用长命名法或特殊前缀解决,如果是引入的第三方库之间的命名冲突,可以使
用link命令及flag解决冲突。
上一篇下一篇

猜你喜欢

热点阅读