今年由于个人原因,有了换工作的想法,所以把我整理的一些面试到的问题还有面试之前整理的问题都写下来,就当做一个备份。部分题目有自己整理的一个简单的答题思路和步骤,有不完整或错误的地方望指出,话不多说,上题:
(1)https的原理
1 https是使用了 TSL(安全传输层)/SSL(安全套接字层)加密的HTTP协议
2 http在传输的过程中是采用明文传输,很容易被窃取或者被篡改数据,而HTTPS的话是加入了身份认证,信息加密,完整性验证 HTTPS = HTTP + TSL/SSL
3 https总共涉及两种加密方式和一种算法:非对称加密(RSA)和对称加密(AES),散列算法(MD5, 哈希)
4 https为了防止中间人的攻击和消息抵赖的情况,采用了第三方机构认证的方式(即CA认证的方式)来保证信息来源的正确性
(2)KVC和KVO的实现原理
KVC : key-value coding(键值编码) 通过key值来获取/设置对象的属性通过字符串来获取/设置对象的属性,在查找的过程中,比如:name,查找会查找 name, _name,getName,setName,isName等的属性和方法, 如果找不到的话,最终会调用valueForUndefinedKey 或者 setValue:forUndefinedKey来进行最后的处理,如果没有这两个方法的实现的话,程序就会崩溃
accessInstanceVariablesDirectly -> 直接访问实例变量
KVO: key-value observer (键值监听 isa-swizzing)
添加观察的方法后,系统会给对应的类添加一个子类,并将该类的isa指针指向对应的子类,子类重写了对应的需要观察的属性的set方法,并且添加了willChangeValueForKey和didChangeValueForKey:的方法,从而达到监听的目的,KVO的基础是KVC,仅针对通过调用set方法赋值的情况下才能监听到,如果直接给属性赋值,不走set方法的话是监听不到属性的变化的
(3)isa指针的指向
isa 是一个指向对象所属真实类的指针,对象的isa指针指向类,类的isa指针指向元类,元类的isa指针指向根元类,根元类的isa指针指向自己,从而形成一个闭环
(4)属性的实质是什么? 包括哪几个部分?属性默认的关键字都有哪些? @dynamic关键字和@synthesize关键字是用来做什么的?
@property = ivar + getter + setter; 属性 = 实例变量+getter+setter
属性默认的关键字:atomic和 readwrite, assign
属性可以拥有的特质分为4类:
1 原子性 - atomic 和 nonatomic
2 读/写属性 -- readwrite 和 readonly
3 内存管理 -- strong weak assign copy retain unsafe_unretain
4 方法名 -- getter setter
@dynamic:不自动生成setter和getter方法,避免编译期间的警告,自己实现对应的存取方法,或者在运行时动态绑定
@synthesize:自动合成getter和setter方法
(5)可变集合类和不可变集合类的copy和mutableCopy有什么区别?如果集合是内容复制的话,集合里面的元素也是内容复制吗?
copy复制的是一份不可变的对象,mutableCopy复制的是可变的对象
浅拷贝:仅拷贝对象的指针,就是多了一个指针指向该内存区域
深拷贝:将该内存区域里面所有的内容都拷贝至新的内存区域,并且有一个指针指向它
浅拷贝就是指针的拷贝,深拷贝就是内容的拷贝
非集合类
对不可变对象进行copy操作属于指针拷贝,mutableCopy操作属于内容拷贝
对 可变对象 进行 copy 和 mutableCopy 操作均属于内容拷贝
集合类
对不可变对象进行的copy操作是指针拷贝,mutableCopy操作属于内容拷贝
对 可变对象 copy和mutableCopy都是 内容拷贝
集合类的内容拷贝是拷贝集合类对象本身,里面的对象元素仍然属于指针拷贝
(6)nonatomic和atomic的区别?atomic是绝对的线程安全吗?为什么?如果不是,那应该如何实现?
用来决定编译器生成的getter和setter是否是原子操作的。
atomic会自动为getter个setter添加锁,保证变量在多线程中的使用的时候是安全的
nonatomic禁止多线程,变量保护,提高性能。使用atomic是不一定线程安全的,atomic所说的线程安全只是保证了getter和setter存取方法的线程安全,并不能保证整个对象是线程安全的,atomic使用的是同步锁
解决方案是给当前的对象互斥锁
(7)UICollectionView开发界面有什么弊端?如何避免?
这个我也不太清楚,求大神解答
(8)进程和线程的区别?同步和异步的区别?并行和并发的区别?
一个APP至少包含一个进程,进程中可以存在多个线程,一个进程一定有一个线程,多个线程共享进程的所有资源。进程有单独的地址空间,线程是进程中操作的不同执行路径,不存在单独的地址空间,线程是CPU独立运行和调度的基本单位,进程是资源分配的基本单位
同步:相当于后一个的执行依赖于前一个的执行完成即为同步
异步:在执行程序的过程中,可以去执行别的任务称为异步,任务互不等待
并发:多个任务同时执行成为并发,是物理意义上的并发
并行:也是多个任务一起执行,但是是时间片上的轮转,看起来像是一起执行
多线程是实现异步的一种手段,开启多个线程执行异步任务
(9)线程间的通信?
GCD(异步进入全局线程和异步回到主线程,在主线程中不要使用同步,会造成线程锁),NSThread(perform方法),NSOperation,最好再了解他们各自的优缺点和差异性
(10)Designated Initializer(指定初始化函数)?
提供“全能初始化方法”
具体细节可以通过搜索关键字了解
(11)block的实质是什么? 一共有几种block?都是在什么情况下生成的?
block本质是使用了结构体的C语言代码,实质上也是一个OC的对象
block一共存在三种形式:
栈上的block(出了函数的作用域之后就会销毁),没有强指针引用的block都是栈区的block,作为函数的传参的block在栈上
堆上的block(因为栈区的block会跟随函数的作用域销毁,但是有可能该block还是有用的,所以要在堆上拷贝一份),有强指针引用或Copy修饰的成员变量会将栈区的block复制到堆区,没有强指针引用之后即可销毁,生命周期由程序员控制
全局静态的block --- 生命周期从创建到应用程序结束
(12)为什么在默认情况下无法修改被block捕获的变量? __block都做了什么?
block只会捕获block中会用到的变量。 由于只捕获了自动变量(自动变量是以值传递方式传递到Block的构造函数里面)的值,并非内存地址,所以Block内部不能改变自动变量的值。
变量的指针通常都是存放在栈上的,而__block会在堆上拷贝一份对应的变量,并且引用变量的指针,从而达到修改的目的
如果指针本身就存在于堆上则直接修改原对象
(13)objc在向一个对象发送消息时,发生了什么?
runtime会根据对象的isa指针找到对象所属的类,然后在类中寻找是否有对象的方法和实现,如果当前类中没有的话,就会到父类中去找,然后沿继承链去寻找,如果找到的话就直接运行,找不到的话就进入消息转发的流程
(14)什么时候会报unregnized selector错误? iOS有哪些机制来避免走到这一步?
当对象及其父类没有实现它所要调用的方法就会报错,并且在运行时也没有找到对应的方法时,可以在消息转发过程中的任何一个环节拦截这个错误并且处理,使应用程序不会崩溃
这个主要说的就是消息转发机制,并且其中可采用的对应的处理
(15)能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量?为什么?
不能向编译后得到的类中添加实例变量,可以向运行时创建的类中添加实例变量,因为编译后的类已经注册在 runtime 中,类结构体中的 objc_ivar_list 实例变量的链表 和 instance_size 实例变量的内存大小已经确定,同时runtime 会调用 class_setIvarLayout 或 class_setWeakIvarLayout 来处理 strong weak 引用。所以不能向存在的类中添加实例变量;
运行时创建的类是可以添加实例变量,调用 class_addIvar 函数。但是得在调用 objc_allocateClassPair 之后,objc_registerClassPair 之前
(16)runtime如何实现weak变量的自动置为nil?
runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为0的时候会 dealloc,假如 weak 指向的对象内存地址是a,那么就会以a为键, 在这个 weak 表中搜索,找到所有以a为键的 weak 对象,从而设置为 nil。
(17)给类添加一个属性后,在类结构体理哪些元素会发生变化?
I_VAR
METHOD_LIST
属性偏移量,
propert_list
(18)苹果是如何实现autorelease pool的?
autoreleasepool 以一个队列数组的形式实现,主要通过下列三个函数完成.
- objc_autoreleasepoolPush
- objc_autoreleasepoolPop
- objc_autorelease
看函数名就可以知道,对 autorelease 分别执行 push,和 pop 操作。销毁对象时执行release操作。
(19)类方法和实例方法有什么区别?
1 类方法在程序开始时就分配好了内存,实例方法在运行时分配内存,所以类方法可以直接调用
2 实例方法需要通过实例来进行调用,类方法可以直接调用(理论上比实例方法快)
3 类方法的内存是连续的,实例方法的内存是分散的。类方法常驻内存,实例方法不是。
4 类方法在堆上分配内存,实例方法在堆栈上
5 类方法中不能直接使用实例变量或调用实例方法
(20) 分类的内部实现?
1.我们不主动引入 Category 的头文件,Category 中的方法都会被添加进主类中。我们可以通过 - performSelector: 等方式 对 Category 中的相应方法进行调用
a)将 Category 和它的主类(或元类)注册到哈希表中;
b)如果主类(或元类)已实现,那么重建它的方法列表
2.在这里分了两种情况进行处理:Category 中的实例方法和属性被整合到主类中;而类方法则被整合到元类中。另外,对协议的处理比较特殊,Category 中的协议被同时整合到了主类和元类中。
3.注意到,不管是哪种情况,最终都是通过调用 staticvoid remethodizeClass(Class cls) 函数来重新整理类的数据的。
(21)objc向一个nil对象发送消息将会发生什么?
如果向一个nil对象发送消息的话,会先去查询对象的isa指针所指向的类,因为当前对象为nil,isa指针的地址就是0直接返回了,所以不会存在错误
(22)AFN为什么添加一条常驻线程?
AFN 的做法是把网络请求的发起和解析都放在同一个子线程中进行,但由于子线程默认不开启 runloop,它会向一个 C语言程序那样在运行完所有代码后退出线程。而网络请求是异步的,这会导致获取到请求数据时,线程已经退出,代理方法没有机会执行。因此,AFN 的做法是使用一个 runloop 来保证线程不死~
然而频繁的创建线程并启动runloop肯定会造成内存泄露(runloop 无法停止.线程无法退出)
所以AFN就创建了一个单例线程,并且保证线程不退出~
(23)最近遇到的一个难点和解决的途径?
(24)UIWebview有哪些性能问题?有没有可替代的方案?
我只能回答打开速度慢,而且交互不流畅,求大神解答
(25)Swift和Objective-c语言的区别是什么?
当你使用Swift编程的时候,你就不能使用Objective-C的思路去使用Swift了,你要知道Swift的特性是什么,不单单是针对OC的特性,而是这门语言本身的特性
(26)http如何在客户端实现转变成HTTPS
这个询问的是要用iOS原生的方法,这个问题目前我还没有去看,所以没有答案
(27)tanleview的优化
一定要说得多一点,结合实例,我这块也是比较薄弱,所以也没有答案
(28)如何通过图片的URL地址得出图片的大小,如果图片过大就不进行下载?
这块看得也简单,最终都是要先去下载图片的,不知道面试官的意思是是否图片过大就不去解码了,这个部分也没有吃透
(29)简单算法了解
冒泡排序,快速排序,这些看还是要看看的,至少问起来不尴尬
以上就是我整理和面试过程中没有回答好的问题啦,希望对各位要面试或准备面试的小伙伴有一点帮助。