因为呆了2年的公司资金链出了问题,导致我3月8号离职,去旅游,去处理家里的事情花费了2个月的时间,现在5月份才开始找工作,以下是我面试中遇到的一些问题。总的来说,除了被阿里和酷狗的面试官虐了,其他的面试还是挺顺利。
1.非对称加密
https://www.jianshu.com/p/53b9ffe8fea6 非对象加密 数字签名 证书的仔细解析。
https://www.jianshu.com/p/929f10f40c40 RSA SSH 加密。
2.https 解析 比http更安全的原因
http://www.zixiong.org/blog/2018/02/12/https.html
https://www.jianshu.com/p/ce2a9bc519f5 iOS 的https适配。
3.app启动速度的优化。
1.延时启动读取io的操作.
减少非系统的framework依赖,如果framework 在当前 App 支持的所有 iOS 系统版本中都存在则设为 required,否则设置为 optional,optional 会有额外检查合并非系统库
删除无用的 class/selector/category
删除无用的方法调用、静态变量等减少 C++ 虚函数(减少创建虚函数表时间)
使用 Swift 的 struct (从而减少符号数量)
为不需要写的属性添加 readonly减少 +load() 方法,尽量使用 +initialize() 代替使用
dispatch_one() pthread_once() std::once() 代替 C/C++ attribute(constructor)
减少静态构造函数
初始化方法中不要使用 dlopen()
https://blog.csdn.net/u011452278/article/details/54966682 今日头条的优化文章
https://www.jianshu.com/p/d280feedbca0
4.可变容易插入空值奔溃怎么办?
-(void)insertSaveObject:(id)anObject atIndex:(NSUInteger)index
-(void)setSaveObject:(id)value forKey:(id)key
过滤
https://www.jianshu.com/p/96332619f2dd 框架 NullSafe
5.线程同步
1.NSLock
2.NSLock延伸之NSCondition线程通信处理
3.synchronized代码块
4.使用GCD 信号量解决资源抢占问题
5.dispatch_barrier_async
6.pthread_mutex_trylock 互斥锁
https://www.jianshu.com/p/40157a10133d
https://www.jianshu.com/p/c04343336193
iOS中保证线程安全的几种方式与性能对比
https://www.jianshu.com/p/938d68ed832c
6.代码安全
1.沙盒文件加密
2..h代码混淆
https://www.jianshu.com/p/3a9952aa9ed2
7.消息转发的机制
https://www.jianshu.com/p/367b2f6b461f VN逃生之路
8.区分深拷贝与浅拷贝
浅拷贝:指针拷贝,不增加新的内存。只是新增加一个指针指向原来的内存区域。
深拷贝:内容拷贝,同时拷贝指针和指针指向的内存。新增指针指向新增的内存。
拷贝条件:
iOS中并非所有的对象都支持copy和mutableCopy,只有遵循了NSCopy协议或者NSMutableCoy协议的类才行。如果遵循着两个协议就必须分别实现copyWithZone和mutableCopyZone方法
拷贝原则:
1.非容器类:像NSString、NSNumber这样的不能包含其他对象的系统类
不可变对象调用copy是浅拷贝;而调用muablecopy是深拷贝并得到可变对象
可变对象调用copy和mutablecopy都是深拷贝, 区别在于copy返回不可变对象,mutablecopy返回可变对象
2.容器类:像NSArray、NSMutableArray等系统类
不可变对象调用copy是浅拷贝,而调用muablecopy是深拷贝并得到可变对象。
可变对象调用copy和mutablecopy都是深拷贝,区别在于copy返回不可变对象,mutablecopy返回可变对象
容器类与非容器类的拷贝原则相似,但需要注意的是:所有的容器类的拷贝,拷贝后新容器里的元素始终是浅拷贝,其指针都指向原来对象。
3.自定义类:比如我们自定义一个Student类(实现拷贝协议)
拷贝协议的具体实现不同,拷贝效果也就不同。在实现的拷贝协议方法中直接返回对象的self就相当于浅拷贝了,但是是如果返回新创建对象就是深拷贝了。
9.区别Strong和weak
在网上找个比较形象的列子来方便理解:
想象我们研究的对象是一条狗,狗想要跑掉(被释放)。
1.Strong
strong型指针就像是栓住的狗。只要你用牵绳挂住狗,狗就不会跑掉。如果有5个人牵着一条狗(5个strong型指针指向1个对象),除非5个牵绳都脱落 ,否着狗是不会跑掉的。
2.Weak
weak型指针就像是一个小孩指着狗喊到:“看!一只狗在那” 只要狗一直被栓着,小孩就能看到狗,(weak指针)会一直指向它。只要狗的牵绳脱落,狗就会跑掉,不管有多少小孩在看着它。
总结:只要最后一个strong型指针不再指向对象,那么对象就会被释放,即使还有weak型指针指向它。一旦最后一个strong型指针离去 ,这个对象将被释放,所有剩余的weak型指针都将被清除。
10.区分MVC与MVVM
MVC弊端:Controller通常负责Model和View关联,造成View和Model的耦合度高,而且Controller变得庞大复杂。
MVVM优点:
1.低耦合。View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2.可重用性。可以把一些视图的逻辑放在ViewModel里面,让很多View重用这段视图逻辑。
3.独立开发。开发人员可以专注与业务逻辑和数据的开发(ViewModel)。设计人员可以专注于界面(View)的设计。
4.可测试性。可以针对ViewModel来对界面(View)进行测试
11.区分类目与扩展
类目:category 为已知的类增加新的方法
1.类目中扩展的方法会被子类继承
2.增加原有类的方法,而且是可以增加多个类目将大的功能划分为小功能。
3.类目中的方法会比原有类中的方法具有更高优先级。所以不能和原有类方法重名否则覆盖。
4.类目只能添加方法,不能添加变量
扩展:即延展,一般是在一个类的实现文件中。给当前类添加私有变量和私有方法。添加的方法是必须实现的
12.区分#include、#import和@class
"#include"
一般来说,导入objective-C的头文件时用#import,导入c/c++头文件用#include。include相当于拷贝文件中的声明内容,多次使用就会报重复定义的错误。如: class A,class B都引用了class C,而class D中又同时引用class A与class B,就会报重复引用的错误。
"#import"
不会产生重复定义的错误,因为它会做一次判断,如果已经导入就不再导入了
@class
@class仅仅是类的声明,告诉编译器有这么个类,具体这个类怎么定义一无所知。
@class在编译的时候,速度更快,解决引用循环依赖死锁的问题(类的扩展,代理设计模式)
@class还可以解决循环依赖的问题,例如A.h导入了B.h,而B.h导入了A.h,每一个头文件的编译都要让对象先编译成功才行。这样的话,在头文件中一般使用@class来声明这个名称是类的名称。 而在实现类里面,因为会用到这个引用类的内部的实体变量和方法,所以需要使用#import来包含这个被引用类的头文件。
注:#import<> 跟 #import””区别:#import<> 包含iOS框架类库里的类,#import""包含项目里自定义的类。
13.区分TCP和UDP
TCP:面向连接、传输可靠(保证数据正确性,保证数据顺序传输)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
UDP:面向非连接、传输不可靠、用于传输少量数据(数据包模式)、速度快,传输的是报文。
14.区分HTTP与Socket
HTTP请求:客户端主动发起请求,服务器才能给予响应,一次请求完毕后则断开连接,节省资源。
Socket:客户端与服务器端直接使用socket套接字连接,双方保持连接通道,都可以主动发送数据,适合游戏或股票等这种即时性很强的要求。主要使用的类是CFSockdetRef。
15.区分KVC和KVO
KVC:值编码,一种使用字符串标识属性,间接访问对象属性的方法。而不是调用存取方法。
KVO:观察者模式。通过监听对象的属性来更新UI或者状态
16.区分MD5和Base64两种加密
"数据加密的基本过程就是对原来为明文的文件或数据按某种算法进行处理,使其成为不可读的一段代码,通常称为“密文”,使其只能在输入相应的密钥之后才能显示出本来内容,通过这样的途径来达到保护数据不被非法人窃取、阅读的目的。 该过程的逆过程为解密,即将该编码**信息转化为其原来数据的过程。"
"加密技术通常分为两大类:“对称式”和“非对称式”。"
--------以上内容摘自百度--------
MD5:严格来说不算加密算法,只能说是摘要算法,而且是一种不可逆的摘要算法。MD5用于生成摘要,并且无法逆破解得到原文。我们常用它验证数据的有效性,比如,在网络请求接口中,通过将所有的参数生成摘要,客户端和服务端采用同样的规则生成摘要,验证数据的有效性。
Base64:一种用64个字符来表示任意二进制数据的编码方式,严格来说也不算是一种加密。Base64的操作是可逆的,经过encode加密,可以decode得到原文。Base64常用来解决网络请求中特殊编码问题和轻量型的加密(转化为非明文)。
关于这两种技术是否为加密算法的讨论有很多,我是这样理解的:
严格意义上来说,这两种技术都不能算是真正的加密算法。但是把明文转化为不可读的密文,这本就算是一种加密。在日常的开发工作中,我们经常用这两种方式将一些数据转为不可读密文,因此称它们叫做加密算法也不为过。至于是否为加密算法只是一种说法而已,只要理解了其基本原理与用法即可。又或许我们把它们叫作为一种加密方式会好些。
可参考链接:
加密算法
Base64编码原理与应用
17.区分define定义的宏和const定义的常量
define定义宏的指令,程序在预处理阶段将用#define所定义的内容只是进行了替换。因此程序运行时,常量表中并没有用#define所定义的宏,系统并不为它分配内存,而且在编译时不会检查数据类型,出错的概率要大一些。
const定义的常量,在程序运行时是存放在常量表中,系统会为它分配内存,而且在编译时会进行类型检查。
18.区分id与instancetype
id:万能指针,指向任意类型
instancetype:只能作为方法的范围类型,并且返回的类型是当前定义类的类型。
19.区分通知和代理
同:都用于对象之间的通信
异:代理是一对一通信。通知可以一对一,也可以一对多
20.区分methord和selector
selector只是一个方法名,而method包含了方法名和方法实现。
21.区分isKindOfClass 与isMemberOfClass
isKindOfClass:确定一个对象是否是一个类的成员,或者是派生自该类的成员.
isMemberOfClass:确定一个对象是否是当前类的成员.
注:isMemberOfClass不能检测任何的类都是基于NSObject类这一事实,而isKindOfClass可以。
22.区别面向过程和面向对象
面向过程:以事件为编程中心,各功能的实现是按照事件的先后顺序或者因果关系来展开的编程的一种思想
面向对象:以对象为编程的中心,以事件为驱动,各功能是模块化的,彼此之间独立互不影响的一种编程思想
23、使 系统的某些block api(如UIView的block版本写动画时),是否也考虑引 循环问题?
系统的某些block api中,UIView的block版本写动画时 需要考虑,但也有 些api 需要考虑:
所谓“引 循环”是指双向的强引 ,所以那些“单向的强引 ”(block 强引 self ) 没有问题, 如这些:
[UIView animateWithDuration:duration animations:^{ [self.superview layoutIfNeeded]; }];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.someProperty = xyz; }];
[[NSNotificationCenter defaultCenter] addObserverForName:@"someNotification"
object:nil queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification * notification) { self.someProperty = xyz; }];
这些情况 需要考虑“引 循环”。
但如果你使 些参数中可能含有 ivar 的系统 api ,如 GCD 、 NSNotificationCenter就要 点: 如GCD 内部如果引 self, 且 GCD 的 其他参数是 ivar,则要考虑到循环引 :
__weak typeof(self) weakSelf = self; dispatch_group_async(_operationsGroup, _operationsQueue, ^ {
typeof(self) strongSelf = weakSelf; [strongSelf doSomething];
[strongSelf doSomethingElse];
} );
类似的:
__weak typeof(self) weakSelf = self;
_observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"testKey"
object:nil queue:nil
usingBlock:^(NSNotification *note) { typeof(self) strongSelf = weakSelf;
[strongSelf dismissModalViewControllerAnimated:YES]; }];
self --> _observer --> block --> self 显然这也是 个循环引 。
检测代码中是否存在循环引 问题,可使 Facebook 开源的 个检测 具 FBRetainCycleDetector 。
24、静态库的原 是 么?你有没有 写过静态编译库,遇到 哪些问题?
库本质上讲是 种可执 的 进制格式,可以载 内存中执 。是程序代码的集合, 共享代码的 种 式。 静态库是闭源库, 公开源代码,都是编译后的 进制 件, 具体实现。 静态库 般都是以 .a 或者 .framework 形式存在。 静态库编译的 件 较 ,因为整个函数库的数据都会被整合到代码中,这样的好处 就是编译后的程序 需要外部的函数库 持, 好的 点就是如果改变静态函数库, 就需要程序重新编译。多次使 就有多份冗余拷 。 使 静态库的好处:模块化分 合作、可重 、避免少 改动导致 的重复编译链 接。 般公司都会有核 开发团队和普通开发团队,然后公司的核 业务由核 开发团队 写成静态库然后让普通开发团队调 ,这样就算普通开发团队离职也带 公司的核 业务代码。 般核 开发团队是 会离职的。 有静态库 然就有动态库 。这 所谓的静态和动态是相对编译期和运 期的。静态 库在程序编译时会被链接到代码中,程序运 时将 再需要改静态库, 动态库在编 译时 会被链接到代码中,只有程序运 时才会被载 ,所以 hook 别 程序或者说 做插件都是运 runtime 机制,然后动态库注 修改的。
制作 .a 件时候,要注意 CPU 架构的 持,i386、X86_64、 armv7、armv7s。 查看可以通过命令 “ lipo -info 静态库名称” 。模拟 .a 件和真机 .a 件合并可 以通过 "lipo -create 模拟 静态库1名 真机静态库2名 -output 新静态库名称" 些坑
命名 要太随意,毕竟是被别 拿过去 的要能看懂。 framework中 到 NSClassFromString,但是转换出来的class 直为nil。解决 法:在主 程的【Other Linker Flags】需要添加参数【-ObjC]即可。 如果Xcode找 到框架的头 件,你可能是忘记将它们声明为public 。 解决 法: 进 target的Build Phases ,展开Copy Headers项,把需要public的头 件从 Project或Private部分拖拽到Public部分。
尽 要 xib 。由于静态框架采 静态链接,linker会剔除所有它认为 的代码。 幸的是,linker 会检查xib 件,因此如果类是在xib中引 , 没有在O-C代码中 引 ,linker将从最终的可执 件中删除类。这是linker的问题, 是框架的问题 (当你编译 个静态库时也会发 这个问题)。苹果内置框架 会发 这个问题,因 为他们是运 时动态加载的,存在于iOS设备固件中的动态库是 可能被删除的。 有两个解决的办法:
1、 让框架的最终 户关闭linker的优化选项,通过在他们的项 的Other Linker Flags中添加-ObjC和-all_load。
2、 在框架的另 个类中加 个该类的代码引 。 如,假设你有个MyTextField类, 被linker剔除 。假设你还有 个MyViewController,它在xib中使 MyTextField,MyViewController并没有被剔除。你应该这样做: 在MyTextField中:
+(void)forceLinkerLoad_ {}
在MyViewController中:
+(void)initialize {[MyTextField forceLinkerLoad_];}
他们仍然需要添加-ObjC到linker设置,但 需要强制all_load 。 第2种 法需要你多做 点 作,但却让最终 户避免在使 你的框架时关闭linker优 化(关闭linker优化会导致object 件膨胀)。
25、 动指定autoreleasepool的前提下, 个autorealese对象在 么时刻释放? ( 如在 个vc的viewDidLoad中创建) 分两种情况: 动 预释放时机、系统 动去释放。
- 动 预释放时机--指定autoreleasepool 就是所谓的:当前作 域 括号结束时 释放。
- 系统 动去释放-- 动指定autoreleasepool
Autorelease对象出 作 域之后,会被添加到最近 次创建的 动释放池中,并会在 当前的 runloop 迭代结束时释放。
释放的时机总结起来,可以 下图来表示:
从程序启动到加载完成是 个完整的运 循环,然后会停下来,等待 户交互, 户 的每 次交互都会启动 次运 循环,来处 户所有的点击事件、触摸事件。 我们都知道: 所有 autorelease 的对象,在出 作 域之后,会被 动添加到最近创 建的 动释放池中。
但是如果每次都放进应 程序的 main.m 中的 autoreleasepool 中,迟早有被撑满的 刻。这个过程中必定有 个释放的动作。何时? 在 次完整的运 循环结束之前,会被销毁。
那 么时间会创建 动释放池?
A:运 循环检测到事件并启动后,就会创建 动释放池。
B: 线程的 runloop 默认是 作, 法主动创建,必须 动创建。( 展:run loop和线程是紧密相连的,可以这样说run loop是为 线程 ,没有线程,它就没有 存在的必要。Run loops是线程的基础架构部分)
C: 定义的 NSOperation 和 NSThread 需要 动创建 动释放池。 如: 定 义的 NSOperation 类中的 main 法 就必须添加 动释放池。否则出 作 域后, 动释放对象会因为没有 动释放池去处 它, 造成内存泄 。
但对于 blockOperation 和 invocationOperation 这种 默认的Operation ,系统已经帮 我们封装好 , 需要 动创建 动释放池。
@autoreleasepool 当 动释放池被销毁或者耗尽时,会向 动释放池中的所有对象发 送 release 消息,释放 动释放池中的所有对象。 如果在 个vc的viewDidLoad中创建 个 Autorelease对象,那么该对象会在 viewDidAppear 法执 前就被销毁 。
26、OC完整的消息转发机制+代码实现【 击】。
消息转发分为两 阶段。第 阶段先征询接收者,所属的类,看其是否能动态添加 法,以处 当前这个“未知的选择 ”,这叫做“动态 法解析”。 第 阶段涉及“完整的消息转发机制(full forwarding mechanism)”如果运 期系统 已经执 完第 阶段,此时,运 期系统会请求我接收者以其它 段来处 消息。可 以细分两 步。1. 先查找有没有replacement receiver进 处 。若 ,2.运 期系 统把Selector相关信息封装到NSInvocation对象中,再给 次机会,若依旧未处 则 让NSObject调 doNotReconizeSelector: 接收者在每 步中均有机会处 消息,步骤越往后,处 消息的代价越 。最好能在 第 步就处 完,这样Runtime System可以将 法缓存起来,第三步除 修改 标相 第 步还要创建处 NSInvocation。
27、iOS app启动如何优化?
- 我们可以通过在 Xcode 中 Edit scheme -> Run -> Auguments 将环境变 DYLD_PRINT_STATISTICS 设为 1,在控制台看到main()函数之前的启动时间。
- 分解优化 标 分步达到优化 的 1). 耗时操作异步处
2). 如果启动流程依赖 络请求回来才能继续,那么需要考虑 络极差情况下的启
动速度
3). 如果APP有loading 告 并且对分辨率的要求较 ,请尝试做缓存吧
4). 主 Controller中的viewDidLoad和viewWillAppear 法中尽 少做事情 5). 排查清 项 中未使 到的类库以及Framework
6). 删减合并 些OC类,删减没有 到或者可以 的静态变 、 法等
7). 轻 化+load 法中的内容,可延迟到+initialize中
28、UITableView性能优化,超实
- Cell重 1.1>数据源 法优化
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
在可 的 会重复绘制 ,每次刷新显示都会去创建新的Cell, 常耗费性 能。
解决 案: 先创建 个静态变 reuseID(代 法返回Cell会调 很多次,防 重复创建,static保证只会被创建 次,提 性能),然后,从缓存池中取相应 identifier的Cell并 新数据,如果没有,才开始alloc新的Cell,并 identifier标识 Cell。每个Cell都会注册 个identifier(重 标识符)放 缓存池,当需要调 的时 候就直接从缓存池 找对应的id,当 需要时就放 缓存池等待调 。(移出屏幕的 Cell才会放 缓存池中,并 会被release)所以在数据源 法中做出如下优化:
// 调 次数太多,static 保证只创建 次reuseID,提 性能
static NSString *reuseID = “reuseCellID”;
// 缓存池中取已经创建的cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseID];
1.2>缓存池的实现
当Cell要alloc时,UITableView会在堆中开辟 段内存以供Cell缓存之 。Cell的重 通过identifier标识 同类型的Cell,由此可以推断出,缓存池外层可能是 个可变 字典,通过key来取出内部的Cell, 缓存池为存储 同 度、 同类型(包含图 、 Label等)的Cell,可以推断出缓存池的字典内部可能是 个可变数组, 来存放 同 类型的Cell,缓存池中只会保存已经被移出屏幕的 同类型的Cell。
1.3>缓存池获取可重 Cell两个 法的区别
-(nullable __kindof UITableViewCell *)dequeueReusableCellWithIdentifier: (NSString *)identifier;
这个 法会查询可重 Cell,如果注册 原型Cell,能够查询到,否则,返回nil; 且需要判断if(cell == nil),才会创建Cell, 推荐
-(__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(6_0);
使 这个 法之前,必须通过xib(storyboard)或是Class(纯代码)注册可重 Cell, 且这个 法 定会返回 个Cell
注册Cell - (void)registerNib:(nullable UINib *)nib forCellReuseIdentifier:(NSString
*)identifier NS_AVAILABLE_IOS(5_0); - (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier NS_AVAILABLE_IOS(6_0);
好处:如果缓冲区 Cell 存在,会使 原型 Cell 实 化 个新的 Cell, 需要再判 断,同时代码结构 清晰。
- 定义 种(尽 少)类型的Cell及善 hidden隐藏(显示)subviews
2.1> 种类型的Cell
分析Cell结构,尽可能的将 相同内容的抽取到 种样式Cell中,前 已经提到
Cell的重 机制,这样就能保证UITbaleView要显示多少内容,真正创建出的Cell可能 只 屏幕显示的Cell多 点。虽然Cell的’体积’可能会 点,但是因为Cell的数 会 很多,完全可以接受的。好处:
- 减少代码 ,减少Nib 件的数 ,统 个Nib 件定义Cell,容 修改、维护
- 基于Cell的重 ,真正运 时铺满屏幕所需的Cell数 致是固定的,设为N个。所 以如果如果只有 种Cell,那就是只有N个Cell的实 ;但是如果有M种Cell,那么运 时最多可能会是“M x N = MN”个Cell的实 ,虽然可能并 会占 太多内存,但是 能少点 是 好吗。
2.2>善 hidden隐藏(显示)subviews
只定义 种Cell,那该如何显示 同类型的内容呢?答案就是,把所有 同类型的 view都定义好,放在cell ,通过hidden显示、隐藏,来显示 同类型的内容。毕 竟,在 户快速滑动中,只是单纯的显示、隐藏subview 实时创建要快得多。
- 提前计算并缓存Cell的 度 在iOS中, 设UITableViewCell的预估 的情况下,会优先调
”tableView:heightForRowAtIndexPath:” 法,获取每个Cell的即将显示的 度, 从 确定UITableView的布局,实际就是要获取contentSize(UITableView继承 UIScrollView,只有获取滚动区域,才能实现滚动),然后才调 ”tableView:cellForRowAtIndexPath”,获取每个Cell,进 赋值。如果项 中模块有 10000个Cell需要显示,可想 知...
解决 案:我个 认为,可以创建 个frame模型,提前计算每个Cell的 度。参考 其中 篇博客的时候,在解决这个问题的时候,可以将计算Cell的 度放 数据模 型,但这与MVC设计模式可能稍微有点冲突,这个时候我就想到MVVM这种设计模 式,这个时候才能稍微有点MVVM这种设计模式的优点(其实还是很 解的),可 以讲计算Cell 度放 ViewModel(视图模型)中,让Model(数据模型)只负责处 数据。
4.异步绘制( 定义Cell绘制) 遇到 较复杂的界 的时候,如复杂点的图 混排,上 的那种优化 的 式可
能就 能满 要求 ,当然 ,由于我的开发经验尚短,说实话,还没遇到要将 定 义的Cell重新绘制
5.滑动时,按需加载 开发的过程中, 定义Cell的种类千奇百怪,但Cell本来就是 来显示数据的, 说
100%带有图 ,也差 多,这个时候就要考虑,下滑的过程中可能会有点卡顿,尤其 络 好的时候,异步加载图 是个程序员都会想到,但是如果给每个循环对象都加 上异步加载,开启的线程太多, 样会卡顿,我记得好像线程条数 般3-5条,最多 也就6条吧。这个时候 UIScrollViewDelegate两个代 法就能很好地解决这个问 题。
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate: (BOOL)decelerate
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
6.缓存View
当Cell中的部分View是 常独 的,并且 于重 的, 且“体积” 常 ,在内 存可控的前提下,我们完全可以将这些view缓存起来。当然也是缓存在模型中。
7.避免 的图 缩放、颜 渐变等,尽 显示“ 刚好合适的图 资源” 8.避免同步的从 络、 件获取数据,Cell内实现的内容来 web,使 异步加载,缓 存请求结果
9.渲染
9.1>减少subviews的个数和层级 控件的层级越深,渲染到屏幕上所需要的计算 就越 ;如多 drawRect绘制
元素,替代 view显示 9.2>少 subviews的透明图层
对于 透明的View,设置opaque为YES,这样在绘制该View时,就 需要考虑 被View覆盖的其他内容(尽 设置Cell的view为opaque,避免GPU对Cell下 的内容 也进 绘制)
9.3>避免CALayer特效(shadowPath) 给Cell中View加阴影会引起性能问题,如下 代码会导致滚动时有明显的卡顿:
view.layer.shadowColor = color.CGColor; view.layer.shadowOffset = offset; view.layer.shadowOpacity = 1; view.layer.shadowRadius = radius;
29、dispatch_barrier_async的作 是 么?
在并 队 中,为 保持某些任务的顺序,需要等待 些任务完成后才能继续进 , 使 barrier 来等待之前任务完成,避免数据竞争等问题。 dispatch_barrier_async 函数会等待追加到Concurrent Dispatch Queue并 队 中的操作全部执 完之后, 然后再执 dispatch_barrier_async 函数追加的处 ,等 dispatch_barrier_async 追加的处 执 结束之后,Concurrent Dispatch Queue才恢复之前的动作继续执 。
打个 : 如你们公司周末跟团旅游, 速休息站上,司机说: 家都去上厕所, 速战速决,上完厕所就上 速。超 的公共厕所, 家同时去,程序猿很快就结束 ,但程序媛就可能会慢 些,即使你第 个回来,司机也 会出发,司机要等待所 有 都回来后,才能出发。 dispatch_barrier_async 函数追加的内容就如同 “上完厕 所就上 速”这个动作。
(注意:使 dispatch_barrier_async ,该函数只能搭配 定义并 队 dispatch_queue_t 使 。 能使 : dispatch_get_global_queue ,否则
dispatch_barrier_async 的作 会和 dispatch_async 的作 模 样。 )
30.NSDictionary 的原理
https://www.jianshu.com/p/d4b5542740d5
31.哈希表 链表
哈希表(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
哈希表hashtable(key,value) 就是把Key通过一个固定的算法函数既所谓的哈希函数转换成一个整型数字即哈希值,然后就将该数字对数组长度进行取余,取余结果就当作数组的下标,将value存储在以该数字为下标的数组空间里。
而当使用哈希表进行查询的时候,就是再次使用哈希函数将key转换为对应的数组下标,并定位到该空间获取value,如此一来,就可以充分利用到数组的定位性能进行数据定位。
链表
链式存储的线性表,简称链表。链表由多个链表元素组成,这些元素称为节点。结点之间通过逻辑连接,形成链式存储结构。存储结点的内存单元,可以是连续的也可以是不连续的。逻辑连接与物理存储次序没有关系。
**链表分为两个域: **
值域:用于存放结点的值
链域:用于存放下一个结点的地址或位置
从内存角度出发: 链表可分为 静态链表、动态链表。
从链表存储方式的角度出发:链表可分为 单链表、双链表、以及循环链表。
https://www.jianshu.com/p/88dfc8f405ab
32.OC中load方法和initialize方法的异同
https://www.jianshu.com/p/a00918b73274
33.查找二维数组的数字
OC实现代码
https://www.jianshu.com/p/7d7e63493740
34.block相关
https://www.jianshu.com/p/51d04b7639f1
35.阿里面试问题答案集合
https://www.jianshu.com/p/86894804db1c
36.排序算法8种
https://www.jianshu.com/p/88962dceaad1
37.谷歌智商题目
https://blog.csdn.net/u010850094/article/details/55518326
38.UIView,UIControl,UIResponder之间的关系
UIControl->(继承于)UIView->UIResponder
39.assgin 和weak的区别?
weak 当引用的对象被释放 会把指针置空。
assgin 不会指针置空。
40.通知NSNotification是同步还是异步?
同步
https://www.jianshu.com/p/c73e22ae23df
41.mrc 和arc的区别
https://www.jianshu.com/p/500d63eb7e89
42.一张图片的内存占用大小是由什么决定的
相片的大小是根据照片的分辨率来计算的,分辨率越高则相片体积越大,按家用相片尺寸来计算一般从低至30万像素(10kb-30kb内存),高至800万(3mb-5mb)不等。
图片是很多个像素(pixel)点组合在一起的.
43.isEqual与hash的区别.
iOS开发 之 不要告诉我你真的懂isEqual与hash!
https://www.jianshu.com/p/915356e280fc?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation
hash 最好的重写的方式:
In reality, a simple XOR over the hash values of critical properties is sufficient 99% of the time(对关键属性的hash值进行位或运算作为hash值)
44.直播的时候如何将摄像头和正在输入键盘的视图合在一起?
https://www.jianshu.com/p/ba1f79f8f6fa
45.可变集合使用copy修饰会不会有问题?
不管是集合类对象,还是非集合类对象,接收到copy和mutableCopy消息时,都遵循以下准则:
copy返回imutable对象;所以,如果对copy返回值使用mutable对象接口就会crash;
mutableCopy返回mutable对象;
下面将针对非集合类对象和集合类对象的copy和mutableCopy方法进行具体的阐述
https://www.zybuluo.com/MicroCai/note/50592
46.@synthesize和@dynamic分别有什么作用?
@property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
@synthesize 的语义是如果你没有手动实现 setter 方法和 getter 方法,那么编译器会自动为你加上这两个方法。
@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
47.GET和POST的区别?
https://www.jianshu.com/p/dd9bde6969c8
48.对象销毁时间表
// 对象的内存销毁时间表
// http://weibo.com/luohanchenyilong/ (微博@iOS程序犭袁)
// https://github.com/ChenYilong
// 根据 WWDC 2011, Session 322 (36分22秒)中发布的内存销毁时间表
1. 调用 -release :引用计数变为零
* 对象正在被销毁,生命周期即将结束.
* 不能再有新的 __weak 弱引用, 否则将指向 nil.
* 调用 [self dealloc]
2. 子类 调用 -dealloc
* 继承关系中最底层的子类 在调用 -dealloc
* 如果是 MRC 代码 则会手动释放实例变量们(iVars)
* 继承关系中每一层的父类 都在调用 -dealloc
3. NSObject 调 -dealloc
* 只做一件事:调用 Objective-C runtime 中的 object_dispose() 方法
4. 调用 object_dispose()
* 为 C++ 的实例变量们(iVars)调用 destructors
* 为 ARC 状态下的 实例变量们(iVars) 调用 -release
* 解除所有使用 runtime Associate方法关联的对象
* 解除所有 __weak 引用
* 调用 free()
49.tableview用到什么设计模式?
享元模式 代理模式
50.weak全解析
https://www.jianshu.com/p/95b80ec80008
51.UIView的生命周期
52.APP大部分崩溃类型的处理
https://www.jianshu.com/p/f63395599633
53.tcp的粘包处理
https://www.cnblogs.com/kex1n/p/6502002.html
54.离屏渲染
https://blog.csdn.net/zhonggaorong/article/details/52757758
55.数据库表的字段冲突如何解决
1.判断数据库表的版本号是不是有更新。
2.有更新先创建了临时 temp表,再把数据导入temp 表。
3.再把以前的表删除掉,再把temp名字改回来。
TableView优化
https://www.jianshu.com/p/2d077da3af94
网络优化
https://mp.weixin.qq.com/s?__biz=MzA4ODk0NjY4NA==&mid=2701606623&idx=1&sn=91a613963e43d432cf8e01af7e057491&chksm=b4d1fc4c83a6755a757975820dba16c72a4876790d708cab236a8b3387cbcef1619371331665&scene=0&pass_ticket=TR%2BQytj%2Fe3F0LkKmFLneOMMrVCSn0BZVsARKST848l95O0lwRLRGFjl7yJAoRERM#rd
招聘一个靠谱的iOS
https://www.jianshu.com/p/a9e4c8914e67