Men的博客

欢迎光临!

0%

UI相关

drawRect和layouSubviews 的区别

1 layoutSubviews方便数据计算,
2 drawRect方便视图重绘。
layoutSubviews在以下情况下会被调用:
addSubview、改变view的大小、滚动一个UIScrollView、
旋转Screen会触发父UIView上的layoutSubviews,调用setLayoutSubviews。
drawRect在以下情况下会被调用:(必须有大小)
loadView,viewDidLoad,sizeToFit
直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:
强制layout刷新,调用setNeedsLayout来代替

setNeedsLayout与layoutIfNeeded的区别

UIView的setNeedsDisplay和setNeedsLayout两个方法都是异步执行的。
而setNeedsDisplay会自动调用drawRect方法,这样可以拿到
UIGraphicsGetCurrentContext进行绘制;而setNeedsLayout会默认调用
layoutSubViews,给当前的视图做了标记;layoutIfNeeded
查找是否有标记,如果有标记及立刻刷新。
只有setNeedsLayout和layoutIfNeeded这二者合起来使用,才会起到立刻刷新的效果。

Core Graphics的更底层的是什么;

 1)获取上下文
 2)绘制路径
 3)添加路径到上下文
 4)修改图形状态参数
 5)渲染上下文
 CGContextRef、CGPathRef、UIBezierPath

iOS 保持界面流畅的技巧

1.预排版,提前计算
在接收到服务端返回的数据后,尽量将 CoreText 排版的结果、单个控件的高度、cell 整体的高度提前计算好,将其存储在模型的属性中。需要使用时,直接从模型中往外取,避免了计算的过程。
尽量少用 UILabel,可以使用 CALayer 。避免使用 AutoLayout 的自动布局技术,采取纯代码的方式
2.预渲染,提前绘制
例如圆形的图标可以提前在,在接收到网络返回数据时,在后台线程进行处理,直接存储在模型数据里,回到主线程后直接调用就可以了
避免使用 CALayer 的 Border、corner、shadow、mask 等技术,这些都会触发离屏渲染。
3.异步绘制
4.全局并发线程
5.高效的图片异步加载

Runtime

消息转发的流程

