这篇文章用来尝试回答落影大佬的面试题,原文:iOS面试小结
一、基础知识
1、Objective-C基础
为了切合iOS面试的主题,面试官通常都会从这一块知识开始入手。OC的知识非常庞杂,有时候遇到熟悉的内容就很了解,如果没有接触过可能就没有印象。比如说:viewDidLoad 的触发时机是发生在什么时候?以及延伸的问题,viewDidLoad 与loadView的关系以及先后顺序。
所以这部分知识,更合适问一些基础、共性的问题。比如说:
常见的property有哪些属性?各自的属性应用场景有哪些?
介绍KVO和KVC的区别?KVO是否会引起循环引用?如果观察对象已经释放,会导致什么现象?用NSNotification 替代KVO,观察对象已释放会如何?如何手动实现KVO?
如何创建一个字符串常量?在.h声明并且实现会有什么问题?
category和extension的区别?category的实现原理?extension是否可以和category写在同一个文件?
答:
- 控制器的生命周期:
- loadView
- viewDidLoad
- viewWillappear
- viewWillLayoutsubViews
- viewDidLayoutsubViews
- viewDidappear
- viewWillDisAppear
- viewDidDisAppear
- dealloc
- KVO和KVC:
- KVO是键值观察,是对属性添加观察,当属性值发生变化时会通知订阅者。属于观察者模式在iOS中的实现。
- 注意,KVO的触发条件是调用set方法,如果通过_成员变量则不触发。
- KVC是键值对编码,说人话就是通过属性字符串名称改变和获取属性
- KVO不会引起循环引用,oberver没有对self强引用
- 观察对象已释放,会产生崩溃,NSNotification则不会
- 手动调用KVO的方法是在set方法前后分别执行
willChangeValueForKey
和didChangeValueForKey
- 变量、常量、宏
//宏
#define HSCoder @"汉斯哈哈哈"
//变量
NSString *HSCoder = @"汉斯哈哈哈";
//常量,四种写法
static const NSString *HSCoder = @"汉斯哈哈哈";
const NSString *HSCoder = @"汉斯哈哈哈";
NSString const *HSCoder = @"汉斯哈哈哈";
NSString * const HSCoder = @"汉斯哈哈哈";
- 宏:只是在预处理器里进行文本替换,没有类型,不做任何类型检查,编译器可以对相同的字符串进行优化。只保存一份到 .rodata 段。甚至有相同后缀的字符串也可以优化,你可以用GCC 编译测试,"Hello world" 与 "world" 两个字符串,只存储前面一个。取的时候只需要给前面和中间的地址,如果是整形、浮点型会有多份拷贝,但这些数写在指令中。占的只是代码段而已,大量用宏会导致二进制文件变大
- 变量:共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以被修改,在编译阶段会执行类型检查
- 常量:共享一块内存空间,就算项目中N处用到,也不会分配N块内存空间,可以根据const修饰的位置设定能否修改,在编译阶段会执行类型检查
2、内存管理
ARC和MRC,iOS开发者需要对两种内存管理方式都熟悉。一个了解MRC的开发者,遇到CF开头的函数怎么办?
很常见的面试切入点是从ARC的实现原理开始,引入__strong/__weak/__unsafe_unretained/__autoreleasing多个关键词的区别,再联想到循环引用,block实现原理,block持有外部的局部变量,autoReleasePool的使用,autoReleasePool与MRC的autorelease区别。
3、Runtime
Runtime机制介绍;
介绍isa、属性列表、方法列表、协议列表;
消息传递机制如何查找方法;
Category实现原理;
method swizzling原理;
imp和selector;
答:
- Runtime是OC语言在C语言基础上实现面向对象和动态性具体实现的一套C语言API。
- isa,对象指针地址,在arm64之后经过优化变成一个共用体(union),还使用位域存储更多信息:
- 是否关联过对象、是否有C++析构函数、是否完成初始化、是否被弱引用指向过、对象是否正在释放、引用计数是否过大无法储存,若无法储存则存在sideTable类的属性中。
- 属性列表、方法列表、协议列表,都存在类对象中,实例对象通过isa指向类对象。
- 编译期,属性列表、方法列表、协议列表存在class_ro_t中,通过runtime添加的话则存在class_rw_t中。
- 消息传递机制如何查找方法?三步走流程
-
消息发送:消息发送方receiver通过isa找到自己的class,从cache查找方法缓存,找不到则从class_rw_t查找,找不到继续通过isa查找superClass进行相同查找顺序,找到后将方法缓存到cache,找不到进入第二步
-
动态方法解析
-
消息转发
-
4.Category实现原理
- Category主要实现对已有类扩展方法,通过runtime甚至可以添加协议、属性,但是不可以添加成员变量
- Category主要是由runtime运行时动态把扩展方法添加到类的方法列表。
- 什么时候被添加?程序启动时,由dyld链接器初始化runtime环境,由runtime添加,由
read_images
方法插入到类方法列表前面
- method swizzling原理
- Method Swizzling 用于改变一个已经存在的 selector 实现。我们可以在程序运行时,通过改变 selector 所在 Class(类)的 method list(方法列表)的映射从而改变方法的调用。其实质就是交换两个方法的 IMP(方法实现)。
- imp和selector;
- IMP代表函数的具体实现
- SEL代表方法\函数名,一般叫做选择器,底层结构跟char *类似
- 可以通过@selector()和sel_registerName()获得
- 可以通过sel_getName()和NSStringFromSelector()转成字符串
- 不同类中相同名字的方法,所对应的方法选择器是相同的
4、RunLoop
runloop概述;
与线程的关系;
与FPS的关系;
RunLoop的实际应用;
答:
- runloop概述;
iOS程序运行过程中循环做的一些事情,包括定时器、事件、GCD、触摸事件,在空闲时休眠,在忙活时启动,达到节省资源目的。 - 与线程的关系;
-
每条线程都有唯一的一个与之对应的RunLoop对象
-
RunLoop保存在一个全局的Dictionary里,线程作为key,RunLoop作为value
-
线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建
-
RunLoop会在线程结束时销毁
-
主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop
- 与FPS的关系;
- RunLoop的实际应用;
-
控制线程生命周期(线程保活)
-
解决NSTimer在滑动时停止工作的问题
-
监控应用卡顿
-
性能优化
5、iOS系统
介绍scheme原理;
微信如何实现呼起第三方app?网页又如何呼起APP?
Push通知实现原理?客户端A直接向客户端B发Push是否可行?
代码签名;
沙盒机制;
地址空间随机化;
答
- 利用scheme:协议进行url跳转。
- .使用通用链接。通用链接就是HTTP协议的普通URL,通过在服务器上配置一些文件,配合应用.实现客户点击网页链接之后直接打开信E投等应用.客户在微信\QQ中点击链接时不再需要点击右上'在Safari浏览器打开'才能打开软件,实现客户操作的无缝跳转,让客户体验更加连贯,更顺畅.
- 通知原理就是服务器给苹果服务器发送推送通知请求,因为iOS应用和apple服务器时长连接,所以可以通过apple服务器给app直接推送消息。
- 代码签名:是对可执行文件或代码进行数字签名以确认软件作者及保证软件在签名后未被修改或损坏的措施。此措施使用加密散列来验证真实性和完整性。
- 沙盒机制:每个app都是单独存放在自己的沙盒中,不同应用不能返回其他应用,这样可以保证应用的安全性。
6、编译原理
介绍整个编译的流程;
静态库、动态库的区别;
静态连接、动态链接的过程和区别;
在VC.h文件引入VC+Test.h(Category)会如何;
答
- 编译过程
- 预处理:处理以#开头的命令,删除注释,解开宏定义等
- 编译:词法分析、语法分析、语义分析、中间代码生成与优化,最终生成汇编代码
- 汇编:将汇编代码翻译成机器码,生成.o目标文件
- 链接:将多个.o目标文件和其他函数库链接成可执行文件
- 动态库和静态库的区别?
- 区别:静态库在程序链接成可执行文件时就已经链接完成,动态库是在程序启动、运行时才进行链接
- 动态链接和静态链接的区别?
- 同上
6.在VC.h文件引入VC+Test.h(Category)会如何?会编译报错,因为互相包含。
7、多线程
7.1.多线程有哪些实现方式 ?
7.2.pthread、NSThread、GCD、NSOperationQueue有哪些应用场景?
image.png
7.3.>多线程如何进行线程同步?
7.4.信号量、锁、代码块、原子变量常见有哪些应用场景?
7.5.实现一个变量的读写锁:读共享,写互斥;
7.6.如何用GCD实现100个任务执行,但是最高并发为10个任务?
//建立任务组
dispatch_group_t group = dispatch_group_create();
//设置信号量大小
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
//创建全局队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//添加实现任务
for (int i = 0; i < 100; i++) {
//semphore值为0时会一直等待执行。当>=1时执行下面的代码。可通过一次,会将semphore的值减1.
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//监视queue队列
dispatch_group_async(group, queue, ^{
NSLog(@"这里在执行耗时操作----%i",i);
sleep(2);
//当前线程执行完成后,使semaphore的值加1,这样,如果semphore的值就加1,会触发dispatch_semaphore_wait执行一条代码
dispatch_semaphore_signal(semaphore);
});
}
//永远地监听Group中的任务是否执行完成。
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
7.7. GCD和线程的关系?GCD并发队列的线程爆炸?
8、网络原理
介绍TCP三次握手?
socket编程中,何时进行三次握手?如何用socket发送数据?
HTTP协议中request和response有哪些数据组成部分?
在浏览器输入URL到页面加载发生了什么?
HTTP断点续传;
HTTP中间人攻击;(重点)
HTTPS实现原理;(加密通信原理)
HTTPS中间人攻击;
DNS劫持;
9、Xcode
LLDB调试技巧:如何查看堆栈、修改内存、监控内存值变化、执行语句;
Xcode中的scheme配置是什么?
General中的Project和Target用处?
Certificate、Provisioning Profile、App ID的关系;
Image Assets Catalogs是什么?
网友评论