面经面试面试题

IOS常见8道面试题

2018-06-21  本文已影响402人  冬天里寒风起

为了让大家能相互交流和分享ios面试题,精彩的demo,最经典的资料,群号:776296806!


QQ图片20180531173835.jpg

题目:

1 讲一下你对iOS内存管理的理解
2 KVO实现原理
3 观察者模式
4如果让你实现NSNotificationCenter,讲一下思路
5 如果让你实现 GCD线程池,讲一下思路
6Category的实现原理,以及 Category 为什么只能加方法不能加实例变量。
7swiftstructclass的区别
8在一个HTTPS连接的网站里,输入账号密码点击登录后,到服务器返回这个请求前,中间经历了什么

一. 讲一下你对 iOS 内存管理的理解

Objective-C的内存管理中,其实就是引用计数(reference count)的管理。内存管理就是在程序需要时程序员分配一段内存空间,而当使用完之后将它释放。如果程序员内存资源使用不当,有时不仅会造成内存资源浪费,甚至会导致程序crach

image.png

1. 引用计数(Reference Count)

为了解释引用计数,我们做一个类比:员工在办公室使用灯的情景。

image.png

1.当第一个人进入办公室时,他需要使用灯,于是开灯,引用计数为1

2.当另一个人进入办公室时,他也需要灯,引用计数为2;每当多一个人进入办公室时,引用计数加1

3.当有一个人离开办公室时,引用计数减1,当引用计数为0时,也就是最后一个人离开办公室时,他不再需要使用灯,关灯离开办公室。

2. 内存管理规则

从上面员工在办公室使用灯的例子,我们对比一下灯的动作与Objective-C对象的动作有什么相似之处:

image.png
因为我们是通过引用计数来管理灯,那么我们也可以通过引用计数来管理使用Objective-C对象。
image.png
Objective-C对象的动作对应有哪些方法以及这些方法对引用计数有什么影响? image.png
当你alloc一个对象objc,此时RC=1;在某个地方你又retain这个对象objc,此时RC加1,也就是RC=2;由于调用alloc/retain一次,对应需要调用release一次来释放对象objc,所以你需要release对象objc两次,此时RC=0;而当RC=0时,系统会自动调用dealloc方法释放对象

3. Autorelease Pool

在开发中,我们常常都会使用到局部变量局部变量一个特点就是当它超过作用域时,就会自动释放。而autorelease pool局部变量类似,当执行代码超过autorelease pool块时,所有放在autorelease pool的对象都会自动调用release。它的工作原理如下:

创建一个NSAutoreleasePool对象

autorelease pool块的对象调用autorelease方法

释放NSAutoreleasePool对象

image.png

4. ARC管理方法

iOS/OS X内存管理方法有两种:手动引用计数(Manual Reference Counting)自动引用计数(Automatic Reference Counting)

自动引用计数(Automatic Reference Counting)简单来说,它让编译器来代替程序员来自动加入retainrelease方法来持有放弃对象所有权

ARC内存管理机制中,id其他对象类型变量必须是以下四个ownership qualifiers其中一个来修饰:
所以在管理Objective-C对象内存的时候,你必须选择其中一个,下面会用一些列子来逐个解释它们的含义以及如何选择它们。

__strong:被它修饰的变量持有对象的所有权(默认,如果不指定其他,编译器就默认加入)

__weak: 被它修饰的变量都不持有对象的所有权,而且当变量指向的对象的RC为0时,变量设置为nil。

__unsafe_unretained:被它修饰的变量都不持有对象的所有权,但当变量指向的对象的RC为0时,变量并不设置为nil,而是继续保存对象的地址;这样的话,对象有可能已经释放,但继续访问,就会造成非法访问(Invalid Access)。

__autoreleasing:相比之前的创建、使用和释放NSAutoreleasePool对象,现在你只需要将代码放在@autoreleasepool块即可。你也不需要调用autorelease方法了,只需要用__autoreleasing修饰变量即可。

5.Property(属性)

image.png

二. KVO实现原理

KVO基本原理:

1.KVO是基于runtime机制实现的

2.当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法。派生类在被重写的setter方法内实现真正的通知机制

3.如果原类为Person,那么生成的派生类名为NSKVONotifying_Person

4.每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法

5.键值观察通知依赖于NSObject的两个方法: willChangeValueForKey: 和didChangevlueForKey:;在一个被观察属性发生改变之前,willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。