(动态添加) 首先是征询接收者所属的类,看其是否能动态添加调用的方法,来处理当前这个未知的选择子;
-(BOOL)resolveInstanceMethod:(SEL)selector
(重定向-备援接收者)寻找是否在其他对象内有该方法实现,并将该消息转发给这个对象

  • (id)forwardingTargetForSelector:(SEL)aSelector
    生成方法签名,然后系统用这个方法签名生成NSInvocation对象。
  • (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    改变选择子
  • (void)forwardInvocation:(NSInvocation *)Invocation
    抛出异常
  • (void)doesNotRecognizeSelector:(SEL)aSelector方法

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

    每一个类对象中都一个方法列表,方法列表中记录着方法的名称,方法实现,
    以及参数类型,其实selector本质就是方法名称,
    通过这个方法名称就可以在方法列表中找到对应的方法实现.

    map_images 函数Runtime 初始化操作

    在runtime中所有类都存在一个哈希表中,在table的buckets中存储
  1. 加载所有类到类的gdb_objc_realized_classes表中
  2. 对所有类做重映射
  3. 将所有SEL都注册到namedSelectors表中
  4. 修复函数指针遗留
  5. 将所有Protocol添加到protocol_map表中
  6. 将所有Protocol重映射
  7. 初始化所有非懒加载的类,进行rw,ro操作
  8. 便利所有懒加载类,执行初始化
  9. 处理所有Category包括Class和MetaClass
  10. 初始化所有未初始化类

    msgSend参数都有哪些;

    内存管理

    NSObject内存分配、ISA指针的内存大小

    在64位架构下,如果他的第一位是0 。则代表他是一个 isa
    指针,表示当前对象的类对象的地址,如果是1,则不仅代表一个 isa
    指针,类对象的地址,里面还存储内存管理相关的内容,第二位代表是否有关联对象,
    0代表没有,1代表有(has_assoc),第三位,代表当前对象是否含有C++代码
    (has_cxx_dtor),3-15表示当前对象的类对象内存地址,16-31
    ,也是,32-35位也是,也就是说,13+16+4 = 33位

    子线程默认不会开启 Runloop,那出现 Autorelease 对象如何处理,在什么情况下子线程使用AutoreleasePool

    在子线程你创建了 Pool 的话,产生的 Autorelease 对象就会交给 pool 去管理。
    如果你没有创建 Pool ,但是产生了 Autorelease 对象,就会调用 autoreleaseNoPage
    方法。在这个方法中,会自动帮你创建一个 hotpage(hotPage 可以理解为当前正在使用的
    AutoreleasePoolPage,如果你还是不理解,可以先看看 Autoreleasepool
    的源代码,再来看这个问题 ),并调用 page->add(obj)将对象添加到
    AutoreleasePoolPage 的栈中,也就是说你不进行手动的内存管理,也不会内存泄漏啦!

    dealloc调用流程

  11. 直接调用 objc_destructInstance()。
  12. 之后调用C的 free() 函数。
  13. objc_destructInstance() 调用流程
    1>.先判断 hasCxxDtor,是否有析构函数(析构器),
    要调用 object_cxxDestruct() ,释放(清除成员变量)。
    2>.再判断hasAssocitatedObjects,如果有的话,
    要调用object_remove_associations(), 移除当前对象的关联对象。
    3>.然后调用 clearDeallocating()。 
  14. clearDeallocating() 调用流程
    0>. 判断isa是否优化过,从arm64架构开始,对isa进行了优化,
    变成了一个共用体(union)结构,所以结果一般是优化过了。
    判断是否有弱引用或者引用计数
    1>.执行 clearDeallocating_slow()。
    2>.再执行 weak_clear_no_lock,在这一步骤中,会将指向该对象的弱引用指针置为 nil。
    3>.接下来执行 table.refcnts.eraser(),从引用计数表中擦除该对象的引用计数。
    4>.至此为止,Dealloc 的执行流程结束。

    怎么检查内存泄露

    启用Zombie Object进行悬挂指针的检测。
    应用Product -> Analysis进行内存泄露的初步检测。
    可以在xcode的build setting中打开implicit retain of ‘self’
    within blocks,xcode编译器会给出警告,逐个排查警告。
    应用Leak Instrument进行内存泄露查找。
    在以上方法不奏效的情况下,通过查看dealloc是否调用查看某个class是否泄露的问题

内存泄漏的原因

内存泄漏(memory leak):是指申请的内存空间使用完毕之后未回收。
一次内存泄露危害可以忽略,但若一直泄漏,无论有多少内存,迟早都会被占用光,
最终导致程序crash。(因此,开发中我们要尽量避免内存泄漏的出现)
内存溢出(out of memory):是指程序在申请内存时,没有足够的内存空间供其使用。
通俗理解就是内存不够用了,通常在运行大型应用或游戏时,应用或游戏所需要
的内存远远超出了你主机内安装的内存所承受大小,就叫内存溢出。最终导致机器重启或者程序crash。
第一种:静态分析方法(Analyze)
第二种:动态分析方法(Instrument工具库里的Leaks)。一般推荐使用第二种。

举例一些I/O操作的例子

1)阻塞IO
2)非阻塞IO
3)IO复用(select和poll)
4)信号驱动IO(sigio)
5)异步IO(aio_)

如何开辟一块内存;

其实结论就是 实际分配内存是按照16字节对齐的 内存大小都是16 的倍数。

怎么控制内存和优化内存;如果是你考虑怎么优化内存,从什么地方着手

复用机制
少使用xib
不要阻塞线程
图片优化
合理使用数组字典优化查找速度
懒加载
缓存
一些objects的初始化很慢,比如NSDateFormatter和NSCalendar。可以用单例来处理,避免日期格式转换
选择正确的数据格式,json、xml、二进制数据流
少使用webView
优化tableView
选择正确的数据持久化

问堆和栈的区别。

(答对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。)

RunLoop

RunLoop概念及数据结构、事件循环机制

CFRunLoop
CFRunLoopMode
Source/Timer/Observer
source0
需要手动唤醒线程
source1
具备唤醒线程的能力
CFRunLoopObserver
观测时间点
kCFRunLoopEntry
kCFRunLoopBeforeTimers
CommonMode的特性
NSRunLoopCommonModes
commonMode不是实际存在的一种mode
是同步Source/Timer/Observer到多个Mode中的一种技术方案
一个 RunLoop 包含若干个 Mode,每个 Mode 又包含若干个
Source/Timer/Observer。每次调用 RunLoop 的主函数时,只能指定其中一个
Mode,这个Mode被称作 CurrentMode。如果需要切换 Mode,只能退出
Loop,再重新指定一个 Mode 进入。这样做主要是为了分隔开不同组的
Source/Timer/Observer,让其互不影响。

