1、Swift对比Objective-C的优缺点?
优点:
- swift是**类型安全的语言,注重安全,
OC
注重灵活 - swift注重面向协议编程、函数式编程、面向对象编程,OC注重面向对象编程
- swift注重值类型,OC注重指针和引用
- swift是静态类型语言,OC是动态类型语言
- swift中的可选类型,是用于所有数据类型,而不仅仅局限于类。相比于OC中的nil更加安全和简明
- swift中的泛型类型更加方便和通用,而非
OC
中只能为集合类型添加泛型 - swift支持函数式编程,Objc本身是不支持的,需要通过引入ReactiveCocoa这个库才可支持函数式编程。
- swift中独有的元组类型(tuples),把多个值组合成复合值。元组内的值可以是任何类型,并不要求是相同类型的。
- swift新增了两种权限,细化权限。
open
>public
>internal
(默认)>fileprivate
>private
- swift中各种方便快捷的[高阶函数](函数式编程)(Swift的标准数组支持三个高阶函数:map,filter和reduce,以及map的扩展flatMap)
缺点:
- 版本不稳定
- App体积变大:使用 Swift 后, App 体积大概增加 5-8 M 左右,对体积大小敏感的慎用。(体积变大的原因是因为 Swift 还在变化,所以 Apple 没有在 iOS 系统里放入 Swift 的运行库,反而是每个 App 里都要包含其对应的 Swift 运行库。)
- 对于不支持Swift的一些第三方类库,如果非得使用,只能混合编程,利用桥接文件实现。
- 社区的开源项目偏少,毕竟OC独大好多年,很多优秀的类库都不支持Swift,不过这种状况正在改变,现在有好多优秀的Swift的开源类库了
- 上线方式改变:在上线的时候,不能使用application Loader上传包文件,会提示你丢失了swift support files,应该使用xcode直接上传。
安全:
- 由于swift的strong static type system,编译器可帮你检查出更多问题,而不是在运行时突然boom,还有一个很牛逼的安全特性就是OptionalType。
快速:
- 静态语言相对来说语言本身速度更快,swift编译期间就能生成vtable,确定具体要调用的方法,比起oc的动态派发自然是更快,当然处理到与oc之间的桥接部分,可能不一定比OC快
细节使用区别
2、autoReleasePool
创建和释放?
App
启动后,苹果在主线程 RunLoop
里注册了两个Observer
,其回调都是 _wrapRunLoopWithAutoreleasePoolHandler()
。
第一个
Observer
监视的事件是Entry(即将进入Loop)
,其回调内会调用_objc_autoreleasePoolPush()
创建自动释放池。其 order 是 -2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。第二个
Observer
监视了两个事件:BeforeWaiting
(准备进入休眠) 时调用_objc_autoreleasePoolPop()
和_objc_autoreleasePoolPush()
释放旧的池并创建新池;Exit
(即将退出Loop) 时调用_objc_autoreleasePoolPop()
来释放自动释放池。这个 Observer 的 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。
在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。
3、autoReleasePool
内部实现?
4、Socket
原理?
5、IOS内存管理机制
- MRC & ARC
- TaggedPointer & NONPOINTER_ISA
- 散列表( 引用计数表 & 弱引用表&自旋锁)
- 自动释放池
6、SDWebImage做了哪些工作?
- 1:正在下载该url的图片,直接返回;
- 2:处理多线程问题,比如cell复用造成的显示错乱问题,也就是下载之前先取消;
- 3:增加一层内存缓存,直接从url得到image,NSURLCache存的是data;
- 4:相同url请求时只加了一个finish回调;
- 5:请求做了排队处理,控制资源。
7、iOS常用设计模式?
装饰模式:分类;
代理模式:协议;
工厂模式:UIButton创建;
原型模式:[object copy];
观察者模式:KVO;
迭代器模式:数组的遍历;
单例模式:Appdelegate;
命令模式:给对象发消息;
职责链模式:事件传递链;
中介者模式:模块解耦;
解释器模式:Siri语意识别;
8、OC中向一个nil对象发送消息将会发生什么?
在 Objective-C 中向 nil 发送消息是完全有效的——只是在运行时不会有任何作用
- 如果一个方法返回值是一个对象,那么发送给nil的消息将返回0(nil)
- 如果方法返回值为指针类型,其指针大小为小于或者等于sizeof(void*),float,double,long double 或者 long long 的整型标量,发送给 nil 的消息将返回0。
- 如果方法返回值为结构体,发送给 nil 的消息将返回0。结构体中各个字段的值将都是0。
- 如果方法的返回值不是上述提到的几种情况,那么发送给 nil 的消息的返回值将是未定义的。
具体原因如下:
objc是动态语言,每个方法在运行时会被动态转为消息发送,即:
objc_msgSend(receiver, selector)。
9、Runloop与事件派发?
https://www.jianshu.com/p/c42bffa97934
当一个硬件事件(触摸/锁屏/摇晃等)发生后,首先由 IOKit.framework 生成一个 IOHIDEvent 事件并由 SpringBoard 接收。SpringBoard 只接收按键(锁屏/静音等),触摸,加速,接近传感器等几种 Event,随后用 mach port 转发给需要的App进程。随后苹果注册的那个 Source1 就会触发回调,并调用 _UIApplicationHandleEventQueue() 进行应用内部的分发。
10、Dealloc实现原理?
- 首先会调用 _objc_rootDealloc() 函数。
-
然后调用rootDealloc(),在这个函数内部会判断对象是否可以直接释放。判断的条件是判断当前对象是否使用了非指针型的isa、当前对象是否有weak指针指向他、是否有关联对象、当前对象的内部实现是否有c++相关的内容,当前对象是否使用arc管理内存、当前对象的引用计数是否使用散列表来维护的。只有以上条件都不满足才会调用object_dispose(),然后结束,否则调用c函数 free()处理
11、object_dispose()实现?
objc_destructInstance() 实现
12、iOS App 启动性能优化?
https://zhuanlan.zhihu.com/p/28600469
启动优化总结:
- 利用DYLD_PRINT_STATISTICS分析main()函数之前的耗时
- 重新梳理架构,减少动态库、ObjC类的数目,减少Category的数目
- 定期扫描不再使用的动态库、类、函数,例如每两个迭代一次
- 用dispatchonce()代替所有的_attribute((constructor)) 函数、C++静态对象初始化、ObjC的+load
- 在设计师可接受的范围内压缩图片的大小,会有意外收获
- 利用锚点分析applicationWillFinishLaunching的耗时
- 将不需要马上在applicationWillFinishLaunching执行的代码延后执行
- rootViewController的加载,适当将某一级的childViewController或subviews延后加载
- 如果你的App可能会被后台拉起并冷启动,可考虑不加载rootViewController
- 不应放过的一些小细节
- 异步操作并不影响指标,但有可能影响交互体验,例如大量网络请求导致数据拥堵
- 有时候一些交互上的优化比技术手段效果更明显,视觉上的快决不是冰冷的数据可以解释的,好好和你们的设计师谈谈动画
12、App启动过程?
- 解析Info.plist
- 加载相关信息,例如如闪屏
- 沙箱建立、权限检查
- Mach-O加载
- 如果是胖二进制文件,寻找合适当前CPU类别的部分
- 加载所有依赖的Mach-O文件(递归调用Mach-O加载的方法)
- 定位内部、外部指针引用,例如字符串、函数等
- 执行声明为attribute((constructor))的C函数
- 加载类扩展(Category)中的方法
- C++静态对象加载、调用ObjC的 +load 函数
- 程序执行
- 调用main()
- 调用UIApplicationMain()
- 调用applicationWillFinishLaunching
13、动态库静态库区别?
介绍
- 动态库形式:.dylib和.framework
- 静态库形式:.a和.framework
区别
- 静态库:链接时,静态库会被完整地复制到可执行文件中,被多次使用就有多份冗余拷贝(图1所示)
-
链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存
14、为什么刷新UI在主线程?
https://www.jianshu.com/p/5849eb69ec82
15、__block的实现原理?
https://www.cnblogs.com/feng9exe/p/7486099.html
16、如何理解OC是一门动态语言?
https://blog.csdn.net/wangsongyang617/article/details/79550045
17、iOS:网络优化?
https://blog.csdn.net/pk_sir/article/details/107865152
18、为什么要设计metaclass?
http://www.zyiz.net/tech/detail-111585.html
1、首先会再一次的从类中寻找需要调用方法的缓存,如果能命中缓存直接返回该方法的实现,如果不能命中则继续往下走。
2、从类的方法列表中寻找该方法,如果能从列表中找到方法则对方法进行缓存并返回该方法的实现,如果找不到该方法则继续往下走。
3、从父类的缓存寻找该方法,如果父类缓存能命中则将方法缓存至当前调用方法的类中(注意这里不是存进父类),如果缓存未命中则遍历父类的方法列表,之后操作如同第2步,未能命中则继续走第3步直到寻找到基类。
4、如果到基类依然没有找到该方法则触发动态方法解析流程。
5、还是找不到就触发消息转发流程
走到这里一套方法发送的流程就都走完了,那这跟元类的存在有啥关系?我们都知道类方法是存储在元类中的,那么可不可以把元类干掉,在类中把实例方法和类方法存在两个不同的数组中?
答:行是肯定可行的,但是在lookUpImpOrForward执行的时候就得标注上传入的cls到底是实例对象还是类对象,这也就意味着在查找方法的缓存时同样也需要判断cls到底是个啥。
倘若该类存在同名的类方法和实例方法是该调用哪个方法呢?这也就意味着还得给传入的方法带上是类方法还是实例方法的标识,SEL并没有带上当前方法的类型(实例方法还是类方法),参数又多加一个,而我们现在的objc_msgSend()只接收了(id self, SEL _cmd, ...)这三种参数,第一个self就是消息的接收者,第二个就是方法,后续的...就是各式各样的参数。
通过元类就可以巧妙的解决上述的问题,让各类各司其职,实例对象就干存储属性值的事,类对象存储实例方法列表,元类对象存储类方法列表,完美的符合6大设计原则中的单一职责,而且忽略了对对象类型的判断和方法类型的判断可以大大的提升消息发送的效率,并且在不同种类的方法走的都是同一套流程,在之后的维护上也大大节约了成本。
19、section和segment 区别?
section 称为节,是指在汇编源码中经由关键字section 或segment 修饰、逻辑划分的指令或数据区域,汇编器会将这两个关键字修饰的区域在目标文件中编译成节,也就是说“节”最初诞生于目标文件中。
segment 称为段,是链接器根据目标文件中属性相同的多个section 合并后的section 集合,这个集合称为segment,也就是段,链接器把目标文件链接成可执行文件,因此段最终诞生于可执行文件中。我们平时所说的可执行程序内存空间中的代码段和数据段就是指的segment 。
19、Http特性对比
HTTP1.0
- 无状态、无连接
HTTP1.1
- 持久连接
- 请求管道化
- 增加缓存处理(新的字段如cache-control)
- 增加Host字段、支持断点传输等
HTTP2.0
- 二进制分帧 -> 滑动窗口协议
- 多路复用(或连接共享)
- 头部压缩
- 服务器推送
20、IOS 死锁案例
1、
// 非死锁
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"====");
});
// 死锁
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"====");
});
2、信号量死锁一直等待
3、lock锁死某块资源不释放
21、Swift 可选类型底层实现
@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none
/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)
public init(_ some: Wrapped)
}
- Optional是通过enum实现的,Optional本质是枚举。
- 有两个case,nil和some。
- 关联值就是传进来的值。
相关连接
22、iOS调优 | 深入理解Link Map File
文件组成
- Object files 最前面的部分是Object files,展示了参与编译的所有文件序号及路径(.o文件)
[2] ../test/Debug-iphonesimulator/EaseAPIDemo(TestUtils.o)
[3] ../test/Debug-iphonesimulator/EaseAPIDemo(TestCell.o)
[4] ../test/Debug-iphonesimulator/EaseAPIDemo(TestView.o)
***
[1222] ***Foundation.framework/Foundation
[1223] ***UIKit.framework/UIKit
- Segment & section 接着是section表,是按照 mach-o 文件映射的Segment和section信息。
0x100006AE4 0x0005A5AC __TEXT __text
0x100061090 0x00000984 __TEXT __stubs
0x100061A14 0x0000099C __TEXT __stub_helper
0x1000623B0 0x00001180 __TEXT __const
0x100063530 0x00002B96 __TEXT __objc_methname
0x1000660C6 0x000000D0 __TEXT __objc_classname
0x100066196 0x00000CEC __TEXT __objc_methtype
0x100066E82 0x00013955 __TEXT __cstring
0x10007A7D8 0x000010D2 __TEXT __ustring
0x10007B8AC 0x000000A8 __TEXT __gcc_except_tab
0x10007B954 0x000006A8 __TEXT __unwind_info
0x10007C000 0x000003E0 __DATA __got
0x10007C3E0 0x00000658 __DATA __la_symbol_ptr
0x10007CA38 0x00000AE0 __DATA __const
0x10007D518 0x00000E20 __DATA __cfstring
0x10007E338 0x00000040 __DATA __objc_classlist
0x10007E378 0x00000010 __DATA __objc_nlclslist
0x10007E388 0x00000000 __DATA __objc_catlist
0x10007E388 0x00000020 __DATA __objc_protolist
0x10007E3A8 0x00000008 __DATA __objc_imageinfo
其中__text是代码段,__data是数据段,__cfstring表示C字符常量section,__objc_classlist是全部Objective-C类列表,__objc_classrefs是引用到的Objective-C类列表(不包括通过反射引用的,这点特别注意)。
技巧:使用otool工具获得各自 __objc_classrefs和 __objc_classlist列表的地址去重后,得到的地址列表就是没有用到的类地址列表,在通过Link Map找到对应地址的无用类即可以删除无用的类。
otool -v -s __DATA __objc_classlist EaseAPIDemo_v7
- 符号表
接着是符号表,按照Object files表中的文件序号依次列出了所有的方法,地址和占用的空间大小,常量等。示例
0x100001E20 0x000000A0 [ 12] -[EaseAPIDemoInfo init]
0x100001EC0 0x00000240 [ 12] -[EaseAPIDemoInfo parameterInit]
0x100002100 0x00000190 [ 12] -[EaseAPIDemoInfo parameterValidation]
...
//如果是C语言的函数,直接显示函数名字,示例:
0x10470E254 0x00000006 [2063] _sqlite3_bind_blob
0x10470E25A 0x00000006 [2063] _sqlite3_bind_double
0x10470E260 0x00000006 [2063] _sqlite3_bind_int
0x10470E266 0x00000006 [2063] _sqlite3_bind_null
0x10470E26C 0x00000006 [2063] _sqlite3_bind_text16
0x10470E272 0x00000006 [2063] _sqlite3_close
根据以上信息即可分析每一个.o或者framework文件的内存占用大小,对于减小包大小有很大帮助。
Link-Map
作用
- 通过分析linkMap文件可以查看每个文件大小,包瘦身可以用到连接
22、WebKit MessageHandle 原理
实现原理:
- 1、JS与iOS约定好jsToOc方法,用作JS在调用iOS时的方法;
- 2、iOS使用WKUserContentController的-addScriptMessageHandler:name:方法监听name为jsToOc的消息;
- 3、JS通过window.webkit.messageHandlers.jsToOc.postMessage()的方式对jsToOc方法发送消息;
- 4、iOS在-userContentController:didReceiveScriptMessage:方法中读取name为jsToOc的消息数据message.body。