技能知识点大全

2019-08-02  本文已影响0人  zero_zql

怎么理解Objective-C是动态运行时语言。
主要是将数据类型的确定由编译时,推迟到了运行时。这个问题其实浅涉及到两个概念,运行时和多态。
简单来说, 运行时机制使我们直到运行时才去决定一个对象的类别,以及调用该类别对象指定方法。
多态:不同对象以自己的方式响应相同的消息的能力叫做多态。
意思就是假设生物类(life)都拥有一个相同的方法-eat;那人类属于生物,猪也属于生物,都继承了life后,实现各自的eat,但是调用是我们只需调用各自的eat方法。
也就是不同的对象以自己的方式响应了相同的消 息(响应了eat这个选择器)。因此也可以说,运行时机制是多态的基础.
alloc 方法做了什么?
答: alloc 分配内存并将内存地址返回给指针,init对分配的内存初始化。
NSCache 与NSDictionary 区别?
答:当系统资源耗尽是NSCache可以自动删减缓存,字典需要自己编写删除程序,当系统通知时再手动进行删减,NSCache会先行删减最新缓存且未被使用的对象。
instancetype 与 id 区别?
1、相同点:都可以作为方法的返回类型
2、不同点
(1)instancetype可以返回和方法所在类相同类型的对象,id只能返回未知类型的对象;
(2)instancetype只能作为返回值,不能像id那样作为参数,比如下面的写法
结构体和类的区别
1、结构体只能封装属性,类却不仅可以封装属性也可以封装方法。如果一个封装的数据有属性也有行为,就只能用类了。
2、结构体变量分配在栈,而OC对象分配在堆,栈的空间相对于堆来说是比较小的,但是存储在栈中的数据访问效率相对于堆而言是比较高
3、堆的存储空间比较大,存储在堆中的数据访问效率相对于栈而言是比较低的
4、如果定义一个结构体,这个结构体中有很多属性,那么这个时候结构体变量在栈中会占据很多空间,这样的话就会降低效率
5、我们使用结构体的时候最好是属性比较少的结构体对象如果属性较多的话就要使用类了。
6、结构体赋值的话是直接赋值,对象的指针,赋值的是对象的地址。
NSObject的本质是什么?
NSObject的底层实现实质是一个结构体。而结构体中的成员isa是Class类型,通过源码typedef struct objc_class *Class可知它是一个指针。在64为环境下指针占8个字节,而在32位机下是占4个字节。因此该结构体占8个字节(因为该结构体只有一个成员)
NSObject对象占多少内存?
系统在alloc的时候,分配了16个字节给 NSObject 对象(malloc_size函数获得)
但是实际上 NSObject 只使用了 8个字节的存储空间(64bit系统下)
可以通过class_getInstanceSize()
}
一个Objective-C对象如何进行内存布局?(考虑有父类的情况)
所有父类的成员变量和自己的成员变量都会存放在该对象所对应的存储空间中
父类的方法和自己的方法都会缓存在类对象的方法缓存中,类方法是缓存在元类对象中
每一个对象内部都有一个isa指针,指向他的类对象,类对象中存放着本对象的如下信息


属性关键字

可变对象的copy和mutablecopy都是深拷贝;
不可变对象的copy是浅拷贝,mutablecopy是深拷贝;
copy方法返回的都是不可变对象;