RunLoop和多线程

在异步线程中下载很多图片,如果失败了,该如何处理?请结合RunLoop来谈谈解决方案
在异步线程中启动一个RunLoop重新发送网络请求,下载图片
如果程序启动就需要执行一个耗时操作,你会怎么做?
开启一个异步的子线程,并启动它的RunLoop来执行该耗时操作

你在开发过程中怎么使用RunLoop?什么应用场景?

开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来的消息,处理其他事件)
在子线程中开启一个定时器
在子线程中进行一些长期监控
可以控制定时器在特定模式下运行
可以让某些事件(行为,任务)在特定模式下执行
可以添加observer监听RunLoop的状态,比如监听点击事件的处理(比如在所有点击事件前做一些处理)
1)NSTimer
2)ImageView显示:控制方法在特定的模式下可用
3)PerformSelector
4)常驻线程:在子线程中开启一个runloop
5)自动释放池

多线程

GCD、NSOperation、NSThread区别优缺点

第一种:pthread
a.特点:
1)一套通用的多线程API
2)适用于Unix\Linux\Windows等系统
3)跨平台\可移植
4)使用难度大
b.使用语言:c语言
c.使用频率:几乎不用
d.线程生命周期:由程序员进行管理
第二种:NSThread
a.特点:
1)使用更加面向对象
2)简单易用,可直接操作线程对象
b.使用语言:OC语言
c.使用频率:偶尔使用
d.线程生命周期:由程序员进行管理
第三种:GCD
a.特点:
1)旨在替代NSThread等线程技术
2)充分利用设备的多核(自动)
b.使用语言:C语言
c.使用频率:经常使用
d.线程生命周期:自动管理
第四种:NSOperation
a.特点:
1)基于GCD(底层是GCD)
2)比GCD多了一些更简单实用的功能
3)使用更加面向对象
b.使用语言:OC语言
c.使用频率:经常使用
d.线程生命周期:自动管理

如何让多个网络请求完成后执行下一步

dispatch_group_t

多个网络请求顺序执行后执行下一步

dispatch_semaphore_wait

异步操作两组数据时, 执行完第一组之后, 才能执行第二组

dispatch_barrier_async

你知道哪些锁、使用场景

