iOS知识整理(二)

2017-10-19  本文已影响95人  Fly晴天里Fly

OC知识整理

代码规范

iOS 代码规范

#pragma mark - 添加子视图
#pragma mark - 添加分割线
//mark:添加标记1
/* FIXME: 添加标记2 /
// MARK: 添加标记3
/
!!!: 添加标记4 /
/
???: 添加标记5 /
/
TODO: 添加标记6 */
#warning 添加警告

小知识点

深入理解 iOS 开发中的锁
深入理解 iOS 开发中的锁
iOS正确使用多线程同步锁 @synchronized()

显式转换 id和void
id和void *
通过“_ _ bridge 转换”,id 和void * 就能够相互转换
ARC 类型转换:显示转换 id 和 void *
CoreFunction和Function 一个是C的库一个OC的库
IOS开发之__bridge,__bridge_transfer和__bridge_retained

Autolayout
iOS 中 Autolayout 优先级的使用

APNS
国内90%以上的iOS 开发者,对APNs的认识都是错的

NSNotificationCenter
浅谈 iOS Notification

当这个事件确实发生了,通知中心发出通知,立刻广播通知到所有注册的对象。或者,通知被放到通知队列中,这个通知延迟指定的通知并且根据指定的标准聚合类似的通知,然后会发布通知到通知中心。

通知中心同步地传递通知给观察者。换句话说,当发布一个通知时,直到所有的观察者都收到以及处理通知后,发布者才能重新控制发布。要异步地发送通知,要使用通知队列。请参考通知队列。

Load过程
关于 +load 方法的几个 QA
Q: 重载自己 Class 的 +load 方法时需不需要调父类?
A: runtime 负责按继承顺序递归调用,所以我们不能调 super

Q: 在自己 Class 的 +load 方法时能不能替换系统 framework(比如 UIKit)中的某个类的方法实现
A: 可以,因为动态链接过程中,所有依赖库的类是先于自己的类加载的

Q: 重载 +load 时需要手动添加 @autoreleasepool 么?
A: 不需要,在 runtime 调用 +load 方法前后是加了 objc_autoreleasePoolPush() 和 objc_autoreleasePoolPop() 的。

Q: 想让一个类的 +load 方法被调用是否需要在某个地方 import 这个文件
A: 不需要,只要这个类的符号被编译到最后的可执行文件中,+load 方法就会被调用(Reveal SDK 就是利用这一点,只要引入到工程中就能工作)

Objc_msgSend消息转发
初始化阶段 —— load 和 initialize
继承自NSObject的不常用又很有用的函数-2
深入理解Objective-C消息转发机制
Objective-C 消息转发
iOS 运行时之消息转发机制
IOS OC 消息转发机制
iOS沉思录-OC消息传递机制三道防线:消息转发机制详解
神经病院 Objective-C Runtime 住院第二天——消息发送与转发

一、动态方法解析(dynamic method resolution)
对象在接收到无法解读的消息后,首先将调用其所属类的下列类方法

//实例方法

二、备援接受者
当前接受者还有第二次机会能处理未知的选择子,在这一步,runtime会询问对象能不能把这条消息转给其他接受者来处理

三、完整的消息转发

Block

iOS Block原理探究以及循环引用的问题
block的小测试
iOS进阶(一)block与property

block的copy机制
作为变量:
一个 block 刚声明的时候是在栈上
赋值给一个普通变量之后就会被 copy 到堆上
赋值给一个 weak 变量不会被 copy
作为属性:
用 strong 和 copy 修饰的属性会被 copy
用 weak 和 assign 修饰的属性不会被 copy
函数传参:
作为参数传入函数不会被 copy
作为函数的返回值会被 copy

多线程

GCD

GCD容易让人迷惑的几个小问题
-Parse的底层多线程处理思路:GCD高级用法 --好好看下
关于GCD开发的一些事儿

dispatch_block_cancel
之前在介绍nsopreration的时候提到它的一个优点是可以取消某个operation,现在在iOS8之后,提交到gcd队列中的dispatch block也可取消了,只需要简单的调用dispatch_block_cancel传入想要取消的block即可:

看到这我们可以知道一些sync的阻塞机制:

我们了解了sync的阻塞机制,再结合发生死锁的根本原因来自于互相等待,我们用下面一句话来总结一下,会引起GCD死锁的行为:
如果同步(sync)提交一个Block到一个串行队列,而提交Block这个动作所处的线程,也是在当前队列,就会引起死锁。

NSOperation

1.继承NSOperation重写什么方法?
-(void)main

NSThread

AutoreleasePool

文档翻译-NSAutoreleasePool

在引用计数的环境下(跟垃圾收集机制不同), 一个对象入池(NSAutoreleasePool对象)前均会收到一条autorelease的消息, 当池子被销毁的时候会发送一条release的消息给这些对象. 因此, 发送autorelease消息来代替发送release消息可以延长池中对象的生命周期, 直到池子被销毁. (这种情况下对象的生命周期有可能更长因为有可能有别的对象引用着这个池中的对象). 另外值得注意的是, 一个对象可以反复加入同一个池子中, 只是它每次入池之前都会先收到release消息.