image.png

三.观察者模式

观察者模式(Observer Pattern):定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。

iOS中典型的观察者模式是:NSNotificationCenterKVO

1. NSNotificationCenter
image.png
2. KVO

KVO的全称是Key-Value Observer,即键值观察。是一种没有中心枢纽的观察者模式的实现方式。一个主题对象管理所有依赖于它的观察者对象,并且在自身状态发生改变的时候主动通知观察者对象。

[object addObserver:self forKeyPath:property options:NSKeyValueObservingOptionNew context:]。

四. 如果让你实现 NSNotificationCenter,讲一下思路

五. 如果让你实现 GCD 的线程池,讲一下思路

具体流程:

六.Category 的实现原理,以及Category 为什么只能加方法不能加实例变量。

category是可以添加属性,不能添加实例变量对吧!之所以不能添加实例变量,是因为一个类的实例变量在编译阶段,就会在objc_class的class_ro_t这里进行存储和布局,而category是在运行时才进行加载的,

然后在加载 ObjC运行时的过程中在 realizeClass 方法中:

// 从 `class_data_bits_t `调用 `data` 方法,将结果从 `class_rw_t `强制转换为 `class_ro_t `指针
const class_ro_t *ro = (const class_ro_t *)cls->data();
// 初始化一个 `class_rw_t` 结构体
class_rw_t *rw = (class_rw_t *)calloc(sizeof(class_rw_t), 1);
// 设置`结构体 ro` 的值以及 `flag`
rw->ro = ro;
// 最后设置正确的` data`。
rw->flags = RW_REALIZED|RW_REALIZING;
cls->setData(rw);

运行时加载的时候 class_ro_t里面的方法、协议、属性等内容赋值给 class_rw_t,而 class_rw_t里面没有用来存储相关变量的数组,这样的结构也就注定实例变量是无法在运行期进行填充.

七. swift 中 struct和class的区别

swift中, class是引用类型, struct是值类型。值类型在传递和赋值时将进行复制,而引用类型则只会使用引用对象的一个"指向"。所以他们两者之间的区别就是两个类型的区别。

class有这几个功能 struct没有的:

八.在一个HTTPS连接的网站里,输入账号密码点击登录后,到服务器返回这个请求前,中间经历了什么

image.png
1.客户端打包请求。包括url,端口,你的账号密码等等。账号密码登陆应该用的是Post方式,所以相关的用户信息会被加载到body里面。这个请求应该包含三个方面:网络地址,协议,资源路径。注意,这里是HTTPS,就是HTTP + SSL / TLS,在HTTP上又加了一层处理加密信息的模块(相当于是个锁)。这个过程相当于是客户端请求钥匙。

2.服务器接受请求。一般客户端的请求会先发送到DNS服务器。 DNS服务器负责将你的网络地址解析成IP地址,这个IP地址对应网上一台机器。这其中可能发生Hosts HijackISP failure的问题。过了DNS这一关,信息就到了服务器端,此时客户端会和服务器的端口之间建立一个socket连接,socket一般都是以file descriptor的方式解析请求。这个过程相当于是服务器端分析是否要向客户端发送钥匙模板。

3.服务器端返回数字证书。服务器端会有一套数字证书(相当于是个钥匙模板),这个证书会先发送给客户端。这个过程相当于是服务器端向客户端发送钥匙模板。

4.客户端生成加密信息。根据收到的数字证书(钥匙模板),客户端会生成钥匙,并把内容锁上,此时信息已经加密。这个过程相当于客户端生成钥匙并锁上请求。

5.客户端发送加密信息。服务器端会收到由自己发送出去的数字证书加锁的信息。 这个时候生成的钥匙也一并被发送到服务器端。这个过程是相当于客户端发送请求。

6.服务器端解锁加密信息。服务器端收到加密信息后,会根据得到的钥匙进行解密,并把要返回的数据进行对称加密。这个过程相当于服务器端`解锁请求、生成、加锁回应信息。

7.服务器端向客户端返回信息。客户端会收到相应的加密信息。这个过程相当于服务器端向客户端发送回应。

8.客户端解锁返回信息。客户端会用刚刚生成的钥匙进行解密,将内容显示在浏览器上。

上一篇下一篇

猜你喜欢

热点阅读