调整符合 UI_APPEARANCE_SELECTOR 的属性
Swizzling on properties that conform to UI_APPEARANCE_SELECTOR
我正在尝试调整 UIView 上的背景颜色 属性。
在调配之前,我执行以下操作:
@implementation UIView (Cat1)
+(void)load {
NSArray *selectors = @[
//Highliter swizzling
NSStringFromSelector(@selector(setBackgroundColor:)),
NSStringFromSelector(@selector(backgroundColor))
];
[[self appearance] setBackgroundColor:[UIColor redColor]];
for (NSString *name in selectors) {
SEL originalSelector = NSSelectorFromString(name);
SEL swizzledSelector = NSSelectorFromString([NSString stringWithFormat:@"swizzled_%@",name]);
Method originalMethod = class_getInstanceMethod(self, originalSelector);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
class_addMethod(self,
originalSelector,
class_getMethodImplementation(self, originalSelector),
method_getTypeEncoding(originalMethod));
class_addMethod(self,
swizzledSelector,
class_getMethodImplementation(self, swizzledSelector),
method_getTypeEncoding(swizzledMethod));
method_exchangeImplementations(originalMethod, swizzledMethod);
}
然后调用swizzled方法时,我除了调用原来的方法什么都不做:
-(void)swizzled_setBackgroundColor:(UIColor *)color {
[self iio_swizzled_setBackgroundColor:color];
}
然后,发生以下崩溃:2017-03-08 19:04:37.863 Develop-InsertViewer[69285:7916872] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Please file a radar on UIKit if you see this assertion.'
*** First throw call stack:
(
0 CoreFoundation 0x0000000108506e65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000107c7ddeb objc_exception_throw + 48
2 CoreFoundation 0x0000000108506cca +[NSException raise:format:arguments:] + 106
3 Foundation 0x00000001078ca5a2 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 169
4 UIKit 0x0000000106227b35 PushNextClassForSettingIMP + 469
5 UIKit 0x000000010622810a TaggingAppearanceObjectSetterIMP + 37
6 InsertFramework 0x00000001071332be -[UIView(Cat1) swizzled_setBackgroundColor:] + 62
7 UIKit 0x0000000105d78fca -[UILabel _commonInit] + 238
8 UIKit 0x0000000105d7913d -[UILabel initWithFrame:] + 94
9 UIKit 0x0000000105b9cc4e -[UIView init] + 62
10 0x0000000105533300 _TTOFCSo7UILabelcfT_S_ + 16
11 0x0000000105532e44 _TFCSo7UILabelCfT_S_ + 68
12 0x0000000105569be3 _TFC12InsertViewer21StarterViewControllercfT5coderCSo7NSCoder_GSqS0__ + 51
13 0x0000000105569d2d _TToFC12InsertViewer21StarterViewControllercfT5coderCSo7NSCoder_GSqS0__ + 45
14 UIKit 0x0000000105ecb7db -[UIClassSwapper initWithCoder:] + 241
15 UIKit 0x000000010609f822 UINibDecoderDecodeObjectForValue + 705
16 UIKit 0x000000010609f558 -[UINibDecoder decodeObjectForKey:] + 278
17 UIKit 0x0000000105ecb4b1 -[UIRuntimeConnection initWithCoder:] + 180
18 UIKit 0x000000010609f822 UINibDecoderDecodeObjectForValue + 705
19 UIKit 0x000000010609f9e3 UINibDecoderDecodeObjectForValue + 1154
20 UIKit 0x000000010609f558 -[UINibDecoder decodeObjectForKey:] + 278
21 UIKit 0x0000000105eca6c3 -[UINib instantiateWithOwner:options:] + 1255
22 UIKit 0x0000000106232c40 -[UIStoryboard instantiateViewControllerWithIdentifier:] + 181
23 UIKit 0x0000000106232d93 -[UIStoryboard instantiateInitialViewController] + 69
24 UIKit 0x0000000105b0dfa6 -[UIApplication _loadMainStoryboardFileNamed:bundle:] + 94
25 UIKit 0x0000000105b0e2d6 -[UIApplication _loadMainInterfaceFile] + 260
26 UIKit 0x0000000105b0cb54 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1390
27 UIKit 0x0000000105b09e7b -[UIApplication workspaceDidEndTransaction:] + 188
28 FrontBoardServices 0x000000010b41e754 -[FBSSerialQueue _performNext] + 192
29 FrontBoardServices 0x000000010b41eac2 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
30 CoreFoundation 0x0000000108432a31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
31 CoreFoundation 0x000000010842895c __CFRunLoopDoSources0 + 556
32 CoreFoundation 0x0000000108427e13 __CFRunLoopRun + 867
33 CoreFoundation 0x0000000108427828 CFRunLoopRunSpecific + 488
34 UIKit 0x0000000105b097cd -[UIApplication _run] + 402
35 UIKit 0x0000000105b0e610 UIApplicationMain + 171
36 Develop-InsertViewer 0x00000001055ae752 main + 114
37 libdyld.dylib 0x00000001095a192d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
如果我在其他 class 上进行 [self appearance],也会发生这种情况,例如 UIToolBar
有什么想法吗??
appea运行ce 系统将所有属性瓶颈到单个实现 TaggingAppearanceObjectSetterIMP
。该实现检查选择器的名称(使用 _UIAppearanceTagObjectForSelector
)并在关联的对象缓存中查找(存储在 __UIAppearanceCustomizedSelectorsAssociationKey
中)。如果它不存在,它会调用 _TagForSelectorWithAxes
找出映射到该选择器的内容,并更新缓存。
你用你自己的运行时技巧踩到了一个相当复杂的运行时技巧的中间。爆炸并不令人震惊.... :D
基本问题至少是方法的名称必须是 setBackgroundColor
,而不是 swizzled_setBackgroundColor
。您可以通过调配实际的实现函数而不是方法来稍微解决这个问题。您可以查看 NSNotificationCenter+RNSwizzle.m
以获取手动执行此操作的示例。
如果在解决该问题后,您仍然 运行 遇到其他细微问题,我不会感到惊讶。我的建议是(好吧,我的建议是 "never swizzle production code, it's way too fragile," 但如果你忽略了那个建议......)拉出 Hopper 中的 appea运行ce 代码并跟踪实现,这样你就可以确保一切都排成一行。 并不复杂,Hopper 的伪代码模式几乎可以向您展示正在发生的事情(我花了大约 2 分钟才弄明白我在这里发布的内容)。也就是说,这是一个非常棘手的实现细节,它很容易在没有警告的情况下更改(导致新的崩溃)。如果你可以在不调配的情况下做到这一点,我强烈推荐。
我正在尝试调整 UIView 上的背景颜色 属性。
在调配之前,我执行以下操作:
@implementation UIView (Cat1)
+(void)load {
NSArray *selectors = @[
//Highliter swizzling
NSStringFromSelector(@selector(setBackgroundColor:)),
NSStringFromSelector(@selector(backgroundColor))
];
[[self appearance] setBackgroundColor:[UIColor redColor]];
for (NSString *name in selectors) {
SEL originalSelector = NSSelectorFromString(name);
SEL swizzledSelector = NSSelectorFromString([NSString stringWithFormat:@"swizzled_%@",name]);
Method originalMethod = class_getInstanceMethod(self, originalSelector);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
class_addMethod(self,
originalSelector,
class_getMethodImplementation(self, originalSelector),
method_getTypeEncoding(originalMethod));
class_addMethod(self,
swizzledSelector,
class_getMethodImplementation(self, swizzledSelector),
method_getTypeEncoding(swizzledMethod));
method_exchangeImplementations(originalMethod, swizzledMethod);
}
然后调用swizzled方法时,我除了调用原来的方法什么都不做:
-(void)swizzled_setBackgroundColor:(UIColor *)color {
[self iio_swizzled_setBackgroundColor:color];
}
然后,发生以下崩溃:2017-03-08 19:04:37.863 Develop-InsertViewer[69285:7916872] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Please file a radar on UIKit if you see this assertion.'
*** First throw call stack:
(
0 CoreFoundation 0x0000000108506e65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000107c7ddeb objc_exception_throw + 48
2 CoreFoundation 0x0000000108506cca +[NSException raise:format:arguments:] + 106
3 Foundation 0x00000001078ca5a2 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 169
4 UIKit 0x0000000106227b35 PushNextClassForSettingIMP + 469
5 UIKit 0x000000010622810a TaggingAppearanceObjectSetterIMP + 37
6 InsertFramework 0x00000001071332be -[UIView(Cat1) swizzled_setBackgroundColor:] + 62
7 UIKit 0x0000000105d78fca -[UILabel _commonInit] + 238
8 UIKit 0x0000000105d7913d -[UILabel initWithFrame:] + 94
9 UIKit 0x0000000105b9cc4e -[UIView init] + 62
10 0x0000000105533300 _TTOFCSo7UILabelcfT_S_ + 16
11 0x0000000105532e44 _TFCSo7UILabelCfT_S_ + 68
12 0x0000000105569be3 _TFC12InsertViewer21StarterViewControllercfT5coderCSo7NSCoder_GSqS0__ + 51
13 0x0000000105569d2d _TToFC12InsertViewer21StarterViewControllercfT5coderCSo7NSCoder_GSqS0__ + 45
14 UIKit 0x0000000105ecb7db -[UIClassSwapper initWithCoder:] + 241
15 UIKit 0x000000010609f822 UINibDecoderDecodeObjectForValue + 705
16 UIKit 0x000000010609f558 -[UINibDecoder decodeObjectForKey:] + 278
17 UIKit 0x0000000105ecb4b1 -[UIRuntimeConnection initWithCoder:] + 180
18 UIKit 0x000000010609f822 UINibDecoderDecodeObjectForValue + 705
19 UIKit 0x000000010609f9e3 UINibDecoderDecodeObjectForValue + 1154
20 UIKit 0x000000010609f558 -[UINibDecoder decodeObjectForKey:] + 278
21 UIKit 0x0000000105eca6c3 -[UINib instantiateWithOwner:options:] + 1255
22 UIKit 0x0000000106232c40 -[UIStoryboard instantiateViewControllerWithIdentifier:] + 181
23 UIKit 0x0000000106232d93 -[UIStoryboard instantiateInitialViewController] + 69
24 UIKit 0x0000000105b0dfa6 -[UIApplication _loadMainStoryboardFileNamed:bundle:] + 94
25 UIKit 0x0000000105b0e2d6 -[UIApplication _loadMainInterfaceFile] + 260
26 UIKit 0x0000000105b0cb54 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1390
27 UIKit 0x0000000105b09e7b -[UIApplication workspaceDidEndTransaction:] + 188
28 FrontBoardServices 0x000000010b41e754 -[FBSSerialQueue _performNext] + 192
29 FrontBoardServices 0x000000010b41eac2 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
30 CoreFoundation 0x0000000108432a31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
31 CoreFoundation 0x000000010842895c __CFRunLoopDoSources0 + 556
32 CoreFoundation 0x0000000108427e13 __CFRunLoopRun + 867
33 CoreFoundation 0x0000000108427828 CFRunLoopRunSpecific + 488
34 UIKit 0x0000000105b097cd -[UIApplication _run] + 402
35 UIKit 0x0000000105b0e610 UIApplicationMain + 171
36 Develop-InsertViewer 0x00000001055ae752 main + 114
37 libdyld.dylib 0x00000001095a192d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
如果我在其他 class 上进行 [self appearance],也会发生这种情况,例如 UIToolBar
有什么想法吗??
appea运行ce 系统将所有属性瓶颈到单个实现 TaggingAppearanceObjectSetterIMP
。该实现检查选择器的名称(使用 _UIAppearanceTagObjectForSelector
)并在关联的对象缓存中查找(存储在 __UIAppearanceCustomizedSelectorsAssociationKey
中)。如果它不存在,它会调用 _TagForSelectorWithAxes
找出映射到该选择器的内容,并更新缓存。
你用你自己的运行时技巧踩到了一个相当复杂的运行时技巧的中间。爆炸并不令人震惊.... :D
基本问题至少是方法的名称必须是 setBackgroundColor
,而不是 swizzled_setBackgroundColor
。您可以通过调配实际的实现函数而不是方法来稍微解决这个问题。您可以查看 NSNotificationCenter+RNSwizzle.m
以获取手动执行此操作的示例。
如果在解决该问题后,您仍然 运行 遇到其他细微问题,我不会感到惊讶。我的建议是(好吧,我的建议是 "never swizzle production code, it's way too fragile," 但如果你忽略了那个建议......)拉出 Hopper 中的 appea运行ce 代码并跟踪实现,这样你就可以确保一切都排成一行。 并不复杂,Hopper 的伪代码模式几乎可以向您展示正在发生的事情(我花了大约 2 分钟才弄明白我在这里发布的内容)。也就是说,这是一个非常棘手的实现细节,它很容易在没有警告的情况下更改(导致新的崩溃)。如果你可以在不调配的情况下做到这一点,我强烈推荐。