当需要在程序中创建大量的临时变量时(大量也可指数量多,不确定,比如从数据库中读取数据时),很容易使内存产生峰值又回到内存低谷,这样对程序的性能会产生很大影响,而使用自动释放池后,峰值明显有所下降。
官方提出的解决方案是,在大量产生局部变量的位置用autoreleasepool代码块进行包装。比如for循环中要执行的语句,这样每次for循环结束后就会及时收回临时变量占用的内存空间。

编译器

Mach-O 可执行文件
iOS 程序 main 函数之前发生了什么
Objective-C Runtime : From Build To Did Launch
你真的了解 load 方法么?
编译器的工作过程
clang编译器
理解编译过程

Runloop

深入理解RunLoop
Runloop本质:mach port和mach_msg()。
Mach是XNU的内核,进程、线程和虚拟内存等对象通过端口发消息进行通信,Runloop通过mach_msg()函数发送消息,如果没有port 消息,内核会将线程置于等待状态 mach_msg_trap() 。如果有消息,判断消息类型处理事件,并通过modeItem的callback回调.
Runloop有两个关键判断点,一个是通过msg决定Runloop是否等待,一个是通过判断退出条件来决定Runloop是否循环。

iOS多线程编程指南(三)Run Loop
iOS多线程编程指南(一)关于多线程编程

基于runloop的线程保活、销毁与通信

  1. 深入理解RunLoop
  2. 解密-神秘的 RunLoop
  3. iOS RunLoop进阶
  4. 关于NSRunLoop和NSTimer的深入理解
  5. 【iOS程序启动与运转】- RunLoop个人小结

RunTime

isa 和 meta-class
objectC 的isa 详解
Method,SEL,IMP的区别
Runtime 10种用法
OC最实用的runtime总结,面试、工作你看我就足够了
Runtime详解(面试必备)

Runtime-动态创建类添加属性和方法
iOS开发之原来Runtime的黑魔法这么厉害
可能碰到的iOS笔试面试题(22)--Runtime
iOS进阶(二)Objective-C底层原理

Objective-C Runtime
Method Swizzling 和 AOP 实践
黑魔法教你让iOS APP防住Crash

Category

iOS RunTime之六:Category及原理
追本溯源-category如何加载

categories的作用?继承和categories在实现中有何区别?
我们知道,在类和category中都可以有+load方法,那么有两个问题:
1)、在类的+load方法调用的时候,我们可以调用category中声明的方法么?
2)、这么些个+load方法,调用顺序是咋样的呢?

所以,对于上面两个问题,答案是很明显的:
1)、可以调用,因为附加category到类的工作会先于+load方法的执行
2)、+load的执行顺序是先类,后category,而category的+load执行顺序是根据编译顺序决定的。
目前的编译顺序是这样的:

DNS劫持

iOS强制ATS后,DNS劫持问题如何解决?
iOS监控-DNS劫持
iOS网络请求优化之DNS映射

KVC&KVO

探究KVO的底层实现原理
KVC和KVO
深入理解 KVC\KVO 实现机制 — KVC
谈谈 KVO--详细

自己实现KVO
原生的KVO API是不太友好的,需要监听者对象,和被监听的对象分别去实现一些东西,代码实现比较分散,并且响应通知的方法也不能自定义,只能在苹果提供的方法中处理,不能用我们熟悉的block或者Target-Action,最后还不能忘了调用removeObserve方法,一忘可能程序运行的时候就奔溃了.
如何自己动手实现 KVO
如何手动触发一个value的KVO

我们重点介绍KVC的实现原理。
第一、方法定义
NSKeyValueCodingprotocol
第二、setValue:forKey是如何访问属性值的

KVC方法的实现get、set方法及实例变量的访问,KVC setValue方法和getValue方法按顺序使用如下技术:

  1. 检查是否存在set<Key>:方法
    如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的set方法,所以这种情况下会直接搜索到。
  2. 检查名为-_<key>、-_is<key>(只针对布尔值有效)、-set<key>:方法;那么按<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。
  3. 直接访问实例变量。实例变量可以是名为:<key>或_<key>;
  4. 调用方法setValue:forUndefinedKey

第三、valueForKey是如何访问属性值的

跟上面setValue执行顺序类似,把set方法改成get方法,当所有都失效时调用方法valueForUndefinedKey。

第四、方法重写

如果我们的类既没有key或_key对应的set/get方法,也没有key或_key对应的实例变量,但要使用setValue和getValue方法,必须重写函数setValue:forUndefinedKey和valueForUndefinedKey。

Extension

iOS8中Today Extension(Widget)的使用

