【iOS】架构师之路~底层原理五 : (面试题目整理)

1. 一个OC对象占用多少内存

系统分配了16个字节给NSObject对象(经过malloc_size函数得到)
但NSObject对象内部只使用了8个字节的空间(64bit环境下,能够经过class_getInstanceSize函数得到)
复制代码

2. 对象的isa指针指向哪里?

instance对象的isa指向class对象
class对象的isa指向meta-class对象
meta-class对象的isa指向基类的meta-class对象
复制代码

3.OC的类信息存放在哪里?

对象方法、属性、成员变量、协议信息,存放在class对象中
类方法,存放在meta-class对象中
成员变量的具体值,存放在instance对象
复制代码

4.iOS用什么方式实现对一个对象的KVO?(KVO的本质是什么?)

- 利用RuntimeAPI动态生成一个子类,而且让instance对象的isa指向这个全新的子类
- 当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数
    willChangeValueForKey:
    父类原来的setter
    didChangeValueForKey:
- 内部会触发监听器(Oberser)的监听方法(observeValueForKeyPath:ofObject:change:context:)
复制代码

5.如何手动触发KVO?

手动调用willChangeValueForKey:和didChangeValueForKey:
//
- (void)viewDidLoad {
[super viewDidLoad];

    Person *person = [[Person alloc]init];;
    [p addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
    [p willChangeValueForKey:@"name"];
    [p didChangeValueForKey:@"name"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"被观测对象:%@, 被观测的属性:%@, 值的改变: %@\n, 携带信息:%@", object, keyPath, change, context);
}
复制代码

6.直接修改为员变量会触发KVO么?

不会触发KVO
复制代码

7.经过KVC修改属性会触发KVO么?

会触发KVO
KVC在赋值时候,内部会触发监听器(Oberser)的监听方法(observeValueForKeyPath:ofObject:change:context:) 发送通知
复制代码

8.KVC的赋值和取值过程是怎样的?原理是什么?

KVC的全称是Key-Value Coding,俗称“键值编码”,能够经过一个key来访问某个属性
调用 setValue:forKey:
setKey,_setKey  ->找到了则进行赋值,未找到调用 accessInstanceVarlableDirctly 是否运行 修改值,返回YES
调用_key, _isKey, key, isKey 进行赋值
复制代码

9.Category的使用场合是什么?

- 在不修改原有类代码的状况下,为类添对象方法或者类方法
- 或者为类关联新的属性
- 分解庞大的类文件

使用场合:
- 添加实例方法
- 添加类方法
- 添加协议
- 添加属性
- 关联成员变量
复制代码

10.Category的实现原理

Category编译以后的底层结构是struct category_t,里面存储着分类的对象方法、类方法、属性、协议信息
在程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)
复制代码

11.Category和Class Extension的区别是什么?

Class Extension在编译的时候,它的数据就已经包含在类信息中
Category是在运行时,才会将数据合并到类信息中
复制代码

12.Category中有load方法吗?load方法是何时调用的?load 方法能继承吗?

- 有load方法
- load方法在runtime加载类、分类的时候调用
- load方法能够继承,可是通常状况下不会主动去调用load方法,都是让系统自动调用
复制代码

13. initialize方法如何调用,以及调用时机

- 当类第一次收到消息的时候会调用类的initialize方法
- 是经过 runtime 的消息机制 objc_msgSend(obj,@selector()) 进行调用的
- 优先调用分类的 initialize, 若是没有分类会调用 子类的,若是子类未实现则调用 父类的
复制代码

13. load、initialize方法的区别什么?它们在category中的调用的顺序?以及出现继承时他们之间的调用过程?

- load 是类加载到内存时候调用, 优先父类->子类->分类
- initialize 是类第一次收到消息时候调用,优先分类->子类->父类
- 同级别和编译顺序有关系
- load 方法是在 main 函数以前调用的
复制代码

14. Category可否添加成员变量?若是能够,如何给Category添加成员变量?

不能直接给Category添加成员变量,可是能够间接实现Category有成员变量的效果
Category是发生在运行时,编译完毕,类的内存布局已经肯定,没法添加成员变量(Category的底层数据结构也没有成员变量的结构)
能够经过 runtime 动态的关联属性
复制代码

15. block的原理是怎样的?本质是什么?

block 本质实际上是OC对象
block 内部封装了函数调用以及调用环境
复制代码

