为什么UIView的setFrame与UILabel的setFrame

时间:2017-05-15 09:59:43

标签: ios objective-c uiview thread-safety uilabel

为了检测后台线程上刷新UI的行为,我使用了第三方库ODUIThreadGuard。 这个lib基于钩子UIView的setNeedsLayout,setNeedsDisplay,setNeedsDisplayInRect选择器。 当我测试它时,我发现UILabel的setFrame:在后台线程上可以被检测到,但是UIView的不行。谁能告诉我为什么?

代码:

// ViewController.m
[self.view addSubview:self.testLabel];
[self.view addSubview:self.testView];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    self.testLabel.frame = CGRectMake(20, 20, 100, 100);
});

将检测到上述代码,但以下代码不会被检测到。

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    self.testView.frame = CGRectMake(20, 20, 100, 100);
});

钩码:

@implementation UIView (ThreadSafeGuard)

+ (void)load {
    [DBHookUtil swizzlingInClass:[self class] originalSelector:@selector(setNeedsLayout) swizzledSelector:@selector(db_setNeedsLayout)];
    [DBHookUtil swizzlingInClass:[self class] originalSelector:@selector(setNeedsDisplay) swizzledSelector:@selector(db_setNeedsDisplay)];
    [DBHookUtil swizzlingInClass:[self class] originalSelector:@selector(setNeedsDisplayInRect:) swizzledSelector:@selector(db_setNeedsDisplayInRect:)];
}

- (void)db_setNeedsLayout {
    NSAssert([NSThread isMainThread], @"refresh UI on background thread");
    [self db_setNeedsLayout];
}

- (void)db_setNeedsDisplay {
    NSAssert([NSThread isMainThread], @"refresh UI on background thread");
    [self db_setNeedsDisplay];
}

- (void)db_setNeedsDisplayInRect:(CGRect)rect {
    NSAssert([NSThread isMainThread], @"refresh UI on background thread");
    [self db_setNeedsDisplayInRect:rect];
}

@end

崩溃日志:

    2017-05-15 18:17:40.876 ThreadSafeGuardDemo[50800:19659410] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'refresh UI on background thread'
*** First throw call stack:
(
    0   CoreFoundation                      0x0000000105181b0b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x0000000104be6141 objc_exception_throw + 48
    2   CoreFoundation                      0x0000000105185cf2 +[NSException raise:format:arguments:] + 98
    3   Foundation                          0x00000001047803b6 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 193
    4   ThreadSafeGuardDemo                 0x0000000104615068 -[UIView(ThreadSafeGuard) db_setNeedsDisplay] + 264
    5   UIKit                               0x00000001058311f6 -[UILabel setNeedsDisplay] + 55
    6   UIKit                               0x00000001058279e6 -[UILabel _invalidateAsNeededForNewSize:oldSize:withLinkCheck:] + 336
    7   UIKit                               0x0000000105827c9f -[UILabel setFrame:] + 76
    8   ThreadSafeGuardDemo                 0x0000000104614a76 __29-[ViewController viewDidLoad]_block_invoke + 278
    9   libdispatch.dylib                   0x0000000107f744a6 _dispatch_call_block_and_release + 12
    10  libdispatch.dylib                   0x0000000107f9d05c _dispatch_client_callout + 8
    11  libdispatch.dylib                   0x0000000107f7f198 _dispatch_root_queue_drain + 1358
    12  libdispatch.dylib                   0x0000000107f7ebef _dispatch_worker_thread3 + 123
    13  libsystem_pthread.dylib             0x00000001083c3746 _pthread_wqthread + 1299
    14  libsystem_pthread.dylib             0x00000001083c3221 start_wqthread + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException

0 个答案:

没有答案