刷刷面试题

2018-03-29  本文已影响37人  优雨

1.关于copyWithZone

为了实现对象的深拷贝 需要遵循NSCopying协议 并实现copyWithZone:方法
这里的关键点在于 当父类未实现NSCopying协议时 需要这样写:

- (id)copyWithZone:(NSZone *)zone {
    Crime *newCrime = [[[self class] allocWithZone:zone] init];// 注意这里
    if(newCrime) {
        [newCrime setMonth:[self month]];
        [newCrime setCategory:[self category]];
        [newCrime setCoordinate:[self coordinate]];
        [newCrime setLocationName:[self locationName]];
        [newCrime setTitle:[self title]];
        [newCrime setSubtitle:[self subtitle]];
    }
    return newCrime;
}

这样可以保证当子类继承调用[super copyWithZone:zone]的时候能够获取到正确的实例对象:

- (id)copyWithZone:(NSZone *)zone {
    Crime *newCrime = [super copyWithZone:zone];// 考虑下若父类直接使用[self allocWithZone:zone]的情况
    [newCrime setMonth:[self month]];
    [newCrime setCategory:[self category]];
    [newCrime setCoordinate:[self coordinate]];
    [newCrime setLocationName:[self locationName]];
    [newCrime setTitle:[self title]];
    [newCrime setSubtitle:[self subtitle]];
    return newCrime;
}

2.copy和mutableCopy

对immutableObject 执行copy得到不可变对象 并且是浅拷贝
对immutableObject 执行mutableCopy得到可变对象 实现的是深拷贝
对mutableObject 执行copy得到不可变对象 并且是深拷贝
对mutableObject 执行mutableCopy得到可变对象 实现的是深拷贝

对于容器类来说,容器类对象本身遵循上述规律,但是其内部包含的所有对象都是浅拷贝,都指向原来的对象

3.@property常用修饰词及其含义

一般来说 属性有默认的关键字,对于基本类型来说为atomicreadwriteassign,对于非基本类型来说为atomicreadwritestrong

4.iOS下实现多线程的方式

有四种 包括pthread、NSThread、GCD和NSOperation
一般使用GCD作为多线程的解决方案
在遇到GCD无法解决的情况一般会使用NSOperation+NSOperationQueue 后者其实是基于前者实现的

GCD了解下async、sync的区别,dispatch_group的使用、dispatch_barrier_async/sync的使用
NSOperation注意下和GCD相比支持取消操作,而且可以方便的控制最大的并发数量,以及确定操作之间的依赖关系等。

5.为什么说OC是一门动态语言

可以从以下几个方面说一说:
动态类型 id 可以接受各种各样的类型 比如说发送通知传参数的时候
动态绑定 在运行的时候才决定要调用哪个方法 比如说method swizzle
动态载入 动态的加载代码运行

6.消息转发机制

所谓的消息转发是指对象无法直接处理消息时(比如说方法有定义,但是却没有实现),提供的补救方案,分为三步:动态方法解析备用接受者完整转发
动态方法解析:对象在接收到未知的消息时,首先会调用resolveInstanceMethodresolveClassMethod,在这里通过class_addMethod函数动态添加C函数到类即可 返回值为BOOL 表示有没有成功的加入方法
备用接受者:如果动态方法无法解析消息(上面的方法返回NO),则会走forwardingTargetForSelector,这个方法返回你需要转发消息的对象,这个备用接受者只能是一个新的对象,不能是self本身,否则就会出现无限循环。返回值为备用的接收者对象
完整转发:如果我们不实现forwardingTargetForSelector,系统就会调用两个方法methodSignatureForSelectorforwardInvocationmethodSignatureForSelector用来生成方法签名,这个签名就是给forwardInvocation中的参数NSInvocation调用的。而forwardInvocation方法则通过新建你需要执行NSInvocation的对象,调用invokeWithTarget来实现完整的消息转发。forwardInvocation方法没有返回值

7.设计模式6大原则

单一职责原则:有且仅有一个原因引起类的变更。单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良
里氏替换原则:在使用基类的的地方可以任意使用其子类,能保证子类完美替换基类。如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生“畸变”,则建议断开父子继承关系 采用依赖、聚合、组合等关系代替继承
依赖倒置原则:高层模块不应该依赖底层模块,二者都该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。高层模块就是调用端,低层模块就是具体实现类。抽象就是指接口或抽象类。细节就是实现类
接口隔离原则:类间的依赖关系应该建立在最小的接口上 建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少,但是要有限度。对接口进行细化可以提高程序设计灵活性,但是如果过小,则会造成接口数量过多,使设计复杂化
迪米特法则:类间解耦,对其他类知道的越少越好。
开放封闭原则:尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来完成变化。一个软件产品在生命周期内,都会发生变化,既然变化是一个既定的事实,我们就应该在设计的时候尽量适应这些变化,以提高项目的稳定性和灵活性