16. __block的做用是什么?有什么使用注意点?

若是须要在 block 内部修改外部的 局部变量的值,就须要使用__block 修饰(全局变量和静态变量不须要加__block 能够修改)

__block 修饰之后,局部变量的数据结构就会发生改变,底层会变成一个结构体的对象,结构内部会声明 一个 __block修饰变量的成员, 而且将 __block修饰变量的地址保存到堆内存中. 后面若是修改 这个变量的值,能够经过 isa 指针找到这个结构体,进来修改 这个变量的值;

能够在 block 内部修改 变量的值
复制代码

17. block的属性修饰词为何是copy?使用block有哪些使用注意?

block 一旦没有进行copy操做,就不会在堆上
使用注意:循环引用问题 (外部使用__weak 解决)
复制代码

17. block在修改NSMutableArray,需不须要添加__block?

若是是操做 NSMutableArray 对象不须要,由于 block 内部拷贝了 NSMutableArray对象的内存地址,实际是经过内存地址操做的
若是 NSMutableArray 对象要从新赋值,就须要加__block
复制代码

18. Block 内部为何不能修改局部变量,须要加__block

经过查看Block 源码,能够发现, block 内部若是单纯使用 外部变量, 会在 block 内部建立一样的一个变量,而且将 外部变量的值引用过来..(只是将外部变量值拷贝到 block 内部), 内部这个变量和外部 实际已经不要紧了

从另外一方面分析,block 本质也是一个 函数指针, 外部的变量也是一个局部变量,颇有可能 block 在使用这个变量时候,外部变量已经释放了,会形成错误

加了__block 之后, 会将外部变量的内存拷贝到堆中, 内存由 block 去管理.
复制代码

19.讲一下 OC 的消息机制

OC中的方法调用其实都是转成了objc_msgSend函数的调用,给receiver(方法调用者)发送了一条消息(selector方法名)
objc_msgSend底层有3大阶段
消息发送(当前类、父类中查找)、动态方法解析、消息转发
复制代码
19.1 消息发送流程
当咱们的一个 receiver(实例对象)收到消息的时候, 会经过 isa 指针找到 他的类对象, 而后在类对象方法列表中查找 对应的方法实现,若是 未找到,则会经过 superClass 指针找到其父类的类对象, 找到则返回,未找打则会一级一级往上查到,最终到NSObject 对象, 若是仍是未找到就会进行动态方法解析

类方法调用同上,只不过 isa 指针找到元类对象;
复制代码
19.1 动态方法解析机制
当咱们发送消息未找到方法实现,就会进入第二步,动态方法解析: 代码实现以下

//  动态方法绑定- 实例法法调用
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    if (sel == @selector(run)) {
        Method method = class_getInstanceMethod(self, @selector(test));
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

// 类方法调用
+(BOOL) resolveClassMethod:(SEL)sel....
复制代码

20.消息转发机制流程

未找到动态方法绑定,就会进行消息转发阶段

// 快速消息转发- 指定消息处理对象
- (id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(run)) {
        return [Student new];
    }
    return  [super forwardingTargetForSelector:aSelector];
} 

// 标准消息转发-消息签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    if(aSelector == @selector(run))
    {
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
   //内部逻辑本身处理 
}
复制代码

21.什么是Runtime?平时项目中有用过么?

Objective-C runtime是一个`运行时`库,它为Objective-C语言的动态特性提供支持,咱们所写的OC代码在运行时都转成了runtime相关的代码,类转换成C语言对应的结构体,方法转化为C语言对应的函数,发消息转成了C语言对应的函数调用。经过了解runtime以及源码,能够更加深刻的了解OC其特性和原理

OC是一门动态性比较强的编程语言,容许不少操做推迟到程序运行时再进行
OC的动态性就是由Runtime来支撑和实现的,Runtime是一套C语言的API,封装了不少动态性相关的函数
平时编写的OC代码,底层都是转换成了Runtime API进行调用
复制代码

22.runtime具体应用

利用关联对象(AssociatedObject)给分类添加属性
遍历类的全部成员变量(修改textfield的占位文字颜色、字典转模型、自动归档解档)
交换方法实现(交换系统的方法)
利用消息转发机制解决方法找不到的异常问题
复制代码

23.打印结果分别是什么?

1.png