[深入浅出Cocoa]详解键值观察(KVO)及其实现机理](http://blog.csdn.net/kesalin/article/details/8194240)

UI事件响应

1.事件响应对象寻找和事件响应回溯
2.怎么让超出superView的部分,可以响应事件。

hitTest:withEvent:方法的处理流程:

先调用pointInside:withEvent:判断触摸点是否在当前视图内
1.如果返回YES,那么该视图的所有子视图调用hitTest:withEvent,调用顺序由层级低到高(top->bottom)依次调用。
2.如果返回NO,那么hitTest:withEvent返回nil,该视图的所有子视图的分支全部被忽略
如果某视图的pointInside:withEvent:返回YES,并且他的所有子视图hitTest:withEvent:都返回nil,或者该视图没有子视图,那么该视图的hitTest:withEvent:返回自己。

如果子视图的hitTest:withEvent:返回非空对象,那么当前视图的hitTest:withEvent:也返回这个对象,也就是沿原路回推,最终将hit-test view传递给keyWindow

如果父控件不能接受事件, 那么子控件就不能接受事件. 如:UIImageView
以下视图的hitTest:withEvent:方法会返回nil,导致自身和其所有子视图不能被hit-testing发现,无法响应触摸事件:
1.隐藏(hidden=YES)的视图
2.禁止用户操作(userInteractionEnabled=NO)的视图
3.alpha<0.01的视图
4.视图超出父视图的区域

iOS-hitTest:withEvent与自定义hit-testing规则
让超出父视图范围的子视图响应事件,在UIView范围外响应点击

不同坐标系点的转化为一个坐标系,并判断是否在某个范围
iOS 坐标系转换(convertPoint)以及点在范围内的判断(pointInside)
点击事件处理, 以及hitTest:withEvent:实现

讲述讲述hit-testing过程



假设用户点击了视图E,系统按照以下顺序来查找hit-test视图:

点击事件发生在视图A的边界内,所以检测子视图B和C;
点击事件不在视图B的边界内,但在视图C的边界范围内,所以检测子图片D和E;
点击事件不在视图D的边界内,但在视图E的边界范围内;
视图E是包含触摸点的视图层次架构中最底层的视图(倒树结构),所以它就是hit-test视图。

因此,我们就可以得到此点击事件的响应链了


事件分发之Response Chain

当一个事件发生时,如果 first responder 不处理,事件就会继续往下传递,被下个 responder 接收,如果下个 responder 也不处理,又会被下下个 responder 接收…… 直到一个 responder 处理了事件或者没有 responder 了。这些 responder 按照传递次序连接起来的链条就构成了响应者链。iOS 上的响应者链:



由于不同的 app 内的布局和层次结构的不同,响应顺序也会有所不同,但事件的传递路径会遵守基本规则。从图中可以看到,响应者链有以下特点:

响应者链通常是由 initial view 开始;

UIView 的 nextResponder 它的 superview;如果 UIView 已经是其所在的 UIViewController 的 top view,那么 UIView 的 nextResponder 就是 UIViewController;

UIViewController 如果有 Super ViewController,那么它的 nextResponder 为其 Super ViewController 最表层的 View;如果没有,那么它的 nextResponder 就是 UIWindow;

UIWindow 的 contentView 指向 UIApplication,将其作为 nextResponder;

UIApplication 是一个响应者链的终点,它的 nextResponder 指向nil,整个 responder chain 结束。

需要说明是,如果当前的 responder 不处理事件,并希望将其传递给 nextResponder 时,需要手动编写代码,才会继续往下传递,否则事件会被废弃。

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{
// 将事件传递给 nextResponder
id theNextResponder = [self nextResponder];
[theNextResponder touchesBegan:touches withEvent:event];
}

总结:

所以关于事件的链有两条:事件的响应链;Hit-Testing 时事件的传递链。

响应链:由离用户最近的view向系统传递。
initial view –> super view –> …..–> view controller –> window –> Application –> AppDelegate

Hit-Testing 链:由系统向离用户最近的view传递。
UIKit –> active app's event queue –> window –> root view –>……–>lowest view

iOS Events and Responder Chain
iOS触摸事件处理详解

Layer

综述iOS视图的frame、bounds、center、position、anchorPosition等与位置、大小有关的属性

UIAnimation

iOS动画,绝对够分量!

iOS设计模式

简单工厂、工厂方法、抽象工厂、策略模式、策略与工厂的区别
iOS设计模式

类簇其实很简单,就是一个抽象工厂模式的iOS版本的实现。类簇不能继承
iOS 类簇(Class Cluster)使用心得

iOS安全checkList

iOS平台下基于UIWebView漏洞的研究

代码混淆

iOS对源代码进行混淆

iOS各版本新功能

ios10有哪些新功能?
开发者所需要知道的 iOS 10 SDK 新特性
ios11有哪些新功能?

上一篇下一篇

猜你喜欢

热点阅读