浅拷贝:浅拷贝只是对内存地址的复制,让目标对象的指针和源对象指向同一片内存空间。
深拷贝:深拷贝让目标对象指针和源对象指针分别指向两片内容相同的内存空间。
是否开辟了新的内存空间;
深拷贝不影响引用计数,浅拷贝会改变引用计数。
1:__weak 和 _Unsafe_Unretain 的区别?
weak: 修饰的指针变量,在指向的内存地址销毁后,会在 Runtime 的机制下,自动置为 nil。
_Unsafe_Unretain: 不会置为 nil,容易出现 悬垂指针,发生崩溃。但是 _Unsafe_Unretain 比 __weak 效率高。
2:@synthesize 与 @dynamic区别?
@synthesize:编译器自动生成setter和getter的方法,在你没有手动去实现这两个方法时。
@dynamic:告诉编译器你会动态生成setter和getter方法,不会要编译器帮你生成
3:@property的本质是什么?ivar、getter、setter是如何生成并添加到这个类中的?
@property 的本质是实例变量(ivar)+存取方法(access method = getter + setter),即 @property = ivar + getter + setter;
4.__weak 属性修饰的变量,如何实现在变量没有强引用后自动置为 nil ?
用的弱引用 - weak表。也是一张 哈希表。
被 weak 修饰的指针变量所指向的地址是 key ,所有指向这块内存地址的指针会被添加在一个数组里,这个数组是 Value。当内存地址销毁,数组里的所有对象被置为 nil。
5: 内存管理默认的关键字是什么?
ARC: @property (atomic ,readWrite,strong) UIView *view;
MRC: @Property (atomic,readWirte, retain) UIiView *view;
6: 是否了解 深拷贝 和 浅拷贝 的概念,集合类深拷贝如何实现?
1、对不可变的非集合对象,copy是指针拷贝,mutablecopy是内容拷贝
2、对于可变的非集合对象,copy,mutablecopy都是内容拷贝
3、对不可变的数组、字典、集合等集合类对象,copy是指针拷贝,mutablecopy是内容拷贝
4、对于可变的数组、字典、集合等集合类对象,copy,mutablecopy都是内容拷贝
但是,对于集合对象的内容复制仅仅是对对象本身,但是对象的里面的元素还是指针复制。要想复制整个集合对象,就要用集合深复制的方法,有两种:
(1)使用initWithArray:copyItems:方法,将第二个参数设置为YES即可

  NSDictionary shallowCopyDict = [[NSDictionary alloc] initWithDictionary:someDictionary copyItems:YES];

(2)将集合对象进行归档(archive)然后解归档(unarchive)

NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];

7:block为何要用copy修饰?
堆中的block 也就是copy修饰的block,它的生命周期是随着对象的销毁而结束,只要对象不销毁,我们就能调用到堆中的block。


UI视图相关:

卡顿

cpu:UI的计算,文本的布局、包括一些视图的绘制,图形的解码 》》 产生的位图提交给GPU
GPU:图层的合成、管理渲染

异步绘制:需要了解下

离屏渲染:GPU在当前缓存区外新开辟一个缓冲区进行渲染操作,
当我们指定了某些UI属性,标记它为在未愈合成之前,在当前屏幕上直接显示的时候就会触发离屏渲染 ,离屏渲染增加了GPU的工作量,


分类

能做的事情:
声明私有方法、 分解体积庞大的类文件、把frameWorkd的私有方法公开
能添加的内容:
实列方法、类方法、属性(只get,set方法,没有分配实列变量)、协议

分类为何不能直接声明属性?
category是表示一个指向分类的结构体指针,结构体没有属性列表.
属性=成员变量+get方法+set方法

分类实现的原理?
由运行时来决议,不同分类中含有同名方法,谁最终生效取决于谁最后进行编译分类当中的同名分类方法最终生效,添加的方法正好是系统类的同名方法,分类方法会覆盖系统方法,由于消息传递过程中优先查找数组靠前的方法;

分类底层原理探索
分类的实现原理是将分类中的方法,属性,协议信息放在 category_t结构体中,然后将结构体内的方法列表拷贝到类对象的方法列表中。
分类中可以添加属性,但是并不会自动生成成员变量及set、get方法。因为底层的category_t结构体中并不存在成员变量。通过之前对对象的分析我们知道成员变量是存放在实例对象中的,并且编译的那一刻就已经决定好了。而分类是在运行时才去加载的,那么我们就无法在程序运行时将分类的成员变量中添加到实例对象的结构体中。因此分类中不可以添加成员变量


扩展

作用:
声明私有属性、私有变量、

分类与扩展的区别:
1:分类运行时决议,扩展编译时决议
2:具有声明也有实现方法,扩展只有实现方法
3:能为系统类添加分类,扩展不能为系统类添加扩展

通知:

通知和代理的区别
1:通知是以观察者模式实现用于跨层传递的机制,代理是以代理模式来实现的
2: 一对多,一对一
通知的实现原理:
NSNotificationCent 可能存在一个 notificationMap 或者是字典,字典的key 就是我们的notificationName ,value就是 obServes,对于同一个notificationName
可能会添加多个observe ,所以这个observe是个list (列表),这个列表当中的每一个成员应当包含通知接收的观察者,同时也包含关于这个观察者调用的方法。


KVO

什么是kvo:
1:kvo是object-c对于观察者模式的又一实现;
每次当被观察对象的某个属性值发生改变时,注册的观察者便能获得通知。
2:苹果使用了isa 混写(isa- swizzling)来实现kvo
追问- isa—swizzling 的实现原理