[self class] 和 [super class] 都是给当前类返送消息,spuer 表示在父类中查找
[self superClass]  和 [super superclass] 也是也当前类发消息,返回父类
第一个打印:
MJStudent / MJStudent/ MJerson / MJPerson

isKindOfClass 表示对象是否为当前类或者子类的 类型
isMemberOfClass 表示是否为当前类的的类型
isMemberOfClass 分为- 对象方法 和+ 类方法2中
- (bool)isMemberOfClass; 比较的是类对象
+ (bool)isMemberOfClass; 比较的是元类
第二个打印:
1 ,0, 0, 0
复制代码

24.如下代码能不能执行成功?若是能够,打印结果是什么?

2.png

打印结果: <ViewController: 0x7f9396c16300>
复制代码

25.讲讲 RunLoop,项目中有用到吗?

runloop运行循环,保证程序一直运行,主线程默认开启
用于处理线程上的各类事件,定时器等
能够提升程序性能,节约CPU资源,有事情作就作,没事情作就让线程休眠

应用范畴:
定时器,事件响应,手势识别,界面刷新,以及autoreleasePool 等等
复制代码

26.runloop内部实现逻辑?

3.png

实际上 RunLoop 就是这样一个函数,其内部是一个 do-while 循环。当你调用 CFRunLoopRun() 时,线程就会一直停留在这个循环里;直到超时或被手动中止,该函数才会返回。
复制代码

27.runloop和线程的关系?

每条线程都有惟一的一个与之对应的RunLoop对象
RunLoop保存在一个全局的Dictionary里,线程做为key,RunLoop做为value
线程刚建立时并无RunLoop对象,RunLoop会在第一次获取它时建立
RunLoop会在线程结束时销毁
主线程的RunLoop已经自动获取(建立),子线程默认没有开启RunLoop
复制代码

28.timer 与 runloop 的关系?

timer 定时器,是基于 runloop 来实现的, runloop 在运行循环当中,监听到了定制器 就会执行;因此 timer 须要添加到 runloop 中去, 注意子线程的 runloop 默认是不开启的,若是在子线程执行 timer 须要手动开启 runloop
复制代码

29.程序中添加每3秒响应一次的NSTimer,当拖动tableview时timer可能没法响应要怎么解决?

将 timer 对象添加到 runloop 中,并修改 runloop 的运行 mode

 NSTimer *timer = [NSTimer timerWithTimeInterval:1 repeats:YES block:nil];
 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
复制代码

30.runloop 是怎么响应用户操做的, 具体流程是什么样的?

不明白问题想问什么?
复制代码

31.说说runLoop的几种状态

添加Observer监听RunLoop的全部状态html

4.png

32.runloop的mode做用是什么?

runloop 只能在一种 mode 下运行, 作不一样的事情,runloop 会切换到对应的 model 下来执行,默认是  kCFRunLoopDefaultMode 若是视图滑动再回切换到  UITrackingRunLoopMode,若是须要在多种 mode 下运行则须要手动设置 kCFRunLoopCommonModes;

1. kCFRunLoopDefaultMode:App的默认Mode,一般主线程是在这个Mode下运行
2. UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其余 Mode 影响
3. UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就再也不使用,会切换到kCFRunLoopDefaultMode
4. GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,一般用不到
5. kCFRunLoopCommonModes: 这是一个占位用的Mode,做为标记kCFRunLoopDefaultMode和UITrackingRunLoopMode用,并非一种真正的Mode 
复制代码

33.你理解的多线程?

同一时间,CPU 只能处理理一条线程, 只有一条线程在⼯工做 多线程并发执行,实际上是 CPU 快速的在多条线程之间调度(切换) 若是 CPU 调度线程的时间⾜足够快, 就形成了多线程并发执⾏的假象

优点
充分发挥多核处理器的优点,将不一样线程任务分配给不一样的处理器,真正进入“⾏行 计算”状态
弊端 
新线程会消耗内存控件和cpu时间,线程太多会下降系统行性能。
复制代码

34.iOS的多线程方案有哪几种?你更倾向于哪种?

5.png

倾向于GCD ,简单灵活,使用方便
复制代码

35.你在项目中用过 GCD 吗?

使用过

GCD中有2个用来执行任务的函数
用同步的方式执行任务
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue:队列
block:任务

用异步的方式执行任务
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
复制代码

36.GCD 的队列类型

GCD的队列能够分为2大类型
并发队列(Concurrent Dispatch Queue)
可让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
并发功能只有在异步(dispatch_async)函数下才有效