8.关于Runloop

Runloop是一种让线程能随时处理事件但并不退出的机制,这种模型通常被称作 Event Loop。 Event Loop 在很多系统和框架里都有实现,比如 Node.js 的事件处理,比如 Windows 程序的消息循环,再比如 OSX/iOS 里的 RunLoop。实现这种模型的关键点在于:如何管理事件/消息,如何让线程在没有处理消息时休眠以避免资源占用、在有消息到来时立刻被唤醒。所以,RunLoop 实际上就是一个对象,这个对象管理了其需要处理的事件和消息,并提供了一个入口函数来执行上面 Event Loop 的逻辑。线程执行了这个函数后,就会一直处于这个函数内部 “接受消息->等待->处理” 的循环中,直到这个循环结束(比如传入 quit 的消息),函数返回。

一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个 Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个 Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出 Loop,再重新指定一个 Mode 进入。

9.HTTP响应码对应的含义

200 OK:客户端请求成功
301 Moved Permanently:请求永久重定向
302 Moved Temporarily:请求临时重定向
304 Not Modified:文件未修改,可以直接使用缓存的文件
400 Bad Request:由于客户端请求有语法错误,不能被服务器所理解
401 Unauthorized:请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden: 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
404 Not Found: 请求的资源不存在,例如,输入了错误的URL
500 Internal Server Error:服务器发生不可预期的错误,导致无法完成客户端的请求
503 Service Unavailable:服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常

10.OSI

OSI七层模型.png

11.三次握手

第一次:客户端 SYN:1 Seq:x SYN_SEND状态
第二次:服务器 SYN:1 ACK:1 Seq:y ACKNum:x+1 SYN_RCVD状态
第三次:客户端 ACK:1 ACKNum:y+1 ESTABLISH状态

为什么需要三次?

最主要是防止已过期的第二次握手报文因网络延迟到达客户端导致连接再次开启的问题

12.四次挥手

第一次:客户端 FIN=1 Seq=x FIN_WAIT_1
第二次:服务器 ACK=1 ACKNum=x+1 CLOSE_WAIT 客户端进入FIN_WAIT_2
中途还可能继续传输一些数据
第三次:服务器 FIN=1 Seq=y LAST_ACK
第四次: 客户端 ACK=1 ACKNum=y+1 TIME_WAIT
服务器在接收到客户端的第四次报文时就会关闭连接 客户端经过2MSL(一个报文发送加回复加起来所需最大的事件)之后如果没接收到服务器要求重传报文的请求 就进入CLOSE关闭连接

为什么需要四次?

因为虽然客户端不在传数据了 但是服务器可能要继续传输一些数据(全双工模式)

13.补充一些Git命令的使用

git reflog:查看自己使用命令的历史
git diff commit1 commit2:将某两次commit之间的变化作对比 commitid可以替换为HEAD HEAD~1等
git stash:如果当前工作区文件有修改但是不想提交,又想切换到其他分支修改一些内容的时候可以使用这个命令,当切换回来的时候,使用git stash pop即可恢复

14.+load方法和+initialize方法的区别

前者在程序开始运行,也就是类被载入的时候就调用
后者在用到这个类的时候才调用
前者如果自己不实现 不会继承父类的load方法
后者却会继承(如果本身没实现的话 会调用父类的initialize方法)
前者在方法体中使用其他类不安全(不能保证此时使用的类已经载入,使用Foundation中的类安全)
后者则安全

15.绘制性能相关问题

上面列出的触发离屏渲染的方式除了drawRect都是GPU上的离屏渲染。

16.一些小Tips:

17.理解类对象

每个对象结构体内部都有一个isa指针指向其对应的类对象,类对象结构体除了有对象的方法类表(实例方法),变量列表等信息外,有一个super_class指针,指向自己的超类的类对象,还有一个isa指针,指向自己的元类。元类有类对象的方法列表(类方法)等信息,他的super_class指针指向其父元类,而isa指针都统一指向根元类。根元类是继承体系中处于顶端的类的元类,也就是说NSObject继承体系下的所有类对象的元类都指向同一个NSObject类对象的元类。

