microsoft / FluentDarkModeKit

A library for backporting Dark Mode in iOS
MIT License
1.63k stars 125 forks source link

Bug:objc_retain + 16 #87

Closed jueying-xiangfeng closed 4 years ago

jueying-xiangfeng commented 4 years ago

切换模式的时候遇到crash: 0 libobjc.A.dylib 0x0000000194dfc020 objc_retain + 16 1 UIKitCore 0x00000001995bfaf4 -[UIView+ 15215348 (Hierarchy) _setBackgroundColor:] + 316 2 FDBaseUI 0x000000010661b724 0x1065fc000 + 128804 3 FDADSDK 0x0000000109f75210 0x109f38000 + 250384 4 FDADSDK 0x0000000109f742b0 0x109f38000 + 246448 5 FDADSDK 0x0000000109f72c90 0x109f38000 + 240784 6 FDADSDK 0x0000000109f47a24 0x109f38000 + 64036 7 FDADSDK 0x0000000109fd6f38 0x109f38000 + 651064 8 FDADSDK 0x0000000109fd69e8 0x109f38000 + 649704 9 FDADSDK 0x0000000109fd99a8 0x109f38000 + 661928 10 FDADSDK 0x0000000109f441c0 0x109f38000 + 49600 11 FDADSDK 0x0000000109f43d68 0x109f38000 + 48488 12 FDADSDK 0x0000000109f43b1c 0x109f38000 + 47900 13 FDADSDK 0x0000000109f48a4c 0x109f38000 + 68172 14 FDADSDK 0x0000000109f6a0bc 0x109f38000 + 204988 15 libdispatch.dylib 0x0000000194d86610 _dispatch_call_block_and_release + 24 16 libdispatch.dylib 0x0000000194d87184 _dispatch_client_callout + 16 17 libdispatch.dylib 0x0000000194d39190 _dispatch_main_queue_callback_4CF$VARIANT$mp + 1044 18 CoreFoundation 0x00000001950385e4 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 12 19 CoreFoundation 0x00000001950335d8 __CFRunLoopRun + 2004 20 CoreFoundation 0x0000000195032adc CFRunLoopRunSpecific + 464 21 GraphicsServices 0x000000019efd3328 GSEventRunModal + 104 22 UIKitCore 0x000000019914063c UIApplicationMain + 1936 23 readerFree 0x0000000105378a88 main + 3771016 (main.m:14) 24 libdyld.dylib 0x0000000194ebc360 start + 4

都是挂在了:static void (dm_original_setBackgroundColor)(UIView , SEL, UIColor *); 看这样子是说当前要修改颜色的view已经销毁了,请问又遇到这种情况吗?

levinli303 commented 4 years ago

Hi here 👋, what version of FluentDarkModeKit are you using? Can you provide a sample project for us to look at?

jueying-xiangfeng commented 4 years ago

你好: 我使用的版本有点老,我们的项目是要适配皮肤,然后是在DarkModeKit基础上做的改动.

开始是 hook 的 UIViewsetBackgroundColor 方法。后来在使用 [[self appearance] setBackgroundColor:[UIColor redColor]]; 的时候会crash,根据旧版的 DarkModeKit 找到的解决方案是这样:

https://stackoverflow.com/questions/42677534/swizzling-on-properties-that-conform-to-ui-appearance-selector

Method method = class_getInstanceMethod(self, @selector(setBackgroundColor:)); dm_original_setBackgroundColor = (void *)method_getImplementation(method); method_setImplementation(method, (IMP)dm_setBackgroundColor);

static void dm_setBackgroundColor(UIView self, SEL _cmd, UIColor color) {

NSAssert([NSThread isMainThread], @"非主线程修改 UI");

if ([color isKindOfClass:DMDynamicColor.class]) {
    self.dm_dynamicBackgroundColor = (DMDynamicColor *)color;
} else {
    self.dm_dynamicBackgroundColor = nil;
}
dm_original_setBackgroundColor(self, _cmd, color);

}

然后就会有一定的概率出现上面遇到的crash。

现在用最新的版本 FluentDarkModeKit 的方法:

class_replaceMethod(self, selector, imp_implementationWithBlock(^(UIView self, UIColor backgroundColor) {

        if ([backgroundColor isKindOfClass:DMDynamicColor.class]) {
            self.dm_dynamicBackgroundColor = (DMDynamicColor *)backgroundColor;
        } else {
            self.dm_dynamicBackgroundColor = nil;
        }

        ((void (*)(UIView *, SEL, UIColor *))imp)(self, selector, backgroundColor);

    }), method_getTypeEncoding(method));

试验了之前会有 crash 的几个机型,没有再出现过crash。

请问下最新版本采用 imp_implementationWithBlock 的方式是基于什么考虑的呢,跟上面提到的 crash 有关系吗?

levinli303 commented 4 years ago

Interesting, the use of imp_implementationWithBlock was merely to avoid defining static C functions.

From #30 , we used the approach with C static function in swizzling "setBackgroundColor:" which should have avoided the problem with UIAppearance. @li-bei I recalled that you said that after that PR was merged, some crashes still persist?

jueying-xiangfeng commented 4 years ago

好的,谢谢,现在 hook 的时机已经在 APP 启动时就已经完成,目前没有再出现 crash 了。