串行队列(Serial Dispatch Queue)
让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
复制代码

37.说一下 OperationQueue 和 GCD 的区别,以及各自的优点

1> GCD是纯C语⾔言的API,NSOperationQueue是基于GCD的OC版本封装
2> GCD只⽀支持FIFO的队列列,NSOperationQueue能够很⽅方便便地调整执⾏行行顺 序、设 置最⼤大并发数量量
3> NSOperationQueue能够在轻松在Operation间设置依赖关系,⽽而GCD 须要写很 多的代码才能实现
4> NSOperationQueue⽀支持KVO,能够监测operation是否正在执⾏行行 (isExecuted)、 是否结束(isFinished),是否取消(isCanceld)
5> GCD的执⾏行行速度⽐比NSOperationQueue快 任务之间不不太互相依赖:GCD 任务之间 有依赖\或者要监放任务的执⾏行行状况:NSOperationQueue
复制代码

38.线程安全的处理手段有哪些?

1.加锁
2.同步执行
复制代码

39.OC你了解的锁有哪些?在你回答基础上进行二次提问;

os_unfair_lock  ios10 开始
OSSpinLock      ios10 废弃
dispatch_semaphore   建议使用,性能也比较好
dispatch_mutex
dispatch_queue   串行
NSLock  对 mutex 封装
@synchronized 性能最差
复制代码

40.追问一:自旋和互斥对比?

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

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

41.追问二:使用以上锁须要注意哪些?

注意死锁
在串行队列使用同步,容易形成死锁
复制代码

42.追问三:用C/OC/C++,任选其一,实现自旋或互斥?口述便可!

两种锁的加锁原理:

互斥锁:线程会从sleep(加锁)——>running(解锁),过程当中有上下文的切换,cpu的抢占,信号的发送等开销。

自旋锁:线程一直是running(加锁——>解锁),死循环检测锁的标志位,
复制代码

43.请问下面代码的打印结果是什么?

6.png

打印 1,3
performSelector after 是基于 timer 定制器,定时器又是基于 runloop 实现的
任务2在子线程中,子线程默认 runloop 是不开启的,因此不执行2
复制代码

44.请问下面代码的打印结果是什么?

7.png

打印1
start 执行完,线程就销毁了.任务 test 无法执行了
复制代码

45.使用CADisplayLink、NSTimer有什么注意点?

CADisplayLink 保证调用频率和刷帧频率一直,60FPS, 不用设置时间间隔,每秒钟60次
    可使用 proxy 代理解决循环引用

    CADisplayLink、NSTimer会对target产生强引用,若是target又对它们产生强引用,那么就会引起循环引用
复制代码

46.介绍下内存的几大区域

低地址-> 高地址
保留->代码段->数据段(字符串常量,已初始化全局数据,未初始化数据)>堆->栈内存-> 内核区域
代码段: 编译以后的代码
数据段: 字符串常量,已经初始化的全局变量,或者静态变量,未初始化的全局变量,静态变量
堆 (低>高)  经过 alloc malloc calloc 动态分配的内存

栈 (高地址 从 低地址)  函数调用开销()
复制代码

47.讲一下你对 iOS 内存管理的理解

在iOS中,使用引用计数来管理OC对象的内存

一个新建立的OC对象引用计数默认是1,当引用计数减为0,OC对象就会销毁,释放其占用的内存空间

调用retain会让OC对象的引用计数+1,调用release会让OC对象的引用计数-1

内存管理的经验总结
当调用alloc、new、copy、mutableCopy方法返回了一个对象,在不须要这个对象时,要调用release或者autorelease来释放它
想拥有某个对象,就让它的引用计数+1;不想再拥有某个对象,就让它的引用计数-1

能够经过如下私有函数来查看自动释放池的状况
extern void _objc_autoreleasePoolPrint(void);
复制代码

48.ARC 都帮咱们作了什么?

LLVM + Runtime 会为咱们代码自动插入 retain 和 release 以及 autorelease等代码,不须要咱们手动管理
复制代码

49.weak指针的实现原理

Runtime维护了一个weak表,用于存储指向某个对象的全部weak指针。weak表实际上是一个hash(哈希)表,Key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象的地址)数组。

