怎么破解软件注册码
为了探究渲染的触发时机,我们自定义一个TestView并复写 drawRect: 方法。
虽然开发中不推荐这么使用 drawRect: 方法,这里是为了设置断点,探究渲染的触发时机。
@interface TestView : UIView
@end
@implementation TestView
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
}
@end
@implementation ViewController
-
(void)loadView
{
self.view = [[TestView alloc] initWithFrame:[UIScreen mainScreen].bounds];
} -
(void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.view.backgroundColor = [UIColor blueColor];
});UIButton *button = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[button addTarget:self action:@selector(buttonPressed) forControlEvents:UIControlEventTouchUpInside];
button.center = self.view.center;
[self.view addSubview:button];
} -
(void)buttonPressed
{
self.view.backgroundColor = [UIColor redColor];
}
@end
复制代码我们在 drawRect: 方法中设置一个断点,然后运行我们的测试代码。
1.1 情况1
刚运行起来就会进入断点,我们在 lldb 中使用 bt 打印一下调用栈。
(lldb) bt
- thread #1, queue = ‘com.apple.main-thread’, stop reason = breakpoint 1.1
- frame #0: 0x000000010bf67094 OCDemo
-[TestView drawRect:](self=0x00007fbd0a70ec00, _cmd="drawRect:", rect=(origin = (x = 0, y = 0), size = (width = 375, height = 812))) at ViewController.m:19:5 frame #1: 0x00007fff491928ae UIKitCore
-[UIView(CALayerDelegate) drawLayer:inContext:] + 632
frame #2: 0x000000010e0b7941 UIKit-[UIViewAccessibility drawLayer:inContext:] + 74 frame #3: 0x00007fff2b4c5ca4 QuartzCore
-[CALayer drawInContext:] + 286
frame #4: 0x00007fff2b391d58 QuartzCoreCABackingStoreUpdate_ + 196 frame #5: 0x00007fff2b4ce665 QuartzCore
___ZN2CA5Layer8display_Ev_block_invoke + 53
frame #6: 0x00007fff2b4c5616 QuartzCore-[CALayer _display] + 2026 frame #7: 0x00007fff2b4d7d72 QuartzCore
CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 520
frame #8: 0x00007fff2b420c04 QuartzCoreCA::Context::commit_transaction(CA::Transaction*, double) + 324 frame #9: 0x00007fff2b4545ef QuartzCore
CA::Transaction::commit() + 649
frame #10: 0x00007fff48ca3747 UIKitCore__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 81 frame #11: 0x00007fff23da0b5c CoreFoundation
CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK + 12
frame #12: 0x00007fff23da0253 CoreFoundation__CFRunLoopDoBlocks + 195 frame #13: 0x00007fff23d9b043 CoreFoundation
__CFRunLoopRun + 995
frame #14: 0x00007fff23d9a944 CoreFoundationCFRunLoopRunSpecific + 404 frame #15: 0x00007fff38ba6c1a GraphicsServices
GSEventRunModal + 139
frame #16: 0x00007fff48c8b9ec UIKitCoreUIApplicationMain + 1605 frame #17: 0x000000010bf677ba OCDemo
main(argc=1, argv=0x00007ffee3c97d28) at main.m:18:12
frame #18: 0x00007fff51a231fd libdyld.dylibstart + 1 frame #19: 0x00007fff51a231fd libdyld.dylib
start + 1
复制代码从调用栈我们可以看到,App运行起来主线程的 RunLoop 会触发 -[UIApplication _firstCommitBlock] 进行第一次的绘制。
1.2 情况2
我们以前看其他博客的时候经常看到以下说法:
- frame #0: 0x000000010bf67094 OCDemo
当在操作UI时,比如改变了frame、更新了UIView/CALayer的层次时,或者手动调用了UIView/CALayer的setNeedsLayout/setNeedsDisplay方法后,这个UIView/CALayer就被标记为待处理,并被提交到一个全局的容器去。
苹果注册了一个Observer监听BeforeWaiting(即将进入休眠)和Exit(即将退出Loop)事件,回调去执行一个很长的函数:
_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv。
这个函数里会遍历所有待处理的UIView/CAlayer以执行实际的绘制和调整,并更新UI界面。
下面我们来验证一下。继续运行,执行完下面代码的中改变视图背景色的部分后
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.view.backgroundColor = [UIColor blueColor];
});
复制代码会进入第二次的断点:
(lldb) bt
- thread #1, queue = ‘com.apple.main-thread’, stop reason = breakpoint 1.1
- frame #0: 0x00000001040cde64 OCDemo
-[TestView drawRect:](self=0x00007fdd2dc09ee0, _cmd="drawRect:", rect=(origin = (x = 0, y = 0), size = (width = 375, height = 812))) at ViewController.m:19:5 frame #1: 0x00007fff491928ae UIKitCore
-[UIView(CALayerDelegate) drawLayer:inContext:] + 632
frame #2: 0x00000001045a9941 UIKit-[UIViewAccessibility drawLayer:inContext:] + 74 frame #3: 0x00007fff2b4c5ca4 QuartzCore
-[CALayer drawInContext:] + 286
frame #4: 0x00007fff2b391d58 QuartzCoreCABackingStoreUpdate_ + 196 frame #5: 0x00007fff2b4ce665 QuartzCore
___ZN2CA5Layer8display_Ev_block_invoke + 53
frame #6: 0x00007fff2b4c5616 QuartzCore-[CALayer _display] + 2026 frame #7: 0x00007fff2b4d7d72 QuartzCore
CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 520
frame #8: 0x00007fff2b420c04 QuartzCoreCA::Context::commit_transaction(CA::Transaction*, double) + 324 frame #9: 0x00007fff2b4545ef QuartzCore
CA::Transaction::commit() + 649
frame #10: 0x00007fff2b454f81 QuartzCoreCA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 79 frame #11: 0x00007fff23da0127 CoreFoundation
CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 23
frame #12: 0x00007fff23d9abde CoreFoundation__CFRunLoopDoObservers + 430 frame #13: 0x00007fff23d9b12a CoreFoundation
__CFRunLoopRun + 1226
frame #14: 0x00007fff23d9a944 CoreFoundationCFRunLoopRunSpecific + 404 frame #15: 0x00007fff38ba6c1a GraphicsServices
GSEventRunModal + 139
frame #16: 0x00007fff48c8b9ec UIKitCoreUIApplicationMain + 1605 frame #17: 0x00000001040ce77a OCDemo
main(argc=1, argv=0x00007ffeebb30d28) at main.m:18:12
frame #18: 0x00007fff51a231fd libdyld.dylibstart + 1 frame #19: 0x00007fff51a231fd libdyld.dylib
start + 1
复制代码这一次我们发现主线程的 RunLoop 通过一个Observer触发了CA::Transaction::observer_callback。
我们知道 __CFRunLoopDoObservers 的API申明如下:
static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity)
复制代码第三个参数为CFRunLoopActivity类型:
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0),
kCFRunLoopBeforeTimers = (1UL << 1),
kCFRunLoopBeforeSources = (1UL << 2),
kCFRunLoopBeforeWaiting = (1UL << 5),
kCFRunLoopAfterWaiting = (1UL << 6),
kCFRunLoopExit = (1UL << 7),
kCFRunLoopAllActivities = 0x0FFFFFFFU
};
复制代码我们打印一下第三个参数:
(lldb) po $arg3
32
复制代码正好是我们的kCFRunLoopBeforeWaiting事件。
下面我们打印主线程的 RunLoop 并搜索 observer_callback 可以看到:
(lldb) po [NSRunLoop mainRunLoop]
…
// activities = 0xa0 kCFRunLoopBeforeWaiting | kCFRunLoopExit
4 : <CFRunLoopObserver 0x600000e1c3c0 [0x7fff8062d610]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2000000, callout = _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv (0x7fff2b454f32), context = <CFRunLoopObserver context 0x0>}
…
复制代码我们可以看到主线程的 RunLoop 即将进入休眠的时候触发了这个观察者。
有些同学对于主线程的 RunLoop 在触发这个观察者之后,界面的渲染事件有疑问:
这时触发的渲染,是在当前轮次,还是下一轮RunLoop进行显示。
其实 BeforeWaiting 指的是,提交到这一轮 RunLoop 的事务都做完了,要进入休眠了。可以理解为每一轮 RunLoop 的 completion callback ,可以开始进行新一轮的事务提交了。而监听到 BeforeWaiting 的Observer会调用 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv ,进行下一次的事务的准备和提交。
_ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv()
QuartzCore:CA::Transaction::observer_callback:
CA::Transaction::commit();
CA::Context::commit_transaction();
CA::Layer::layout_and_display_if_needed();
CA::Layer::layout_if_needed();
[CALayer layoutSublayers];
[UIView layoutSubviews];
CA::Layer::display_if_needed();
[CALayer display];
[UIView drawRect];
复制代码即,下一轮的RunLoop才会刷新界面 。
1.3 情况3
我们点击按钮之后,也会更改视图的背景色:
- frame #0: 0x00000001040cde64 OCDemo
- (void)buttonPressed
{
self.view.backgroundColor = [UIColor redColor];
}
复制代码我们知道,点击按钮会触发主线程的 RunLoop 的 source1 执行 __IOHIDEventSystemClientQueueCallback ,唤醒下一轮 RunLoop 。
(lldb) bt
- thread #1, queue = ‘com.apple.main-thread’, stop reason = breakpoint 1.1
- frame #0: 0x0000000108105e64 OCDemo
-[TestView drawRect:](self=0x00007fdeaa51d430, _cmd="drawRect:", rect=(origin = (x = 0, y = 0), size = (width = 375, height = 812))) at ViewController.m:19:5 frame #1: 0x00007fff491928ae UIKitCore
-[UIView(CALayerDelegate) drawLayer:inContext:] + 632
frame #2: 0x000000010a254941 UIKit-[UIViewAccessibility drawLayer:inContext:] + 74 frame #3: 0x00007fff2b4c5ca4 QuartzCore
-[CALayer drawInContext:] + 286
frame #4: 0x00007fff2b391d58 QuartzCoreCABackingStoreUpdate_ + 196 frame #5: 0x00007fff2b4ce665 QuartzCore
___ZN2CA5Layer8display_Ev_block_invoke + 53
frame #6: 0x00007fff2b4c5616 QuartzCore-[CALayer _display] + 2026 frame #7: 0x00007fff2b4d7d72 QuartzCore
CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 520
frame #8: 0x00007fff2b420c04 QuartzCoreCA::Context::commit_transaction(CA::Transaction*, double) + 324 frame #9: 0x00007fff2b4545ef QuartzCore
CA::Transaction::commit() + 649
frame #10: 0x00007fff48c84fc8 UIKitCore_UIApplicationFlushRunLoopCATransactionIfTooLate + 104 frame #11: 0x00007fff48d32ab0 UIKitCore
__handleEventQueueInternal + 7506
frame #12: 0x00007fff48d28fb9 UIKitCore__handleHIDEventFetcherDrain + 88 frame #13: 0x00007fff23da0d31 CoreFoundation
CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
frame #14: 0x00007fff23da0c5c CoreFoundation__CFRunLoopDoSource0 + 76 frame #15: 0x00007fff23da0434 CoreFoundation
__CFRunLoopDoSources0 + 180
frame #16: 0x00007fff23d9b02e CoreFoundation__CFRunLoopRun + 974 frame #17: 0x00007fff23d9a944 CoreFoundation
CFRunLoopRunSpecific + 404
frame #18: 0x00007fff38ba6c1a GraphicsServicesGSEventRunModal + 139 frame #19: 0x00007fff48c8b9ec UIKitCore
UIApplicationMain + 1605
frame #20: 0x000000010810677a OCDemomain(argc=1, argv=0x00007ffee7af8d28) at main.m:18:12 frame #21: 0x00007fff51a231fd libdyld.dylib
start + 1
frame #22: 0x00007fff51a231fd libdyld.dylibstart + 1 复制代码进入断点之后,我们发现唤醒 下一轮RunLoop 之后由 source0 执行 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION 回调,进而触发 QuartzCore
CA::Transaction::commit() 方法。
- frame #0: 0x0000000108105e64 OCDemo
Source1在处理任务的时候,有时会跟Source0一起配合,把一些任务分发给Source0去执行。例如刚刚提到的点击事件,先由Source1处理硬件事件,之后Source1将事件包装分发给Source0继续进行处理。
本文地址:https://blog.csdn.net/weixin_48342209/article/details/107133641
推荐阅读
-
acd fotoangelo 2.0是什么软件?怎么利用FotoAngelo制作个性化屏保
-
bricscad v17怎么破解?BricsCAD V17.2.08安装激活及运行图文详细教程
-
pycharm 2017注册码怎么用?pycharm2017注册码获取及激活方法介绍
-
ANSYS SpaceClaim 2018怎么安装?SpaceClaim 2018安装破解版详细图文教程
-
百度hi聊天软件怎么切换语言?百度hi app进行中英文模式转换的方法介绍
-
caxa2016电子图板怎么破解?caxa cad电子图板2016安装及破解详细图文教程
-
win10系统总是天猫精选/聚划算软件该怎么办?
-
CATIA 2019怎么破解?CATIA Composer R2019安装+中文破解详细教程
-
会声会影x9没有出现在软件界面的遮罩该怎么使用?
-
世界最难破译的十大密码 第十个连本人都忘了怎么破解