其实KVO是通过isa-swizzling技术实现的,主要的操作如下:

1.当为某个对象添加观察者的时候,该对象的类将被继承生成一个中间类,并使该对象的isa指针指向中间类(所以,有时候发送消息需要明确指定类型)。注意:同一个类的其它实例对象并不受影响。
2.中间类在被观察的属性的setter方法中,在改变属性值的前后分别添加了willChangeValueForKey:和didChangeValueForKey:。使其在通过KVC标准改变属性值时可以被观察到,并向观察者发送消息。
3.当移除对某个对象的所有观察后,该对象的isa指针会重新指向原有的类。

kvo的实现原理?
kvo是系统关于观察者模式的又一实现;
kvo运用了isa混写技术来动态运行时来为某一个类添加一个子类,然后重写它的setter方法,同时把原有类的isa指针指向新创建的类;
在多人合作开发环境下,可能会有重复添加KVO的时候,或者重复移除KVO的时候,重复添加或删除KVO会怎么样?采取什么方案去解决?
重复添加或删除kvo会发生crash;一种就是手动实现一个KVO,KVO本质是苹果偷偷添加了一个派生类,将指针指向派生的子类,去监听子类的set方法从而实现监听的效果,手动实现一个KVO,并修改其添加和移除的方法,使用BOOL值作为属性在方法内部进行判断当前这个对象是否添加过或删除过即可;第二种方法,就是写一个类别,利用runtime去交换kvo的添加或移除方法到自定义的添加或移除方法,修改内部方法实现以达到该效果。


KVC

KVC(Key-value coding)键值编码,指iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值而不需要调用明确的存取方法。
KVC的实现原理


内存管理

Objective-C 如何对内存管理的,说说你的看法和解决方法?
答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
1). 自动内存计数ARC:由Xcode自动在App编译阶段,在代码中添加内存管理代码。
2). 手动内存计数MRC:遵循内存谁申请、谁释放;谁添加,谁释放的原则。
3). 内存释放池Release Pool:把需要释放的内存统一放在一个池子中,当池子被抽干后(drain),池子中所有的内存空间也被自动释放掉。内存池的释放操作分为自动和手动。自动释放受runloop机制影响。
复制代码

内存泄漏检测方法:

原理:MLeaksFinder一开始是从UIViewController入手的,UIViewController在POP或dismiss之后该控制器及其上的view,view的subviews都会被释放掉,MleaksFinder就是在控制器POP或dismiss之后去查看该控制器和其上的view是否都被释放掉。

具体的方法是,为基类 NSObject 添加一个方法 willDealloc 方法,该方法的作用是,先用一个弱指针指向 self,并在一小段时间(3秒)后,通过这个弱指针调用 -assertNotDealloc,而 -assertNotDealloc 主要作用是直接中断言。这样,当我们认为某个对象应该要被释放了,在释放前调用这个方法,如果3秒后它被释放成功,weakSelf 就指向 nil,不会调用到 -assertNotDealloc 方法,也就不会中断言,如果它没被释放(泄露了),-assertNotDealloc 就会被调用中断言。这样,当一个 UIViewController 被 pop 或 dismiss 时(我们认为它应该要被释放了),我们遍历该 UIViewController 上的所有 view,依次调 -willDealloc,若3秒后没被释放,就会中断言。


block相关

截获变量相关知识点
问题总结:

RunLoop

相关指导文章: https://www.jianshu.com/p/5ef8f28025b9

什么是runloop?
runloop是通过内部维护事件循环来对事件、消息进行管理的一个对象。
1:没有消息需要处理时,休眠以避免资源浪费;
用户态 ————>内核态(状态切换)
2:有消息处理时,立刻被唤醒。
用户态 <—— 内核态
怎样做到有事做事,没事休息的?
当我们调用cfRunLoop的run 相关的方法之后,会调用系统的一个函数much__mag同时发生了用户态向核心态的切换然后当前线程处于休眠状态。

NSRunLoopCommonModes
1:commonMode 不是实际存在的一种mode
2:commonModel是同步source/Time/observer到多个model的一种技术