runtime对注册的类, 会进行布局,对于weak对象会放入一个hash表中。 用weak指向的对象内存地址做为key,当此对象的引用计数为0的时候会dealloc,假如weak指向的对象内存地址是a,那么就会以a为键, 在这个weak表中搜索,找到全部以a为键的weak对象,从而设置为nil。
复制代码

50.autorelease对象在什么时机会被调用release

iOS在主线程的Runloop中注册了2个Observer
-第1个Observer监听了kCFRunLoopEntry事件,会调用objc_autoreleasePoolPush()
-第2个Observer
    监听了kCFRunLoopBeforeWaiting事件,会调用objc_autoreleasePoolPop()、objc_autoreleasePoolPush()
    监听了kCFRunLoopBeforeExit事件,会调用objc_autoreleasePoolPop()

    objc_autoreleasePoolPop()调用时候回给 pool 中的对象发送一次 release 消息
复制代码

51.方法里有局部对象, 出了方法后会当即释放吗

若是是普通的 局部对象 会当即释放
若是是放在了 autoreleasePool 自动释放吃,则会等runloop 循环,进入休眠前释放
复制代码

52.思考如下2段代码能发生什么事?有什么区别?

8.png

第一个内存会暴涨,self.name 会不停的建立
第二个内存固定,会使用 Tagged Pointer 将值存在地址中
复制代码

53.你在项目中是怎么优化内存的?

内存优化能够从 内存泄漏 和 内存开销 2方面入口

- 减小内存泄露
  可使用静态分析以及instruments的leaks 分析
  注意 NStimer 以及 block ,delegate 等的使用,避免循环引用

- 下降内存使用峰值
  1. 关于图片加载占用内存问题:imageNamed: 方法会在内存中缓存图片,用于经常使用的图片。
   imageWithContentsOfFile: 方法在视图销毁的时候会释放图片占用的内存,适合不经常使用的大图等。

  2.tableView cell 尽可能使用重用机制,减小额外的开销
  3.tableView 列表图片展现尽可能使用缩略图
  4.延迟加载 对象,节约内存开销
  5.避免短期大量建立对象,配合 autoreleasePool 减小内存峰值
  6.重用大开销对象,好比: NSDateFormatter和NSCalendar
  7.加载 html 尽可能使用 wkwebView
  8.单例使用不易过多
  9.线程最大并发数
复制代码

54.优化你是从哪几方面着手?

卡顿优化
启动优化
耗电量优化
app 瘦身

CPU 占用率、 内存使用状况、网络情况监控、启动时闪退、卡顿、FPS、使用时崩溃、耗电量监控、流量监控....
复制代码

55.列表卡顿的缘由可能有哪些?你平时是怎么优化的?

1.最经常使用的就是cell的重用, 注册重用标识符
   若是不重用cell时,每当一个cell显示到屏幕上时,就会从新建立一个新的cell;
   若是有不少数据的时候,就会堆积不少cell。
   若是重用cell,为cell建立一个ID,每当须要显示cell 的时候,都会先去缓冲池中寻找可循环利用的cell,若是没有再从新建立cell

2.避免cell的从新布局
   cell的布局填充等操做 比较耗时,通常建立时就布局好
   如能够将cell单独放到一个自定义类,初始化时就布局好

3.提早计算并缓存cell的属性及内容
    当咱们建立cell的数据源方法时,编译器并非先建立cell 再定cell的高度
    而是先根据内容一次肯定每个cell的高度,高度肯定后,再建立要显示的cell,滚动时,每当cell进入凭虚都会计算高度,提早估算高度告诉编译器,编译器知道高度后,紧接着就会建立cell,这时再调用高度的具体计算方法,这样能够方式浪费时间去计算显示之外的cell

4.减小cell中控件的数量
   尽可能使cell得布局大体相同,不一样风格的cell可使用不用的重用标识符,初始化时添加控件,
   不适用的能够先隐藏

5.不要使用ClearColor,无背景色,透明度也不要设置为0
   渲染耗时比较长

6.使用局部更新
   若是只是更新某组的话,使用reloadSection进行局部更新

7.加载网络数据,下载图片,使用异步加载,并缓存

8.少使用addView 给cell动态添加view

9.按需加载cell,cell滚动很快时,只加载范围内的cell

10.不要实现无用的代理方法,tableView只遵照两个协议

11.缓存行高:estimatedHeightForRow不能和HeightForRow里面的layoutIfNeed同时存在,这二者同时存在才会出现“窜动”的bug。因此个人建议是:只要是固定行高就写预估行高来减小行高调用次数提高性能。若是是动态行高就不要写预估方法了,用一个行高的缓存字典来减小代码的调用次数便可

