P4
QA1、队列和栈有什么区别?
队列和栈是两种不同的数据容器。
队列是一种先进先出的数据结构;
它在两端进行操作,一端进行入队列操作,一端进行出列队操作;
队列是基于地址指针进行遍历,而且可以从头部或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影响数据结构,速度要快的多。
栈是一种先进后出的数据结构;
它只能在栈顶进行操作,入栈和出栈都在栈顶操作;
栈只能从头部取数据也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性,速度较慢。
QA2、常见的object-c的数据类型有那些,和C的基本数据类型有什么区别?
object-c的数据类型有NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;而object-c的NSNumber包含有父类NSObject的方法和NSNumber自己的方法,可以完成复杂的操作。
QA3、请简述UITableView的复用机制。
每次创建cell的时候通过dequeueReusableCellWithIdentifier:方法创建cell,它先到缓存池中找指定标识的cell,如果没有就直接返回nil。
如果没有找到指定标识的cell,那么会通过initWithStyle:reuseIdentifier:创建一个cell。
当cell离开界面就会被放到缓存池中,以供下次复用。
QA4、@class和import以及include的区别?
import会引入整个.h头文件。
@class只是告诉编译器该类中可以使用这个class类名。
QA5、属性关键字assign、retain、weak、copy的类型区别?
assign:用于基本数据类型和结构体。如果修饰对象的话,当销毁时,属性值不会自动置nil,可能造成野指针。
weak:对象引用计数为0时,属性值也会自动置nil
retain:强引用类型,ARC下相当于strong,但block不能用retain修饰,因为等同于assign不安全。
strong:强引用类型,修饰block时相当于copy。
QA6、单例实例是什么?
Foundation 和Application Kit 框架中的一些类只允许创建单例对象,即这些类在当前进程中的唯一实例。
QA7、简述iOS中的ARC内存管理方式。
iOS的ARC内存管理用的是自动引用计数的方法。
ARC:开发者通过声明对象的属性为strong,weak,retain,assign来管理对象的引用计数,被strong和retain修饰的属性变量系统会自动对所修饰变量的引用计数进行自增自减操作,同样地,retainCount为0时,系统会释放对象内存。
QA8、什么是深拷贝与浅拷贝?
深拷贝就是开辟一块新的内存空间来存储原来内存空间的内容,对象指针指向新的内存空间。
浅拷贝只是重新生成一个指针,指向的还是原来的内存空间。
QA9、浅拷贝和深拷贝的区别?
深拷贝开辟了新的内存空间,浅拷贝内存空间不变。
深拷贝不改变当前对象的引用计数,而浅拷贝是会改变。
QA10、NSArray与NSSet的区别?
NSArray内存中存储地址连续,而NSSet不连续;
NSSet效率高,内部使用hash查找;
NSArray查找需要遍历;
NSSet通过anyObject访问元素,NSArray通过下标访问;
P5
QA11、@protocol 和category 中如何使用@property?
在protocol 中使用property 只会生成setter 和getter 方法声明,我们使用属性的目的,是希望遵守协议的对象能实现该属性。
category 使用@property 也是只会生成setter 和getter 方法的声明,如果我们真的需要给category 增加属性的实现,需要借助于运行时的两个函数:objc_setAssociatedObject 与objc_getAssociatedObject
QA12、一个objc对象的isa的指针指向什么?有什么作用?
isa 指向他的类对象,从而可以找到对象上的方法。
同一个类的不同对象,他们的isa指针是一样的。
QA13、IBOutlet连出来的视图属性为什么可以被设置成weak?
因为父控件的subViews数组已经对它有一个强引用。
QA14、简述iOS内存分区情况。
代码区:存放函数二进制代码。
数据区:系统运行时申请内存并初始化,系统退出时由系统释放。用来存放全局变量、静态变量、常量。
堆区:通过malloc等函数或new等操作符动态申请得到,需程序员手动申请和释放。
栈区:函数模块内申请,函数结束时由系统自动释放。存放局部变量、函数参数。
QA15、沙盒目录结构是怎样的?各自用于那些场景?
一级目录:Application、Documents、tmp、Library
Application:存放程序源文件,上架前经过数字签名,上架后不可修改。
Documents:常用目录,iCloud备份目录,存放数据。
tmp:存放临时文件,不会被备份,而且这个文件下的数据有可能随时被清除的可能。
Library:包含二级目录Caches和Preference。
Caches:存放体积大又不需要备份的数据。
Preference:设置目录,iCloud会备份设置信息。
QA16、通知,代理,block,KVO的使用场景分别是什么,有什么区别?
通知:适用于毫无关联的页面之间或者系统消息的传递,属于一对多的信息传递关系。
代理:一对一的信息传递方式,适用于相互关联的页面之间的信息传递。
block:一对一的信息传递方式,效率会比代理要高。
KVO:属性监听,监听对象的某一属性值的变化状况,当需要监听对象属性改变的时候使用。
QA17、NSTimer计时器是准确的吗,为什么?
NSTimer计时器不是准确的。
原因:定时器被添加在主线程中,由于定时器在一个RunLoop中被检测一次,所以如果在这一次的RunLoop中做了耗时的操作,当前RunLoop持续的时间超过了定时器的间隔时间,那么下一次定时就被延后了。
QA18、类的分类和类的扩展的区别?
类的分类可以动态添加方法(运行时),类的扩展可以添加更多的属性变量(编译期)。
QA19、http和https的区别?
http:// https在http的基础上增加了SSL数据传输安全性认证层。
http:// https协议需要到ca申请证书。
http是超文本传输协议,信息是明文传输,https 则是具有安全性的ssl加密传输协议。
http和https使用的是完全不同的连接方式用的端口也不一样,前者是80,后者是443。
http的连接很简单,是无状态的。
HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议。
QA20、iOS的retain和release的操作是在编译期还是运行时进行的?
retain和release是在编译期由编译器自动生成的代码。
QA21、UIViewController的生命周期方法调用顺序
alloc 创建对象,分配空间。
init 初始化对象,初始化数据。
loadView 从nib载入视图。
viewDidLoad 载入完成,可以进行自定义数据以及动态的创建其他控件。
viewWillAppear 视图将出现在屏幕之前。
viewDidAppear 视图在屏幕上渲染完成。
当一个视图被移除屏幕并且销毁的时候执行顺序:
viewWillDisappear 视图被移除之前。
viewDidDisappear 视图被移除之后。
dealloc 销毁视图。
QA22、如何化解ViewController和NSTimer的循环引用关系?
NSTimer和使用Timer的ViewController相互持有会引起循环引用。
方法1:在ViewContoller的viewWillDisappear生命周期中注销Timer。
方法2:引入第三方NSObject管理和持有Timer,让Timer持有第三方的成员变量。这样就打破了互相引用的循环关系。
QA23、描述数据持久化的几种方式和对应的应用场景?
plist文件(属性列表):即直接拖拽plist文件到程序目录当中。由NSBundle获取本地plist资源。存储一些本地的,且不会改变的数据到程序当中。
preference(偏好设置):即NSUserDefaults,存储一些小型数据,设置参数,开关属性等等。
NSKeyedArchiver(归档):存储一些不涉及增删改查的字典数组或者NSObject等,存储的对象一定要遵循NSCoder和NSDecoder协议。
SQLite:存储一些涉及增删改查的字段数据。
CoreData:效率比较高,存储一些涉及增删改查的且体积非常大的数据。
QA24、如何进行网络消息推送?
一种是Apple自己提供的通知服务(APNS服务器)、一种是用第三方推送机制。
首先应用发送通知,系统弹出提示框询问用户是否允许,当用户允许后向苹果服务器(APNS)请求deviceToken,并由苹果服务器发送给自己的应用,自己的应用将DeviceToken发送自己的服务器,自己服务器想要发送网络推送时将deviceToken以及想要推送的信息发送给苹果服务器,苹果服务器将信息发送给应用。
第三方推送机制,普遍使用Socket机制来实现,几乎可以达到即时的发送到目标用户手机端,适用于即时通讯类应用。
QA25、TCP和UDP的区别与联系?
TCP为传输控制层协议,为面向连接、可靠的、点到点的通信;
UDP为用户数据报协议,非连接的不可靠的点到多点的通信;
TCP侧重可靠传输,UDP侧重快速传输。
QA26、HTTPS的加密原理?
服务器端用非对称加密(RSA)生成公钥和私钥,
然后把公钥发给客户端, 服务器则保存私钥;
客户端拿到公钥后, 会生成一个密钥, 这个密钥就是将来客户端和服务器用来通信的钥匙;
然后客户端用公钥对密钥进行加密, 再发给服务器;
服务器拿到客户端发来的加密后的密钥后, 再使用私钥解密密钥, 到此双方都获得通信的钥匙。
QA27、如何高性能的给 UIImageView 加个圆角?
解决方案:
1、设置Calayer的cornerRadius和masksToBounds(会导致离屏渲染)
2、使用绘图技术绘制圆角。
3、使用贝塞尔曲线"切割"个这个图片, 给UIImageView 添加圆角。
QA28、UIView 和CAlayer 是什么关系?
UIView可以响应事件,CALayer不可以。
UIView是CALayer的delegate。UIView主要处理事件,CALayer负责绘制。
每个 UIView 内部都有一个 CALayer 在背后提供内容的绘制和显示,并且 UIView 的尺寸样式都由内部的CALayer 所提供。
QA29、用@property声明的 NSString / NSArray / NSDictionary 经常使用 copy 关键字,为什么?
使用copy的目的是,防止把可变类型的对象赋值给不可变类型的对象时,可变类型对象的值发生变化会无意间篡改不可变类型对象原来的值。
QA30、如果用strong关键字@property声明的 NSString / NSArray / NSDictionary,有什么问题?
用 @property 声明 NSString、NSArray、NSDictionary有对应的可变类型:NSMutableString、NSMutableArray、 NSMutableDictionary。如果我们使用是 strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性。
QA31、单例使用的优缺点?
主要优点:
1、提供了对唯一实例的受控访问。
2、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
3、允许可变数目的实例。
主要缺点:
1、由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
2、单例类的职责过重,在一定程度上违背了“单一职责原则”。
3、滥用单例将带来一些负面问题,如系统回收后对象状态的丢失。
QA32、原子(atomic)跟非原子(non-atomic)属性有什么区别
atomic提供多线程安全。是防止在写未完成的时候被另外一个线程读取,造成数据错误。
non-atomic:在自己管理内存的环境中,解析的访问器保留并自动释放返回的值,如果指定了 nonatomic ,那么访问器只是简单地返回这个值。
QA33、谈谈id和instancetype的异同?
相同点: 两者都是可以作为方法的返回值类型。
不同点:
instancetype可以返回和方法所在类相同类型的对象,id只能返回的是未知类型的对象。
instancetype不能作为函数的参数,只能作为返回值。
QA34、如何选择delegate、notification、KVO?
三种模式都是一个对象传递事件给另外一个对象。
delegate:一对一。
notification:一对多或者多对多。
KVO:一对一。三者各有自己的特点:
delegate:语法简洁,方便阅读,易于调试。
notification:灵活多变,可以跨越多个类之间进行使用。
KVO:实现属性监听,实现model和view同步。
QA35、Runloop的作用是什么?
作用:保持程序的持续运行、随时处理各种事件、节省cpu资源(没事件休息释放资源)、渲染屏幕UI。
QA36、iOS的签名机制大概是怎么样的?
先将应用内容通过摘要算法,得到摘要再用私钥对摘要进行加密得到密文,将源文本、密文、和私钥对应的公钥一并发布。查看公钥是否是私钥方的,然后用公钥对密文进行解密得到摘要,将APP用同样的摘要算法得到摘要,两个摘要进行比对,如果相等那么则校验正常。
QA37、weak属性如何自动置nil的?
Runtime会对weak属性进行内存布局,构建hash表:以weak属性对象内存地址为key,weak属性值(weak自身地址)为value。当对象引用计数为0 dealloc时,会将weak属性值自动置nil。
QA38、iOS中使用的锁有哪几种?
@synchronized、信号量、NSLock等。
QA39、iOS中如何导致死锁的产生?
多个线程同时访问同一资源,造成循环等待。
QA40、访问控制关键字(public、open、private、filePrivate、internal)的区别?
public与open:public在module内部中,class和func都可以被访问/重载/继承,外部只能访问;而open都可以。
private与filePrivate:private修饰class/func,表示只能在当前class源文件/func内部使用,外部不可以被继承和访问;而filePrivate表示只能在当前swift源文件内访问。
internal:在整个模块或者app内都可以访问,默认访问级别,可写可不写。
QA41、Autorelease对象什么时候释放?
在没有手加Autorelease Pool的情况下,Autorelease对象是在当前的runloop迭代结束时释放的,而它能够释放的原因是系统在每个runloop迭代中都加入了自动释放池Push和Pop。
QA42、runtime 中,SEL和IMP的区别?
每个类对象都有一个方法列表,方法列表存储方法名、方法实现、参数类型,SEL是方法名(编号),IMP指向方法实现的首地址
QA43、load方法和initialize方法的异同?——主要说一下执行时间,各自用途,没实现子类的方法会不会调用父类的?
load和initialize的调用时机:load是在app启动后,initialize是在runtime初始化的时候,第一个方法调用前调用。
调用顺序:load是父类->本类->分类的调用顺序,initialize是父类->本类的调用顺序(如果有分类直接调用分类,本类不会调用)
没实现子类的方法会不会调用父类的? 不会
是否沿用父类实现? 否
QA44、KVO底层实现原理?
当观察一个对象时,runtime会动态创建继承自该对象的类,并重写被观察对象的setter方法,重写的setter方法会负责在调用原setter方法前后通知所有观察对象值得更改,最后会把该对象的isa指针指向这个创建的子类,对象就变成子类的实例。
QA45、@property (nonatomic, copy) NSMutableArray *array; 这种写法会出什么问题?
当对数组array进行添加, 删除等操作时, 程序会因为找不到对应的实例方法而崩溃。
原因: 当对array进行copy操作后, 就是复制了一个不可变的NSArray对象,不能对NSArray对象进行添加,删除等操作。
QA46、如何实现OC与JS交互?
1、通过对象方法拦截url
2、使用JavaScriptCore(只适用于UIWebView)
3、使用WKScriptMessageHandler(只适用于WKWebView)
4、使用像WebViewJavaScriptBridge的第三方框架
QA47、-(BOOL)isKindOfClass和-(BOOL)isMemberOfClass的区别?
-(BOOL) isKindOfClass: classObj 判断是否是这个类或者这个类的子类的实例
-(BOOL) isMemberOfClass: classObj 判断是否是这个类的实例
P6
QA48、nil, Nil, NSNULL, NULL的区别?
nil是指向obj-c中对象的空指针,是一个对象,在o-c中nil对象调用方法不会引起crash。
Nil是指向obj-c中的类的空指针,表示的是一个空类。
NULL是指向任何类型的空指针(如c/c++中的空指针),在objective -c中是一个数值。
NSNULL用于集合操作,在集合对象中,表示一个空值的集合对象。
QA49、如何监听View的触摸事件?
复写View类的touchBegin、touchMove、touchEnd系列方法监听视图的触摸。
QA50、事件是如何传递的?
事件传递:当触摸一个视图时,首先系统会捕捉此事件,并为此事件创建一个UIEvent对象,将此对象加入当前应用程序的事件队列中,然后由UIApplication对象从队列中,一个一个取出来进行分发,首先分发给UIWindow对象,然后由UIWindow对象分发给触摸的视图对象,也就是第一响应者对象。
QA51、视图的响应链是什么?
响应者链:事件被交由第一响应者对象处理,如果第一响应者不处理,事件被沿着响应者链向上传递,交给下一个响应者(next responder)。
QA52、描述下SDWebImage里面给UIImageView加载图片的逻辑。
第一步:首先会在SDWebImageCache 中寻找图片是否有对应的缓存, 它会以url 作为数据的索引先在内存中寻找是否有对应的缓存。
第二步:如果缓存未找到就会利用通过MD5处理过的key来继续在磁盘中查询对应的数据, 如果找到了, 就会把磁盘中的数据加载到内存中,并将图片显示出来。
第三步:如果在内存和磁盘缓存中都没有找到,就会向远程服务器发送请求,开始下载图片。
下载后的图片会加入缓存中,并写入磁盘中。
整个获取图片的过程都是在子线程中执行,获取到图片后回到主线程将图片显示出来。
QA53、Cookie和Session的区别?
存储位置:Cookie存放在客户端上,Session数据存放在服务器上。
Session 的运行依赖session id,而session id 是存在Cookie 中的,也就是说,如果浏览器禁用了Cookie ,同时Session 也会失效。
安全性:Cookie存在浏览器中,可能会被一些程序复制,篡改;而Session存在服务器相对安全很多。
性能:Session会在一定时间内保存在服务器上,当访问增多,会对服务器造成一定的压力。考虑到减轻服务器压力,应当使用Cookie。
QA54、GCD与NSOperation两种管理多线程方式的异同点?
GCD是用C语言实现的,而NSOperation是用OC实现的。
NSOperation可以设置最大线程并发数,可以设置线程依赖关系,可以设置线程的优先级。
GCD方式管理多线程是一种对开发者非常友好的开发方式,开发者只需要关注同步异步,串行并发这些线程关系就可以轻松地进行线程管理了。
QA55、MJExtension的原理?
通过运行时,拿到Model对应的PropertyName,然后通过KVC,将字典中的值传入Model。
QA56、iOS 以scheduledTimerWithTimeInterval的方式触发的timer,在滑动页面上的列表时,timer会暂停,为什么?该如何解决?
方法一:是将timer加入到NSRunloopCommonModes中。
方法二:是将timer放到另一个线程中,然后开启另一个线程的runloop,这样可以保证与主线程互不干扰,而现在主线程正在处理页面滑动。
QA57、怎么防止反编译?
本地数据加密:对NSUserDefaults,sqlite存储文件数据加密,保护帐号和关键信息。
URL编码加密:对程序中出现的URL进行编码加密,防止URL被静态分析。
网络传输数据加密:对客户端传输数据提供加密方案,有效防止通过网络接口的拦截获取数据。
方法体,方法名高级混淆:对应用程序的方法名和方法体进行混淆,保证源码被逆向后无法解析代码。
程序结构混排加密:对应用程序逻辑结构进行打乱混排,保证源码可读性降到最低。
QA58、Scoket连接和HTTP连接的区别?
HTTP协议是基于TCP连接的,是应用层协议,主要解决如何包装数据。
Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
HTTP连接:短连接,客户端向服务器发送一次请求,服务器响应后连接断开,节省资源。服务器不能主动给客户端响应(除非采用HTTP长连接技术)。
Socket连接:长连接,客户端跟服务器端直接使用Socket进行连接,没有规定连接后断开,因此客户端和服务器段保持连接通道,双方可以主动发送数据。
QA59、Controller如何优化?
(答案很多,只要相关都算对)
将网络请求抽象到单独的类中。
方便在基类中处理公共逻辑。
方便在基类中处理缓存逻辑,以及其它一些公共逻辑。
方便做对象的持久化。
将界面的封装抽象到专门的类中。
构造专门的 UIView 的子类,来负责这些控件的拼装。这是最彻底和优雅的方 式,不过稍微麻烦一些的是,你需要把这些控件的事件回调先接管,再都一一暴露回 Controller。
构造ViewModel。
借鉴MVVM。具体做法就是将 ViewController 给 View 传递数据这个过程,抽象成构造 ViewModel 的过程。
专门构造存储类。
专门来处理本地数据的存取。
整合常量。
QA60、__weak,__block的作用?
__weak与weak基本相同。前者用于修饰变量(variable),后者用于修饰属性(property)。__weak 主要用于防止block中的循环引用。
__block也用于修饰变量。它是引用修饰,所以其修饰的值是动态变化的,即可以被重新赋值的。__block用于修饰某些block内部将要修改的外部变量。
QA61、runloop和线程有什么关系?
runloop与线程是一一对应的,一个runloop对应一个核心的线程,为什么说是核心的,是因为runloop是可以嵌套的,但是核心的只能有一个,他们的关系保存在一个全局的字典里。
runloop是用来管理线程的,当线程的runloop被开启后,线程会在执行完任务后进入休眠状态,有了任务就会被唤醒去执行任务。
runloop在第一次获取时被创建,在线程结束时被销毁。
对于主线程来说,runloop在程序一启动就默认创建好了。
对于子线程来说,runloop是懒加载的,只有当我们使用的时候才会创建,所以在子线程用定时器要注意:确保子线程的runloop被创建,不然定时器不会回调。
QA62、id和NSObject*的区别?
id是一个 objc_object 结构体指针,定义是 typedef struct objc_object *id
id可以理解为指向对象的指针。所有oc的对象id都可以指向,编译器不会做类型检查,id调用任何存在的方法都不会在编译阶段报错,当然如果这个id指向的对象没有这个方法,该崩溃还是会崩溃的。
NSObject *指向的必须是NSObject的子类,调用的也只能是NSObjec里面的方法否则就要做强制类型转换。
不是所有的OC对象都是NSObject的子类,还有一些继承自 NSProxy。NSObject *可指向的类型是id的子集。
QA63、setNeedsDisplay 和 layoutIfNeeded 两者是什么关系?
UIView的setNeedsDisplay和setNeedsLayout两个方法都是异步执行的。
而setNeedsDisplay会自动调用drawRect方法,这样可以拿到UIGraphicsGetCurrentContext进行绘制;
而setNeedsLayout会默认调用layoutSubViews,给当前的视图做了标记;layoutIfNeeded 查找是否有标记,如果有标记即立刻刷新。
只有setNeedsLayout和layoutIfNeeded这二者合起来使用,才会起到立刻刷新的效果。
QA64、iOSApp如何做性能优化?
(答案很多,只要相关都算对)
一般都是说关于tableView的优化处理,造成tableView卡顿的原因:
没有使用cell的重用标识符,导致一直创建新的cell。
cell的重新布局。
没有提前计算并缓存cell的属性及内容。
cell中控件的数量过多。
使用了ClearColor,无背景色,透明度为0。
更新只使用tableView.reloadData()(如果只是更新某组的话,使用reloadSection进行局部更新)。
加载网络数据,下载图片,没有使用异步加载,并缓存。
使用addView 给cell动态添加view。
没有按需加载cell(cell滚动很快时,只加载范围内的cell)。
实现无用的代理方法(tableView只遵守两个协议)。
没有做缓存行高(estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同时存在,这两者同时存在才会出现“窜动”的bug。建议是:只要是固定行高就写预估行高来减少行高调用次数提升性能。如果是动态行高就不要写预估方法了,用一个行高的缓存字典来减少代码的调用次数即可)。
做了多余的绘制工作(在实现drawRect:的时候,它的rect参数就是需要绘制的区域,这个区域之外的不需要进行绘制)。
没有预渲染图像。(当新的图像出现时,仍然会有短暂的停顿现象。解决的办法就是在bitmap context里先将其画一遍,导出成UIImage对象,然后再绘制到屏幕)。
提升tableView的流畅度:本质上是降低 CPU、GPU 的工作,从这两个大的方面去提升性能。
CPU:对象的创建和销毁、对象属性的调整、布局计算、文本的计算和排版、图片的格式转换和解码、图像的绘制
GPU:纹理的渲染
卡顿优化在 CPU 层面
尽量用轻量级的对象,比如用不到事件处理的地方,可以考虑使用 CALayer 取代 UIView。
不要频繁地调用 UIView 的相关属性,比如 frame、bounds、transform 等属性,尽量减少不必要的修改。
尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性。
Autolayout 会比直接设置 frame 消耗更多的 CPU 资源。
图片的 size 最好刚好跟 UIImageView 的 size 保持一致。
控制一下线程的最大并发数量。
尽量把耗时的操作放到子线程。
文本处理(尺寸计算、绘制)。
图片处理(解码、绘制)。
卡顿优化在 GPU层面
尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示。
GPU能处理的最大纹理尺寸是 4096x4096,一旦超过这个尺寸,就会占用 CPU 资源进行处理,所以纹理尽量不要超过这个尺寸。
尽量减少视图数量和层次。
减少透明的视图(alpha<1),不透明的就设置 opaque 为 YES。
尽量避免出现离屏渲染。
QA65、如何设计一种检测UIViewController的内存泄漏的机制?
前提:如果UIViewController被释放,但是持有的子对象还存在,说明这些子对象造成了内存泄露。
设计:子对象subView建立一个对controller的weak引用,如果Controller被释放,这个weak引用也随之置为nil。那怎么知道子对象没有被释放呢?可以用一个单例对象每隔一小段时间发出一个通知给这个子对象,如果子对象还活着就会响应通知。所以如果子对象subView的controller已不存在,但还能响应到这个通知,那么这个对象就是可疑的泄漏对象。
QA66、类的分类的实现原理?
在运行时过程中,本类的方法加载完毕之后,会查询是否有类的分类,如果有类的分类,就会再去加载类的分类的方法,把这些方法全部存储到objc_class结构体的methodLists数组中。注意,这里的类的分类的方法是插入到数组的第一个元素位置的,也就是说类的分类的方法会覆盖本类的同名方法。如果有多个类的分类都包含同名函数,那么最后一个被加载进compile sources的类的分类文件中的方法将会覆盖其他的同名方法。