[iOS 13] Access to ivar is prohibited

In iOS 13, we can not use KVC(valueForKey:, setValue:forKey:) to access some private APIs, it causes the crash of UISearchBar (QMUI), UINavigationBar (QMUI) and UITabBar (QMUI).

以下记录 iOS 13 系统禁止通过 KVC 访问的几种实现方式:

UITextField

UITextField *textField = [UITextFieldnew];[textFieldvalueForKey:@"_placeholderLabel"];

系统的 UITextField 重写了 valueForKey: 拦截了外部的取值,实现如下:

@implementationUITextField- (id)valueForKey:(NSString*)key{if([keyisEqualToString:@"_placeholderLabel"]) {        [NSExceptionraise:NSGenericExceptionformat:@"Access to UITextField's _placeholderLabel ivar is prohibited. This is an application bug"];    }    [supervalueForKey:key];}@end

简单解决:

去掉下划线即可 [textField valueForKey:@"placeholderLabel"];

UISearchBar

UISearchBar *bar = [UISearchBarnew];[barsetValue:@"test"forKey:@"_cancelButtonText"]UIView *searchField = [barvalueForKey:@"_searchField"];

根据 KVC 的实现,会先去找名为 set_cancelButtonText 的方法,所以系统内部重写了这个方法,什么事都不干,专门用来拦截 KVC,实现如下:

- (void)set_cancelButtonText:(NSString*)text {    [NSExceptionraise:NSGenericExceptionformat:@"Access to UISearchBar's set_cancelButtonText: ivar is prohibited. This is an application bug"];    [self_setCancelButtonText];}

拦截 _searchField:

- (void)_searchField {    [NSExceptionraise:NSGenericExceptionformat:@"Access to UISearchBar's _searchField ivar is prohibited. This is an application bug"];    [selfsearchField];}

简单解决:

直接调用 _setCancelButtonText, searchField

根据上面提到的原理,这里提供一种全局绕过这个禁止的方法供参考。

请注意:这只是一种临时的参考方案,我们 不推荐 开发者这么做, 因为访问私有属性会带来了不确定和不稳定性,少了苹果的警告会让你无节制去访问使用各种属性,随着系统的升级这私有属性会面临改动和失效的风险。

@implementationNSException(DisableUIKVCAccessProhibited)+ (void)load{staticdispatch_once_tonceToken;dispatch_once(&onceToken, ^{MethodoriginalMethod =class_getClassMethod(self,@selector(raise:format:));MethodswizzlingMethod =class_getClassMethod(self,@selector(sw_raise:format:));method_exchangeImplementations(originalMethod, swizzlingMethod);            });}+ (void)sw_raise:(NSExceptionName)raiseformat:(NSString*)format, ... {if(raise==NSGenericException&& [formatisEqualToString:@"Access to%@'s%@ivar is prohibited. This is an application bug"]) {return;    }va_listargs;va_start(args, format);NSString*reason =  [[NSStringalloc]initWithFormat:formatarguments:args];    [selfsw_raise:raiseformat:reason];va_end(args);}@end

你可能感兴趣的:([iOS 13] Access to ivar is prohibited)