12.不要作多余的绘制工做。在实现drawRect:的时候,它的rect参数就是须要绘制的区域,这个区域以外的不须要进行绘制。例如上例中,就能够用CGRectIntersectsRect、CGRectIntersection或CGRectContainsRect判断是否须要绘制image和text,而后再调用绘制方法。

13.预渲染图像。当新的图像出现时,仍然会有短暂的停顿现象。解决的办法就是在bitmap context里先将其画一遍,导出成UIImage对象,而后再绘制到屏幕;

14.使用正确的数据结构来存储数据。
复制代码

56.app 启动优化

1\. pre-main 以前

    * 排查无用的动态库(按期清理)
    * 减小ObjC类(项目中不适用的的库,废弃的代码等)、方法(selector)、分类(category)的数量、无用的库
    * 少在类的+load方法里作事情,尽可能把这些事情推迟到+initiailize1.

2\. main 函数以后的 didFinishLaunchingWithOptions 加载完以前

    * 不影响用户体验的操做,作延迟加载,不要所有放在  didFinishLaunchingWithOptions中去作
    * 版本更新,一些三方初始化,不须要在 didFinishLaunchingWithOptions 初始化的放到,界面展现完之后再初始化
    * 一些网络请求延迟 请求..
    * 一些业务逻辑延迟 加载
    * 初始化第三方 SDK
    * 配置 APP 运行须要的环境
    * 本身的一些工具类的初始化
复制代码

57.app 耗电量优化

1.不要频繁的刷新页面,能刷新1行cell最好只刷新一行,尽可能不要使用reloadData.
2.选择正确的集合
    NSArray,使用index来查找很快(插入和删除很慢)
    字典,使用键来查找很快
    NSSets,是无序的,用键查找很快,插入/删除很快
3.少用运算得到圆角,必需要用圆角的话,不如把图片自己就作成圆角
4.懒加载,不要一次性建立全部的subview,而是须要时才建立.
5.重用机制
6.图片处理
    图片与imageView相同大小,避免多余运算
    可使用整副的图片,增长应用体积,可是节省CPU
    可调大小的图片,能够省去一些没必要要的空间
    CALayer,CoreGraphics,甚至OpenGL来绘制,消耗CPU
7.cache,cache,cache(缓存全部须要的)
    服务器相应结果的缓存(图片)
    复杂计算结果的缓存(UITableView的行高)
8.尽可能少用透明或半透明,会产生额外的运算.

9.使用ARC减小内存失误,dealloc须要重写并对属性置为nil

10.避免庞大的xib,storyBoard,尽可能使用纯代码开发

CPU层面

1.Timer的时间间隔不宜过短,知足需求便可
2.线程适量,不宜过多,不要阻塞主线程
3.优化算法,减小循环次数
4.定位和蓝牙按需取用,定位以后要关闭或下降定位频率
5.一些硬件的使用,不使用就关掉
复制代码

58.app 的包瘦身

9.png

59.讲讲 MVC、MVVM、MVP,以及你在项目里具体是怎么写的?

MVC  Model-view-controller 数据-视图-控制器     
通常控制器用于管理数据和视图, 数据和视图交互都是经过控制器来进行的.视图和数据进行了解耦, 可是咱们平常使用常常会将模型绑定给视图.模型封装在视图内部,外部不用管理视图内部业务逻辑,这数据 mvc 的变种, 控制器只给视图模型数据就行了. 缺点是视图和 模型有耦合;

MVVM Model-view-viewModel  模型-视图-视图模型
view 和 model 的交互经过viewmodel 来进行交互,实现数据的双向绑定

MVP  Model-view - Presenter  模型-视图-主持人

view 和 model 的交互经过Presenter,controller经过Presenter来管理 model 和 View
复制代码

60.你本身用过哪些设计模式?

结合本身项目来说吧
复制代码

61.通常开始作一个项目,你的架构是如何思考的?

根据模块,使用 mvc 功能划分..结合本身项目讲比较容易
涉及到东西也比较多,比较杂,大到整个项目架构,小到一个 view 的架构;没具体的答案
复制代码

参考:iOS底层原理班(下)/OC对象/关联对象/多线程/内存管理/性能优化ios

相关文章
相关标签/搜索