@synchronized 一个对象层面的锁,锁住了整个对象,底层使用了互斥递归
锁来实现
pathread_mutex 互斥锁(c语言)和信号量的实现原理类似,也是阻塞线程并进入睡眠
,需要进行上下文切换。
NSLock 对象锁-简单的互斥锁(内部封装了一个 pthread_mutex)
NSCondition (封装了一个互斥锁和条件变量。互斥锁保证线程安全,条件
NSCondition和NSLock、@synchronized等是不同的是,
NSCondition可以给每个线程分别加锁,加锁后不影响其他线程进入临界区。
这是非常强大。
NSConditionLock (借助 NSCondition 来实现,本质是生产者-消费者模型)
也可以像NSCondition一样做多线程之间的任务等待调用,而且是线程安全的。
NSRecursiveLock 递归锁有时候“加锁代码”中存在递归调用,递归开始前加
dispatch_semaphore GCD中信号量,也可以解决资源抢占问题,
支持信号通知和信号等待。每当发送一个信号通知,则信号量+1;
每当发送一个等待信号时信号量-1,;如果信号量为0则信号会处于等待状态,
直到信号量大于0开始执行
OSSpinLock 自旋锁(不建议使用)
自旋锁的实现原理比较简单,就是死循环。当a线程获得锁以后,b线程想要获取
锁就需要等待a线程释放锁。在没有获得锁的期间,b线程会一直处于忙等的状
态。如果a线程在临界区的执行时间过长,则b线程会消耗大量的cpu时间,不太
划算。所以,自旋锁用在临界区执行时间比较短的环境性能会很高。

自旋和互斥对比

相同点:都能保证同一时间只有一个线程访问共享资源。
都能保证线程安全。
不同点:
互斥锁:如果共享数据已经有其他线程加锁了,线程会进入
休眠状态等待锁。一旦被访问的资源被解锁,则等待资源的
线程会被唤醒。
自旋锁:如果共享数据已经有其他线程加锁了,线程会以死循环
的方式等待锁,一旦被访问的资源被解锁,则等待资源的线程会
立即执行。
自旋锁的效率高于互斥锁。
由于自旋时不释放CPU,因而持有自旋锁的线程应该尽快释放
自旋锁,否则等待该自旋锁的线程会一直在哪里自旋,这就会浪
费CPU时间。
持有自旋锁的线程在sleep之前应该释放自旋锁以便其他可以获得
该自旋锁。内核编程中,如果持有自旋锁的代码sleep了就可能
导致整个系统挂起。

runloop与autoreleasepool的关系

(AutoreleasePool并没有单独的结构,而是由若干个AutoreleasePoolPage以双向链表的形式组成)
AutoreleasePoolPage每个对象会开辟4096字节内存(也就是虚拟内存一页的大小),
除了上面的实例变量所占空间,剩下的空间全部用来储存autorelease对象的地址
iOS里的TaggedPointer不适用autorelesepool
AutoreleasePool 在 runloop 在开始时被push,在runloop休眠时(beforewaiting状态)pop

GCD 在Runloop中的使用

GCD由 子线程 返回到 主线程,只有在这种情况下才会触发 RunLoop。会触发 RunLoop 的 Source 1 事件。

GCD Global队列创建线程进行耗时操作的风险

dispatch_async 函数分发到全局队列不一定会新建线程执行任务,全局队列底层有一个的线程池,如果线程池满了,
那么后续的任务会被 block 住,等待前面的任务执行完成,才会继续执行。如果线程池中的线程
长时间不结束,后续堆积的任务会越来越多,此时就会存在 APP crash的风险。
避免使用 GCD Global 队列创建 Runloop 常驻线程

NSOperation数据结构

ddDependency操作依赖性
KVO 兼容属性
cancelAllOperations 响应取消命令
start;执行操作
NSBlockOperation:用于管理一个或多个block的并发执行。
NSInvocationOperation:NSInvocationOperation类是NSOperation的一个具体
子类,用于开启一个操作,该操作包括在指定对象上调用一个selector。

重写NSOperation需要注意的点

1、如果需要自定义并发执行的 Operation,必须重写start、main、isExecuting、isFinished、isAsynchronous方法。
2、在 operation 的 main 方法里面,必须提供 autorelease pool,因为你的 operation 完成后需要销毁。
3、一旦你的 operation 开始了,必须通过 KVO,告诉所有的监听者,现在该operation的执行状态。
4、调用时,如果需要并发执行 Operation,必须调用performOperation:方法,当然,也可以改为自定义其他方法或者直接在start方法添加多线程调用。
5、对于自定义的 Operation 类,如果不需要并发执行,可以直接调用start

进程中的哪些空间是线程所共有的?

一个进程中的所有线程共享该进程的地址空间,但它们有各自独立的(/私有的)栈(stack)

使用GCD需要注意什么;

dispatch_sync同步死锁(循环等待)
重复的获取互斥资源引发的等待(加锁)
开启过多线程
线程和RunLoop,子线程不会开启runloop

runloop跟runtime有没有关联

个人想到的是autoreleasepool、其他的不好找
runloop中事件源都是由运行时runtime触发

CPU和GPU怎么相互合作的

命令缓冲区包含了一个命令队列,由CPU向其中添加命令,而由GPU从中读取命令
,添加和读取的过程是互相独立的。命令缓冲区使得CPU和GPU可以互相独立工作
。当CPU需要渲染一些对象时,它可以向命令缓冲区中添加命令,而当GPU完成了上
一次的渲染任务后,它就可以从命令队列中再取出一个命令并执行它。

网络

HTTPS TLS/SSL加密过程

1、客户端向服务器端索要并验证公钥。
2、双方协商生成”对话密钥”。
3、双方采用”对话密钥”进行加密通信。
其中,前两个阶段,被称为“握手阶段”。
TLS握手过程有单向验证和双向验证之分,简单解释一下,单向验证就是
server端将证书发送给客户端,客户端验证server端证书的合法性等,
例如百度、新浪、google等普通的https网站,双向验证则是不仅客户端会验
证server端的合法性,同时server端也会验证客户端的合法性,例如银行网银登陆
,支付宝登陆交易等。
1、确认使用的加密通信协议版本,比如TLS 1.0版本。如果浏览器与服务器支持的版本不一致,服务器关闭加密通信。
2、一个服务器生成的随机数(Sever Random),稍后用于生成”对话密钥”。
3、确认使用的加密方法,比如RSA公钥加密。
4、服务器证书(Certificate)。
5、支持的一些SSL/TLS扩展。

HTTPS过程

①客户端发送报文进行SSL通信。报文中包含客户端支持的SSL的指定版本、
加密组件列表(加密算法及密钥长度等)。
②服务器应答,并在应答报文中包含SSL版本以及加密组件。
服务器的加密组件内容是从接受到的客户端加密组件内筛选出来的。
③服务器发送报文,报文中包含公开密钥证书。
④服务器发送报文通知客户端,最初阶段SSL握手协商部分结束。
⑤SSL第一次握手结束之后,客户端发送一个报文作为回应。
报文中包含通信加密中使用的一种被称Pre-master
secret的随机密码串。该密码串已经使用服务器的公钥加密。
⑥客户端发送报文,并提示服务器,此后的报文通信会采用
Pre-master secret密钥加密。
⑦客户端发送Finished报文。该报文包含连接至今全部报文的
整体校验值。这次握手协商是否能够完成成功,要以服务器是否能够正确解密该报文作为判定标准。
⑧服务器同样发送Change Cipher Spec报文。
⑨服务器同样发送Finished报文。
⑩服务器和客户端的Finished报文交换完毕之后,SSL连接就算建立完成。
⑪应用层协议通信,即发送HTTP响应。
⑫最后由客户端断开链接。断开链接时,发送close_nofify报文

为什么一定要用三个随机数,来生成”会话密钥

不管是客户端还是服务器,都需要随机数,这样生成的密钥才不会每次都一样。
由于SSL协议中证书是静态的,因此十分有必要引入一种随机因素来保证协商出来的密钥的随机性。
对于RSA密钥交换算法来说,pre-master-key本身就是一个随机数,
再加上hello消息中的随机,三个随机数通过一个密钥导出器最终导出一个对称密钥。
pre master的存在在于SSL协议不信任每个主机都能产生完全随机的随机数,
如果随机数不随机,那么pre master secret就有可能被猜出来,那么仅适用
pre master secret作为密钥就不合适了,因此必须引入新的随机因素,那么客户端和
服务器加上pre master secret三个随机数一同生成的密钥就不容易被猜出了,一个伪随机
可能完全不随机,可是是三个伪随机就十分接近随机了,每增加一个自由度,
随机性增加的可不是一。

TCP特点及与UDP区别

基于连接(点对点)
传输数据前需要建立好连接,然后在传输
双工通信
TCP连接一旦建立,就可以在连接上进行双向的通信
基于字节流而非报文
将数据按字节大小进行编号,接收端通过ACK来确认收到的数据编号,通过这种机制能够保证TCP协议的有序性和完整性,因此TCP能够提供可靠性传输

可靠传输
拥塞控制
慢启动,拥塞避免,拥塞发生,快速恢复四个算法
流量控制能力

DNS解析流程

DNS服务器一般分三种,根DNS服务器,顶级DNS服务器,权威DNS服务器。
1)浏览器缓存  
2)系统缓存  
3)路由器缓存    
4) ISP(互联网服务提供商)DNS缓存
5)根域名服务器   
6)顶级域名服务器  
8)保存结果至缓存