事件循环机制流程图:
描述如下:
首先,进入 RunLoop (顺便通知Observer我要进入了)
然后就去处理 Timer (顺便通知 Observer 我要处理 Timer)
然后处理 Source (顺便通知 Observer 我要处理 Source)
然后判断 Source1 还有没有没有分发的任务?
--- 有的话就去处理 Source1 收到的任务包括 Timer 和Source
--- 没有的话, 就要去睡觉了
任务都处理完了,进入休眠(顺便通知 Observer 我要休眠)
休眠的时候如果有新的任务进入, RunLoop被唤醒....

RunLoop 和多线程:
runloop和多线程是一一对应的,默认情况下是没有创建runloop
怎样实现一个常驻线程?
1:为当前线程开启一个runloop;
2:向该RunLoop添加一个Port/source/observer等维持RunLoop的事件循环;
3:启动该RunLoop(也就是调用cfRunLoop的run 方法).

RunLoop和多线程的关系?
每条线程都有唯一的一个与之对应的RunLoop对象,其关系是保存在一个全局的 Dictionary 里;主线程的RunLoop已经自动创建,子线程的RunLoop需要主动创建;RunLoop在第一次获取时创建,在线程结束时销毁


RunTime

1. runtime怎么添加属性、方法等

ivar表示成员变量
class_addIvar
class_addMethod
class_addProperty
class_addProtocol
class_replaceProperty

2. runtime 如何实现 weak 属性

runtime对注册的类,会进行布局,会将 weak 对象放入一个 hash 表中。用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会调用对象的 dealloc 方法,假设 weak 指向的对象内存地址是a,那么就会以a为key,在这个 weak hash表中搜索,找到所有以a为key的 weak 对象,从而设置为 nil。

在ARC环境无论是强指针还是弱指针都无需在 dealloc 设置为 nil , ARC 会自动帮我们处理
即便是编译器不帮我们做这些,weak也不需要在dealloc中置nil
在属性所指的对象遭到摧毁时,属性值也会清空

objc// 模拟下weak的setter方法,大致如下- (void)setObject:(NSObject *)object{ objc_setAssociatedObject(self, "object", object, OBJC_ASSOCIATION_ASSIGN); [object cyl_runAtDealloc:^{ _object = nil; }];}

推荐文章:weak底层实现原理

3. runtime如何通过selector找到对应的IMP地址?(分别考虑类方法和实例方法)

每一个类对象中都一个对象方法列表(对象方法缓存)
类方法列表是存放在类对象中isa指针指向的元类对象中(类方法缓存)
方法列表中每个方法结构体中记录着方法的名称,方法实现,以及参数类型,其实selector本质就是方法名称,通过这个方法名称就可以在方法列表中找到对应的方法实现.
当我们发送一个消息给一个NSObject对象时,这条消息会在对象的类对象方法列表里查找
当我们发送一个消息给一个类时,这条消息会在类的Meta Class对象的方法列表里查找

4.使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么?
无论在MRC下还是ARC下均不需要被关联的对象在生命周期内要比对象本身释放的晚很多,它们会在被 NSObject -dealloc 调用的object_dispose()方法中释放
补充:对象的内存销毁时间表,分四个步骤

1、调用 -release :引用计数变为零

2、 父类调用 -dealloc

3、NSObject 调 -dealloc

  1. 调用 object_dispose()

6.能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?

不能向编译后得到的类中增加实例变量
能向运行时创建的类中添加实例变
***分析如下: ***
因为编译后的类已经注册在runtime中,类结构体中的objc_ivar_list 实例变量的链表和instance_size实例变量的内存大小已经确定,同时runtime 会调用class_setIvarLayout 或 class_setWeakIvarLayout来处理strong weak引用,所以不能向存在的类中添加实例变量
运行时创建的类是可以添加实例变量,调用 class_addIvar函数,但是得在调用objc_allocateClassPair之后,objc_registerClassPair之前,原因同上。

7.简述下Objective-C中调用方法的过程(runtime)

Objective-C是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector),整个过程介绍如下:

补充说明:Runtime 铸就了Objective-C 是动态语言的特性,使得C语言具备了面向对象的特性,在程序运行期创建,检查,修改类、对象及其对应的方法,这些操作都可以使用runtime中的对应方法实现。

