iOS程序猿iOS开发iOS开发那点儿事

iOS初级到中级的进阶之路

2018-11-27  本文已影响650人  SunshineBrother

前言:这篇文章是我看李明杰老师的iOS底层原理班(下)/OC对象/关联对象/多线程/内存管理/性能优化总结所得,断断续续历时3个月左右,把课堂听的东西给做了一下笔记。

总结不易,耗时耗力,您的一颗小星星✨是我无限的动力。原文地址

iOS底层原理.png

我们经常会看一些面试题,但是好多面试题我们都是知其然不知其所以然,你如果认真的看了我上面总结的几十篇文章,那么你也会知其所以然。

OC对象本质

1、一个NSObject对象占用多少内存?

系统分配了16个字节给NSObject对象(通过malloc_size函数获得),但NSObject对象内部只使用了8个字节的空间(64bit环境下,可以通过class_getInstanceSize函数获得)

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

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

具体实现请参考:
1、一个NSObject对象占用多少内存
2、OC对象的分类

KVO

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

2、如何手动触发KVO?

手动调用willChangeValueForKey:和didChangeValueForKey:

3、直接修改成员变量会触发KVO么?

不会触发KVO

具体实现请参考:3、KVO实现原理

KVC

1、通过KVC修改属性会触发KVO么?

会触发KVO,因为KVC是调用set方法,KVO就是监听set方法

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

KVO的setValue:forKey原理

KVC2.png

KVO的ValueforKey原理

KVC3.png

具体实现请参考:4、KVC实现原理

Category

1、Category的实现原理

2、Category和Class Extension的区别是什么?

3、load、initialize方法的区别什么?

4、load、initialize的调用顺序

1.load

2.initialize

5、如何实现给分类“添加成员变量”?

默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过关联对象来间接实现

关联对象提供了以下API
添加关联对象
void objc_setAssociatedObject(id object, const void * key,
                                id value, objc_AssociationPolicy policy)

获得关联对象
id objc_getAssociatedObject(id object, const void * key)

移除所有的关联对象
void objc_removeAssociatedObjects(id object)

具体实现请参考:
5.1、分类的实现原理
5.2、Load和Initialize实现原理

Block

1、block的原理是怎样的?本质是什么?

block的底层.png

2、block的(capture)

变量捕获.png

为了保证block内部能够正常访问外部的变量,block有个变量捕获机制

3、Block类型有哪几种
block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型

Block类型.png

4、block的copy

在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况

MRC下block属性的建议写法
@property (copy, nonatomic) void (^block)(void);

ARC下block属性的建议写法
@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);

5、__block修饰符

6、循环引用

__unsafe_unretained typeof(self) weakSelf = self;
self.block = ^{
 print(@"%p", weakSelf);
}
__weak typeof(self) weakSelf = self;
self.block = ^{
 print(@"%p", weakSelf);
}
__block id weakSelf = self;
self.block = ^{
weakSelf = nil;
}
self.block();

具体实现请参考:6、Block底层解密

RunTime

1、讲一下 OC 的消息机制

2、消息转发机制流程

消息发送阶段

消息发送流程是我们平时最经常使用的流程,其他的像动态方法解析和消息转发其实是补救措施。具体流程如下

消息发送1.png

动态方法解析

消息发送2.png

开发者可以实现以下方法,来动态添加方法实现

消息转发

如果方法一个方法在消息发送阶段没有找到相关方法,也没有进行动态方法解析,这个时候就会走到消息转发阶段了。

消息发送6.png

3、什么是Runtime?平时项目中有用过么?

具体应用

4、super的本质

具体实现请参考:

RunLoop

1、讲讲 RunLoop,项目中有用到吗?
1、定时器切换的时候,为了保证定时器的准确性,需要添加runLoop
2、在聊天界面,我们需要持续的把聊天信息存到数据库中,这个时候需要开启一个保活线程,在这个线程中处理

2、runloop内部实现逻辑

每次运行RunLoop,线程的RunLoop会自动处理之前未处理的消息,并通知相关的观察者。具体顺序

RunLoop7.png

3、RunLoop与线程

4、timer 与 runloop 的关系?

解决定时器在滚动视图上面失效问题NSTimer添加到两种RunLoop中

[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

5、RunLoop有几种状态

kCFRunLoopEntry = (1UL << 0), // 即将进入RunLoop 
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer 
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source 
kCFRunLoopBeforeWaiting = (1UL << 5), //即将进入休眠 
kCFRunLoopAfterWaiting = (1UL << 6),// 刚从休眠中唤醒
 kCFRunLoopExit = (1UL << 7),// 即将退出RunLoop

**6、RunLoop的mode的作用 **

RunLoop的mode的作用 系统注册了5中mode

kCFRunLoopDefaultMode //App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode //界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响
UIInitializationRunLoopMode // 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用
GSEventReceiveRunLoopMode // 接受系统事件的内部 Mode,通常用不到
kCFRunLoopCommonModes //这是一个占位用的Mode,不是一种真正的Mode

但是我们只能使用两种mode

kCFRunLoopDefaultMode //App的默认Mode,通常主线程是在这个Mode下运行
UITrackingRunLoopMode //界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

具体实现请参考:7、RunLoop实现原理

多线程

1、你理解的多线程?
2、iOS的多线程方案有哪几种?你更倾向于哪一种?
3、你在项目中用过 GCD 吗?
4、GCD 的队列类型
5、说一下 OperationQueue 和 GCD 的区别,以及各自的优势
6、线程安全的处理手段有哪些?
使用线程锁

7、线程通讯
线程间通信的体现

1、NSThread
可以先将自己的当前线程对象注册到某个全局的对象中去,这样相互之间就可以获取对方的线程对象,然后就可以使用下面的方法进行线程间的通信了,由于主线程比较特殊,所以框架直接提供了在主线程执行的方法

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
 

2、GCD

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      
 });

内存管理

1、使用CADisplayLink、NSTimer有什么注意点?
CADisplayLink、NSTimer会对target产生强引用,如果target又对它们产生强引用,那么就会引发循环引用

2、介绍下内存的几大区域

3、讲一下你对 iOS 内存管理的理解
在iOS中,使用引用计数来管理OC对象的内存

内存管理的经验总结

可以通过以下私有函数来查看自动释放池的情况
extern void _objc_autoreleasePoolPrint(void);

4、ARC 都帮我们做了什么
LLVM + Runtime

5、weak指针的实现原理
runtime维护了一个weak表,用于存储指向某个对象的所有weak指针。weak表其实是一个hash(哈希)表,key是所指对象的地址,Value是weak指针的地址(这个地址的值是所指对象指针的地址)数组

6、autorelease对象在什么时机会被调用release

7、方法里有局部对象, 出了方法后会立即释放吗
在ARC情况下会立即释放
在MRC情况下,对象是在 runloop 的即将进入休眠时进行释放的

文章中可以提炼出来的题目太多了,我这里也就简单的总结几道题,想要了解具体实现请到我的github中找到相关文章进行阅读。欢迎点赞哦,如果里面有什么我理解的不太正确,欢迎提出,我们相互印证

上一篇下一篇

猜你喜欢

热点阅读