18.SDWebImage 使用ImageView下载图片的大致流程是怎么样的?

草草看了下代码,综合相关文章,只说说重点:

19.GCD拾遗

20.loadView方法 viewDidLoad方法

loadView方法会在UIViewController想使用self.view,但是view为空的时候调用,其默认实现为创建一个空白View(没有xib的时候),如果想自己创建self.view,那么就可以重写这个方法,并且不调用[super loadView]避免创建空白view,然后创建属于自己的view即可。
viewDidLoad则会在self.view被创建出来的时候调用,我们一般可以在这里方法里面往view里面添加子view,然后进行一些其他数据的初始化操作。

21.UIViewController生命周期方法的调用顺序

22.产生死锁的必要条件和解决死锁的策略

23.常见的设计模式

单例、Builder、工厂模式
工厂模式分为普通的工厂模式和抽象工厂,两者区别在于后者的工厂接口定义了生产多种抽象产品的方法,而普通工厂只生产一种抽象产品

24.关于iOS中的事件传递和响应机制

25.iOS中有哪些设计模式的相关体现?

观察者:KVO
单例:经常用到
代理:delegate

26.HTTP和HTTPS的区别

HTTPS更安全(基于SSL 非明文 非对称加密)
端口号(HTTPS443 HTTP80)

非对称加密:用秘钥加密的数据只有公钥才能解开 反之亦然(不会导致私钥的泄露)

27.iOS如何实现线程安全?

28.iOS内存分布

栈:局部变量(指针) 函数的参数
堆:各种对象
全局区:全局对象 常量(字符串常量之类) 静态对象(static修饰的)

29.TCP和UDP的区别

TCP有连接(三次握手 四次挥手) UDP无连接
TCP可靠传输 UDP不可靠
TCP有拥塞控制 UDP没有 网络不好也不会导致传输效率降低
TCP是一对一的 但是UDP支持一对多和多对一

30.TCP的拥塞控制

发送方维持一个叫做拥塞窗口的东西:conwind
阈值threshold:决定conwind超过这个值的时候采用什么方式增加窗口大小
conwind < threshold:慢启动 指数级增加窗口大小 由于刚刚开始传输的时候threshold很大 所以一开始肯定是慢启动
conwind > threshold: 拥塞避免 线性增加窗口大小
两种可能的超时情况:3个冗余ACK(说明有报文丢失了) 和 直接超时
3个冗余ACK:说明网络情况还是能传数据的 将conwind和threshold都设置为conwind的一半 进入拥塞避免状态
超时:网络情况很差了 将threshold减半 但是conwind从1MSS(最大报文段长度) 从慢启动开始

31.在浏览器中输入一个域名会执行哪些操作

1.根据域名 查找IP 涉及到DNS解析域名
2.根据IP 向服务器发送HTTP请求 建立TCP连接涉及到三次握手
3.服务器回传HTML资源 客户端浏览器根据资源进行页面的渲染
4.如果没有后续的连接操作 通过四次挥手 断开TCP连接

32.为什么选择使用代码布局而不是用stroyBoard或者xib

主要是为了多人开发的时候方便代码的codereview,而且重用方便,虽然会麻烦一些,而且不是很直观

33.讲解一下RunLoop