HTTP请求头都有哪些内容

Accept: /(客户端能接收的资源类型)
Accept-Language: en-us(客户端接收的语言类型)
Connection: Keep-Alive(维护客户端和服务端的连接关系)
Host: localhost:8080(连接的目标主机和端口号)
Referer: http://localhost/links.asp(告诉服务器我来自于哪里)
User-Agent: Mozilla/4.0(客户端版本号的名字)
Accept-Encoding: gzip, deflate(客户端能接收的压缩数据的类型)
If-Modified-Since: Tue, 11 Jul 2000 18:23:51 GMT(缓存时间)
Cookie(客户端暂存服务端的信息)
Date: Tue, 11 Jul 2000 18:23:51 GMT(客户端请求服务端的时间

哪些加密算法

MD5加密算法
RSA加密算法
AES加密算法
Base64加密算法

断点续传怎么实现;

续传的文件就好说了,只要给一个续传的标识位置,和对应的字节流就可以了,代码如下:
filePath:生成的文件,用来续传用
content:将要写入的字节
position:续传的字节位置

设计模式

设计原则

单一职责原则
CALayer:动画和视图的显示。
UIView:只负责事件传递、事件响应。
生成的数据模型
开闭原则
对修改关闭,对扩展开放。 要考虑到后续的扩展性,而不是在原有的基础上来回修改
接口隔离原则
使用多个专门的协议、而不是一个庞大臃肿的协议,如
UITableviewDelegate + UITableViewDataSource
依赖倒置原则
抽象不应该依赖于具体实现、具体实现可以依赖于抽象。
调用接口感觉不到内部是如何操作的
里氏替换原则
父类可以被子类无缝替换,且原有的功能不受任何影响 如:KVO
迪米特法则
一个对象应当对其他对象尽可能少的了解,实现高聚合、低耦合

iOS有哪些常见的设计模式?

01代理委托Delegate是协议的一种
,通过@protocol方式实现,常见的有tableView,textField等。
02观察者 通知机制(notification)和KVO机制(Key-value Observing)
03MVC
04单例(Singleton),UIApplication, NSBundle, NSNotificationCenter,
NSFileManager, NSUserDefault, NSURLCache等都是单例.
05策略
06工厂

内存设计、磁盘设计、网络设计原则

内存设计:存储的Size,淘汰策略 LRU算法
磁盘设计:存储方式\大小限制\淘汰策略
网络设计:图片请求最大并发\请求超时策略\请求优先级

MVVM模式思想

MVVM 即模型-视图-视图模型
在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,
ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel
能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,
ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的
双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。
优点 VIew可以独立于Model的变化和修改,一个ViewModel可以绑定到不同的View上,
降低耦合,增加重用
缺点 过于简单的项目不适用、大型的项目视图状态较多时构建和维护成本太大
合理的运用架构模式有利于项目、团队开发工作,但是到底选择哪个设计模式,

ReactNative的数据流思想

Flux是Facebook用来构建用户端的web应用的应用程序体系架构。
它通过利用数据的单向流动为React的可复用的视图组件提供了补充。
相比于形式化的框架它更像是一个架构思想,不需要太多新的代码你就可以马上
使用Flux构建你的应用。
一个 Flux 应用主要包含四个部分:
dispatcher
处理动作分发,维护 Store 之间的依赖关系
stores
数据和逻辑部分
views
React 组件,这一层可以看作 controller-views,作为视图同时响应用户交互
actions
提供给 dispatcher 传递数据给 store
视图上添加的所有的视图组成一个视图多叉树;
比如某个UI发生变化后,需要反向到根节点,然后由根节点想下遍历查找需
要更新的结点;
任何一个子节点是没有权利自我更新的,需要把自我变化更
新的消息传递给根节点,由根节点进行更新,相当于由主动行为变成被动行为

AsyncDisplayKit

UI 线程中一旦出现繁重的任务就会导致界面卡顿,这类任务通常分为3类:
排版,绘制,UI对象操作。
排版通常包括计算视图大小、计算文本高度、重新计算子式图的排版等操作。
绘制一般有文本绘制 (例如 CoreText)、图片绘制 (例如预先解压)、元素绘制 (Quartz)等操作。
UI对象操作通常包括 UIView/CALayer 等 UI 对象的创建、设置属性和销毁。
其中前两类操作可以通过各种方法扔到后台线程执行,而最后一类操作只能在主
线程完成,并且有时后面的操作需要依赖前面操作的结果
(例如TextView创建时可能需要提前计算出文本的大小)。ASDK
所做的,就是尽量将能放入后台的任务放入后台,不能的则尽量推迟
(例如视图的创建、属性的调整)。
为此,ASDK 创建了一个名为 ASDisplayNode 的对象,并在内部封装了
UIView/CALayer,它具有和 UIView/CALayer 相似的属性,例如
frame、backgroundColor等。所有这些属性都可以在后台线程更改,开发者可以只
通过 Node 来操作其内部的 UIView/CALayer,这样就可以将排版和绘制
放入了后台线程。但是无论怎么操作,
这些属性总需要在某个时刻同步到主线程的 UIView/CALayer 去。

ASDK 仿照 QuartzCore/UIKit 框架的模式,实现了一套类似的界面
更新的机制:即在主线程的 RunLoop 中添加一个 Observer,监听了
kCFRunLoopBeforeWaiting 和 kCFRunLoopExit
事件,在收到回调时,遍历所有之前放入队列的待处理的任务,然后一一执行。

AFNetworking 底层原理分析

AFNetworking是封装的NSURLSession的网络请求,由五个模块组成:
分别由NSURLSession,Security,Reachability,Serialization,UIKit五部分组成
NSURLSession:网络通信模块(核心模块) 对应 AFNetworking中的
AFURLSessionManager和对HTTP协议进行特化处理的AFHTTPSessionManager
,AFHTTPSessionManager是继承于AFURLSessionmanager的
Security:网络通讯安全策略模块 对应 AFSecurityPolicy
Reachability:网络状态监听模块 对应AFNetworkReachabilityManager
Seriaalization:网络通信信息序列化、反序列化模块 对应AFURLResponseSerialization
UIKit:对于iOS UIKit的扩展库

SDWebImage加载图片过程,图片缓存设计

0、首先显示占位图
1、在webimagecache中寻找图片对应的缓存,它是以url为数据索引先在内存中
查找是否有缓存;
2、如果没有缓存,就通过md5处理过的key来在磁盘中查找
对应的数据,如果找到就会把磁盘中的数据加到内存中,并显示出来;
3、如果内存和磁盘中都没有找到,就会向远程服务器发送请求,开始下载图片;
4、下载完的图片加入缓存中,并写入到磁盘中;
5、整个获取图片的过程是在子线程中进行,在主线程中显示。

组建化优缺点

业务分层、解耦,使代码变得可维护;
有效的拆分、组织日益庞大的工程代码,使工程目录变得可维护;
便于各业务功能拆分、抽离,实现真正的功能复用;
分工更加明确,提高开发效率
复用性更好,能迅速的组成更多的App

复杂页面架构

视图层(View&ViewController)
业务逻辑处理(ViewModel)
数据层(Model&Engine)
数据流
数据与数据关系
MVVM框架思想
ReactiveNative的数据流思想
系统UIView更新机制的思想
FaceBook的开源框架AsyncDisplayKit关于预排版的设计思想

解耦的方式

1、组件化
2、结合MVVM架构和数据驱动UI模式对原有MVC架构进行了兼容性优化
3、通过AOP技术对部分业务进行拆分解耦
4、优化事件传递方式

项目中用的技术以及实现;

1.复杂cell提前缓存行高和UI的frame
2.网络请求库的封装
3.组建化简单实现
4.tableView嵌套滑动
5.地图对象的单例封装
6.用View代替ViewController的实现
7.定时器使用

缓存机制是怎么清除数据的?

沙盒:iOS系统为每一个应用程序创建一个文件目录,是一个的独立,封闭,安全的空间, 一个沙盒就是一个文件目录。沙盒规定了一个程序只能在自身的沙盒中进行操作,不能去访问其他应用程序的沙盒(iOS8已经部分开放访问)
沙盒的作用: 用来存放非代码文件(图片, 音频, 视频, 属性列表(plist), sqlite数据库, 文本文件, 其他等等)

如何进行安全测试;

ipa包加壳(苹果)
敏感信息存储位置
通讯网络安全
代码混淆

说下生产者-消费者模型,其中的同步机制是怎么样的

产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。
在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产
者负责往仓库了进商品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模式。
dispatch_semaphore_wait
dispatch_semaphore_signal

开发日常

APP启动时间应从哪些方面优化?

App启动时间可以通过xcode提供的工具来度量,在Xcode的Product->Scheme–>Edit
Scheme->Run->Auguments中,将环境变量DYLD_PRINT_STATISTICS设为YES,
优化需以下方面入手
dylib loading time
核心思想是减少dylibs的引用
合并现有的dylibs(最好是6个以内)
使用静态库
rebase/binding time
核心思想是减少DATA块内的指针
减少Object C元数据量,减少Objc类数量,减少实例变量和函数(与面向对象设计思想冲突)
减少c++虚函数
多使用Swift结构体(推荐使用swift)
ObjC setup time
核心思想同上,这部分内容基本上在上一阶段优化过后就不会太过耗时
initializer time
使用initialize替代load方法
减少使用c/c++的attribute((constructor));推荐使用
dispatch_once() pthread_once() std:once()等方法
推荐使用swift
不要在初始化中调用dlopen()方法,因为加载过程是单线程,无锁
,如果调用dlopen则会变成多线程,会开启锁的消耗,同时有可能死锁
不要在初始化中创建线程

如何降低APP包的大小

可执行文件
编译器优化:Strip Linked Product、Make Strings Read-Only、Symbols Hidden
by Default 设置为 YES,去掉异常支持,Enable C++ Exceptions、Enable
Objective-C Exceptions 设置为 NO, Other C Flags 添加 -fno-exceptions
利用 AppCode 检测未使用的代码:菜单栏 -> Code -> Inspect Code
编写LLVM插件检测出重复代码、未被调用的代码
资源(图片、音频、视频 等)
优化的方式可以对资源进行无损的压缩
去除没有用到的资源:

UILabel图层混合

UILabel图层混合解决方法: iOS8以后设置背景色为非透明色并且设置label.layer
.masksToBounds=YES让label只会渲染她的实际size区域,
就能解决UILabel的图层混合问题
iOS8 之前只要设置背景色为非透明的就行
为什么设置了背景色但是在iOS8上仍然出现了图层混合呢?
UILabel在iOS8前后的变化,在iOS8以前,UILabel使用的是CALayer作为底图层,
而在iOS8开始,UILabel的底图层变成了_UILabelLayer,绘制文本也有所改变。在
背景色的四周多了一圈透明的边,而这一圈透明的边明显超出了图层的矩形区域,设
置图层的masksToBounds为YES时,图层将会沿着Bounds进行裁剪 图层混合问题解决了

日常如何检查内存泄露?

目前我知道的方式有以下几种
Memory Leaks
Alloctions
Analyse
Debug Memory Graph
MLeaksFinder
泄露的内存主要有以下两种:
Laek Memory 这种是忘记 Release 操作所泄露的内存。
Abandon Memory 这种是循环引用,无法释放掉的内存。

LLDB常用的调试命令?

po:print object的缩写,表示显示对象的文本描述,如果对象不存在则打印nil。
p:可以用来打印基本数据类型。
call:执行一段代码 如:call NSLog(@”%@”, @“yang”)
expr:动态执行指定表达式
bt:打印当前线程堆栈信息 (bt all 打印所有线程堆栈信息)
image:常用来寻找栈地址对应代码位置 如:image lookup –address 0xxxx

iOS 常见的崩溃类型有哪些?

unrecognized selector crash
KVO crash
NSNotification crash
NSTimer crash
Container crash
NSString crash
Bad Access crash (野指针)
UI not on Main Thread Crash

iOS App 稳定性指标及监测

开发过程中,主要是通过监控内存使用及泄露,CPU使用率,FPS,启动时间等指标,
以及常见的UI的主线程监测,NSAssert断言等,最好能在Debug模式下,实时显
示在界面上,针对出现的问题及早解决。

iOS的签名机制是怎么样的

签名机制:
先将应用内容通过摘要算法,得到摘要
再用私钥对摘要进行加密得到密文
将源文本、密文、和私钥对应的公钥一并发布
验证流程:
查看公钥是否是私钥方的
然后用公钥对密文进行解密得到摘要
将APP用同样的摘要算法得到摘要,两个摘要进行比对,如果相等那么一切正常

instruments它为什么能检测内存泄漏

推送的原理

1.由App向iOS设备发送一个注册通知,用户需要同意系统发送推送。
2.iOS向APNs远程推送服务器发送App的Bundle Id和设备的UDID。
3.APNs根据设备的UDID和App的Bundle Id生成deviceToken再发回给App。
4.App再将deviceToken发送给远程推送服务器(自己的服务器), 由服务器保存在数据库中。
5.当自己的服务器想发送推送时, 在远程推送服务器中输入要发送的消息并选择发给哪些用户的deviceToken,由远程推送服务器发送给APNs。
6.APNs根据deviceToken发送给对应的用户。

项目上线被拒原因

设计类型的问题,图标、UI等
app类型设置不准确
第三方资源用到广告等资源

有了解过代码如何编译的嘛

LLVM编译一个源文件的过程:预处理 -> 词法分析 -> Token -> 语法分析 ->
AST -> 代码生成 -> LLVM IR -> 优化 -> 生成汇编代码 -> Link -> 目标文件

针对线上版本的崩溃处理;

UIKit不是线程安全的,执行UIKit操作如果不在主线程很可能造成程序Crash
KVO
避免 Foundation 类Carsh
容器越界(NSArray, NSDictionary,…)
unrecognized selector crash (这个很多时候是由于class使用错误导致)
第三方工具:友盟
dSYMTools分析

Xcode构建过程;

解析项目文件,获取你项目中的所有文件、target 及其依赖关系、build settings,最后把它变成一个树形结构(有向图)。
增量构建。