主要记录一些题目所关联的知识点, 简单概述
iOS 题目详解 部分一
iOS 题目详解 部分二
iOS 题目详解 部分三
题目1. iOS 如何实现断点续传:
要实现断点续传通常服务器端和手机端都需要记录下来当前下载的进度, 在 HTTP1.1后开始支持;
Range: 需要在请求头中设置, 指定第一个字节的位置和最后一个字节位置; 一般格式为
Range:(unit=first byte pos)-[last byte pos]
Content-Range: 用于响应头,就是回掉时的内容, 需要指定下载哪一段数据同时还需指示整个实体的长度, 一般格式为
Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth]
则请求, 如果是长度800的文件, 前面400已经下载了则再次下载时只要这样这样设置请求头
请求下载整个文件:
GET /test.rar HTTP/1.1
Connection: close
Host: 127.0.0.1
Range: bytes=400-800 //一般请求下载整个文件是bytes=0- 或不用这个头
一般正常回应
HTTP/1.1 200 OK
Content-Length: 800 #文件实体的长度
Content-Type: application/octet-stream
Content-Range: bytes 400-800/800 #800 文件总大小
题目2. 服务器在北京, 那么北京附近访问就会很快, 深圳访问很慢, 这怎么办?
使用CDN 内容分发网络, 或者服务器集群, 数据库之间使用局域网之类通讯; 用户访问后通过 DNS 解析为 IP何 mac 地址,首先 DNS 服务器会查询是否有这个域名的缓存如果有的话就直接返回对应的ip, 如果没有缓存则通过递归查找13个根服务器; 当DNS 服务器解析时候, 可以通过 LDNS(Local DNS)进行定位, 例如调度访问发现是来自深圳的 LDNS 服务器, 那就分发给深圳电信的CND;
题目3. 日常开发中使用那些 HTTP 的请求方法
GET
方法: 单纯的获取资源时候使用, 幂等性, 意思就是无论请求多少次结果都是一样的;请求参数长度限制; 不同的浏览器要求不一样;
POST
方法: 对服务器产生副作用时,例如数据插入数据之类; 或者像数据传输数据; 对请求参数没限制;
PUT
方法:工程中使用的用户第一次上传自选股时使用PUT
请求建表, 往后都是使用 POST
;
DELETE
方法:用户要重置自选股的数据时, DELETE
请求删除表;
题目4. TCP 的链接和断开:
6种TCP
标志位: 建立链接(syn
包); 确认(ack
包); 传送(psh
包); 结束(fin
包); 重置(rst
);
TCP的建立链接三次握手: 第一次客户端发送 syn
包申请建立链接,然后处于 synsend
状态; 第二次服务器端收到后发送syn+ack
包给客户端, 处于synreceive
状态; 第三次客户端收到后再次发送 ack+1
给服务器端建立链接;
为什么要三次握手?
简单来说, 第一次握手服务器端确认了: 客户端的发送能力正常以及自己的接受能力正常, 然后第二次握手后客户端可以确认:自己和服务器的发送能力和接收能力正常;然后第三次握手, 服务器端可以确认自己的发送能力正常; 至此, 双方都可以确认彼此的发送/接收能力正常, 然后开始通讯;
TCP的断开链接四次握手: 第一次, 客户端发送fin
包给服务器申请断开连接; 第二次, 服务器收到fin
包发送ack
给客户端确认可以断开连接, 同时处于closewait
状态, 同时发送剩余数据; 第三次,剩余数据发送完毕后, 服务器端再次响应客户端发送fin+ack
, 告知自己可以关闭; 第四次, 客户端收收到包后再次发送ack
后处于close
状态, 服务器端收到后处于close
状态;
题目5. iOS 持久化存储的方案
- NSUserDefault: 适合轻量级的本地存储, 不适合自定义对象;
- 沙盒存储: 适合较大的文件存储, 不适用自定义对象, 需要归档/解档;
- Keychain 存储: 适用于敏感信息的存储, 键值对方式存储;
- Cordata 存储:
- 数据库存储: 本地创建数据库进行管理;
题目6. MVVM 如何实现绑定?
MVVM的框架大致如下
实现数据绑定的方式: 代理,
Block
, RXSwift
, RAC
; 核心为 KVO
监听;
题目7. 进程和线程的区别
进程有独立的内存空间, 线程依赖于进程; 线程属于最小的任务单元;
题目8. 关于 Block 内的循环引用
在block
里面访问成员变量
会造成循环引用吗?怎么解决?
会造成, 只要访问成员变量, Block
就会对当前对象强引用;
#import "ViewController2.h"
typedef void(^Block)(void);
@interface ViewController2 ()
@property (nonatomic, strong) NSMutableArray *nameArr;
@property (nonatomic, copy) Block block;
@end
@implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
self.nameArr = [NSMutableArray arrayWithCapacity:0];
[self.nameArr addObject:@"1212"];
///循环引用
self.block = ^{
NSLog(@"%@", self->_nameArr);
};
///循环引用
self.block = ^{
NSLog(@"%@", _nameArr);
};
///循环引用
self.block = ^{
NSLog(@"%@", self.nameArr);
};
self.block();
}
- (void)dealloc {
NSLog(@"%s", __func__);
}
@end
题目9. Weak指针的大致流程
首先看runtime的源码NSObject.mm
的最上面有个SideTable
里面其中两个成员是RefcountMap
和weak_table_t
; RefcountMap
是用来存储引用计数 的, weak_table_t
是一个哈希表, 用来存放weak
对象指针的;存储形式是key:value[]
, 其中key
是对象地址, value
是一个数组(里面是一个个的weak
指针, 因为一个weak
对象有可能被多个weak
指针指向), 最后这个数组被封装为weak_entry_t
;
- 初始化时首先调用
objc_initWeak()
函数, 初始化weak
指针指向weak
对象; - 接下来调用
objc_storeWeak()
函数, 更新weak
指针的指向, 创建/更新弱引用表; - 当对象
dealloc
时依次调用_objc_rootDealloc()
->rootDealloc()
->object_dispose()
->objc_destructInstance()
->clearDeallocating()
->weak_clear_no_lock()
通过等函数, 首先通过weak
对象的地址获取到weak
指针的数组, 然后遍历这个数组, 将weak
指针置为nil
;然后将这个weak_entry_t
从哈希表中移出;
有理解错误的地方还请不吝赐教;
参考文章和下载链接
Apple 一些源码的下载地址
网友评论