①为什么要有RunLoop?因为我们希望某个线程不退出一直能够处理事件 细化到iOS里面 就是保持程序运行 处理各种触摸事件等。而作为这样的一个工具,要保证可以良好的处理好事件,并在空闲的时候休眠节省资源,需要的时候可以快速唤醒。
②如何获取RunLoop?除开主线程,线程默认是不启动RunLoop的,它的第一次创建是你在第一次获取它的时候:[NSRunLoop currentRunLoop]。RunLoop无法被直接创建。
③RunLoop的内部构成是怎么样的?一个RunLoop包含若干个Mode,其中一个Mode又包含若干个STO(Source/Timer/Observer)。每次调用RunLoop主函数的时候只能指定一个Mode,这是为了分割开不同组的STO防止相互影响。这个被指定的Mode称为CurrentMode。如果想要切换Mode,只能先退出当前RunLoop再进入。
④如何理解Mode?RunLoop总是运行在某种Mode下,Mode必须包含STO,否则RunLoop就会退出。App在刚启动的时候会在一个UIInitilizationRunLoopMode下,然后就会变为CFRunLoopDefaultMode,这是RunLoop的默认Mode。除了这两种Mode,还有UITrackingRunLoopMode(用来追踪ScrollView的滚动)和GSEventReceiverRunLoopMode(处理系统事件),以及一个通用的CFRunLoopCommonMode(一个占位用的Mode)
⑤如何理解Source?Source代表事件源,和Timer一样用于唤醒RunLoop处理消息。Source有两种类型,一种是不基于端口的,叫做Source0,一般用来处理系统事件,UITouch等。还有一种是基于端口的Source叫做Source1,用它可以实现进程间互相发送消息,它可以主动的唤醒RunLoop。
⑥如何理解Timer?STO里面的Timer基于CoreFoundation其实和NSTimer可以互相转换,它其实也是一种事件源,一旦时间点到了,就唤醒RunLoop,执行相应的回调。所以我们初始化一个NSTimer的时候需要指定一个RunLoop(通过runLoop的addTimer:forMode)(scheduled系列的方法其实默认指定使用当前线程的RunLoop)。performSelector:withObject:afterDelay方法其实是基于NSTimer实现的。
⑦如何理解Obeserver?RunLoop拥有各种各样的运行状态,比如进入/退出RunLoop,将要开始处理Source/Timer或者将要唤醒/休眠。利用Observer就可以监听RunLoop的各种状态。
⑧RunLoop有哪些应用场景?1.防止UITableView卡顿,使用performSelector:withObject:afterDelay:inMode中指定为DefaultMode,防止TableView在滚动的时候设置上图片。2.系统有用Obeserver监听主线程RunLoop的休眠状态来提交各种UI的更新。

34.iOS证书非对称加密的机制和原理?

①数字签名?对原始文件的摘要用私钥加密,得到的叫做数字签名。将数字签名和文件一起发送给用户,用户通过公钥对签名解密,得到摘要,然后再用同一种摘要算法计算传过来文件的摘要,对比两个摘要就知道文件有没有被篡改
②苹果如何加密?两对秘钥:开发者MAC生成的公钥L 私钥L 苹果的公钥A 私钥A。首先开发者将自己的公钥L上传给苹果 苹果用私钥A对公钥L加密 得到签名。开发者将app用自己的私钥L加密,和证书一起装到iOS设备里,iOS设备用苹果提供的公钥A解密签名,得到可靠的公钥L,再用这个公钥L解密app,确保app的可靠性。

35.有哪些定时器?

NSTimer/GCD/CADisplayLink

35.谈谈MVC和MVVM

MVC:model 代表数据,view 代表 UI ,而 controller 则负责协调它们两者之间的关系


M-V-C.png

C在这里占据核心位置,负责更新View和model的状态,View则将用户的交互通知给C,Model增加数据的更新传递给C。controller 由于承载了过多的逻辑,往往会变得臃肿不堪

MVVM:将controller中的展示逻辑抽离出来,放在viewModel里,得到的模型如下:


M-V-VM.png

View由 MVC 中的 view 和 controller 组成,负责 UI 的展示,绑定 viewModel 中的属性,触发 viewModel 中的命令
ViewModel负责从 model 中获取 view 所需的数据,转换成 view 可以展示的数据,并暴露公开的属性和命令供 view 进行绑定
Model与 MVC 中的 model 一致,包括数据模型、访问数据库的操作和网络请求等;

36.谈谈消息发送机制(不是转发哦)?

在oc里面使用[object func]调用某个方法其实在运行时是通过objc_msgSend(object_object, SEL)这个方法来实现的,也就是所谓的消息发送。其内部原理实际上是通过对象结构体的isa指针来查询类对象结构体。类对象结构体里面包含了方法列表和方法列表的缓存。首先从缓存里面找,如果没有找到,则从方法列表里面直接找(如果找到会将方法加入缓存),找到的方法其实是一个IMP,他是一个函数指针,通过这个指针,可以调用对应的函数。如果方法没有找到,那么就会进行方法的转发流程。

37.什么是多态?

一个接口有多种实现方式就是多态

38.Unicode和UTF-8 UTF-16 UTF-32有什么联系?

Unicode是一种字符和码点值对应的规范,就是一张表。比如说16进制下的码点值U+0021对应的字符就是感叹号!
UTF-8 UTF-16和UTF-32则是将码值转换为计算机中的01串的规范,他对应的是计算机内的储存形式。

上一篇 下一篇

猜你喜欢

热点阅读