8.什么是method swizzling(俗称黑魔法)
简单说就是进行方法交换
在Objective-C中调用一个方法,其实是向一个对象发送消息,查找消息的唯一依据是selector的名字。利用Objective-C的动态特性,可以实现在运行时偷换selector对应的方法实现,达到给方法挂钩的目的
每个类都有一个方法列表,存放着方法的名字和方法实现的映射关系,selector的本质其实就是方法名,IMP有点类似函数指针,指向具体的Method实现,通过selector就可以找到对应的IMP
9 :runtime具体应用
利用关联对象(AssociatedObject)给分类添加属性
遍历类的所有成员变量(修改textfield的占位文字颜色、字典转模型、自动归档解档)
交换方法实现(交换系统的方法)
利用消息转发机制解决方法找不到的异常问题
KVC 字典转模型
10:向nil对象发送消息会怎样?
在object中我们向对象发送消息时,runtime库会根据对象的isa指针查找该对象所属的类。然后在该类中的方法列表及其父类的方法列表中查找方法运行,然后再发送消息的时候,object_magsend方法不会返回值,所谓的返回值都是具体调用时执行的,然而当向一个nil对象发送消息时其对象的isa指针就返回0地址,所以不会发送任何错误。

网络相关

TCP/UDP

1:TCP建立流程:

1:为何要建立3次握手🤝?
当客服端发生请求发送了同步报文SYN到服务端,如果在传输过程中发生了超时逗留在网络路由中,发生超时后客户端会启用超时重传策略重新发送新的SYN同步报文到服务端,之后server端发送SYN同步报文、ACK确认报文到客户端,客户端再将ACK确认报文发送到服务端,这时在网络路由中逗留的超时报文传递到server端,server会以为是一次新的连接。,发送确认信息给发送端,但是当发送端没有理会的时候,接收端也就知道这是错误信息,就不会等待,也就没有资源浪费了。

DNS:

1:解释
DNS是 域名到IP地址的映射,DNS解析采用了UDP报文端口号为53且明文传输;
客户端通过DNS协议到DNS服务器请求对响应域名的一个解析,DNS把解析后的结果IP地址返回给客户端,再由客服端向IP server服务端发起请求
2:DNS解析的方式
递归查询、迭代查询
3:DNS常见的问题?
01:DNS劫持: 在向DNS服务器请求解析IP地址的过程中被钓鱼DNS服务窃听到返回一个错误的IP地址给客户端
02:DNS解析转发
4:如何防止DNS劫持呢?
01:httpDNS : 使用http协议向DNS服务器的80端口进行请求IP
02:长链接模式:

Session 、 cookie

对http无状态的特点的补充,
1:session和cookie的区别?
cookie:主要是记录用户状态,区分用户,状态保存在客户端中;
session: 记录用户状态,区分用户,状态存放在服务器端中;
2:怎么修改cookie?


多线程 GCD

自旋锁、互斥锁 选择

自旋锁:等待状态处于忙等
互斥锁:等待状态处于休眠

浅谈dispatch_once实现原理:

+ (instancetype)sharedInstance
{
  /*定义相应类实例的静态变量;
  意义:函数内定义静态变量,无论该函数被调用多少次,
       在内存中只初始化一次,并且能保存最后一次赋的值
  */
  static ClassName *instance = nil;
  /*定义一个dispatch_once_t(其实也就是整型)静态变量,
    意义:作为标识下面dispatch_once的block是否已执行过。
         static修饰会默认将其初始化为0,当值为0时才会执行block。
         当block执行完成,底层会将onceToken设置为1,这也就是为什
         么要传onceToken的地址(static修饰的变量可以通过地址修改
         onceToken的值),同时底层会加锁来保证这个方法是线程安全的
    */
    static dispatch_once_t onceToken;
    /*只要当onceToken == 0时才会执行block,否则直接返回静态变量instance*/
  dispatch_once(&onceToken, ^{
      instance = [[ClassName alloc] init];
      //...
  });
   return instance;
}

1、什么情况使用自旋锁比较划算?
预计线程等待锁的时间很短
加锁的代码(临界区)经常被调用,但竞争情况很少发生
CPU资源不紧张
多核处理器

2、什么情况使用互斥锁比较划算?
预计线程等待锁的时间较长
单核处理器
临界区有IO操作
临界区代码复杂或者循环量大
临界区竞争非常激烈

数据库相关操作

多线程操作共享资源的问题

方法交换

tableview 性能优化:

复用单元格
单元格中的视图尽量都使用不透明的,单元格中尽量少使用动画
图片加载使用异步加载
滑动时不加载图片,停止滑动时开始加载(需要处理快速滑动的空白)
单元格中的内容可以在自定义cell类中的drawRect方法内自己绘制
如非必要,减少reloadData全部cell,只reloadRowsAtIndexPaths
如果cell是动态行高,计算出高度后缓存
cell高度固定的话直接使用cell.rowHeight设置高度

https://www.jianshu.com/p/04457377b48d

webView

1.说一下 JS 和 OC 互相调用的几种方式?

通过替换js中的function(方法)
方式二:通过注入对象,直接调用对象方法
方式三:利用网页重定向,截取字符串.
方式四:

2.在使用 WKWedView 时遇到过哪些问题?
白屏问题,
Cookie 问题,
在WKWebView上直接使用NSURLProtocol无法拦截请求,
在WKWebView 上通过loadRequ发起的post请求body数据被丢失,截屏问题等

架构和框架相关

整理架构流程:
独立于APP的通用层(网络请求、时长统计框架、bug统计、第三方库等)
通用业务层(针对当下公司业务组件、有些UI的封装)
中间层 (协调和解耦,与业务之前紧密联系)
业务A、业务B、业务C、业务D

业务之间解耦的方式?
1: openUrl
2: 依赖注入

SDWebIMage基本流程

核心类 负责模块
SDWebImageManager 调度各个类
SDWebImageDownloader 下载
SDImageCache 缓存, 包括内存缓存和磁盘缓存
SDWebImageCodersManager 图片解码

1:图片通过什么方式进行读写,过程是怎么样的?
以图片URL的单项hash值作为key来存储到对于的框架中,读取是通过图片请求URL所对应的key进行查找,从内存中缓存,磁盘缓存中进行对应的查找都没有再进行下载操作,采取多级缓存的方式。
2:如果让你去设计SDWebImage的缓存机制,怎么去设计?
SDWebImage的缓存分为两种,一种是内存缓存(MemoryCache),另一种是硬盘缓存(DiskCache),我会自定义一个单例缓存类,其中会有对应的两种缓存作为属性,另外还会暴露一些自定义属性让用户可以去修改缓存的策略,例如最大缓存字节数,自动进行清理缓存还是不自动去清理等,还会暴露一些方法比如通过key去查找该缓存文件,当前key是否存在于沙盒或者内存中等。
3、 如何实现断点续传?
断点续传的理解可以分为两部分:一部分是断点,一部分是续传。断点的由来是在下载过程中,将一个下载文件分成了多个部分,同时进行多个部分一起的下载,当 某个时间点,任务被暂停了,此时下载暂停的位置就是断点了。续传就是当一个未完成的下载任务再次开始时,会从上次的断点继续传送。

使用多线程断点续传下载的时候,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,多个线程并发可以占用服务器端更多资源,从而加快下载速度。

在下载(或上传)过程中,如果网络故障、电量不足等原因导致下载中断,这就需要使用到断点续传功能。下次启动时,可以从记录位置(已经下载的部分)开始,继续下载以后未下载的部分,避免重复部分的下载。断点续传实质就是能记录上一次已下载完成的位置。
4、断点续传的过程
1.断点续传需要在下载过程中记录每条线程的下载进度;
2.每次下载开始之前先读取数据库,查询是否有未完成的记录,有就继续下载,没有则创建新记录插入数据库;
3.在每次向文件中写入数据之后,在数据库中更新下载进度;
4.下载完成之后删除数据库中下载记录。
5.如果让你去设计SDWebImage的缓存机制,怎么去设计?
SDWebImage的缓存分为两种,一种是内存缓存(MemoryCache),另一种是硬盘缓存(DiskCache),我会自定义一个单例缓存类,其中会有对应的两种缓存作为属性,另外还会暴露一些自定义属性让用户可以去修改缓存的策略,例如最大缓存字节数,自动进行清理缓存还是不自动去清理等,还会暴露一些方法比如通过key去查找该缓存文件,当前key是否存在于沙盒或者内存中等。

Swift

swift的优势有哪些?
1、Swift容易阅读,语法和文件结构简易化。
2、Swift更易于维护,文件分离后结构更清晰。
3、Swift更加安全,它是类型安全的语言。
4、Swift代码更少,简洁的语法,可以省去大量冗余代码
5、Swift速度更快,运算性能更高。

人事及领导问答面试题:

https://www.jianshu.com/p/7ca1737c65dc

提问环节

其它

自动打包--Jenkins相关步骤

上一篇下一篇

猜你喜欢

热点阅读