随着iOS 13的发布,公司的项目也势必要着手适配了。现汇总一下iOS 13的各种坑
这次iOS 13系统升级,影响范围最广的应属KVC访问修改私有属性了,直接禁止开发者获取或直接设置私有属性。而KVC的初衷是允许开发者通过Key名直接访问修改对象的属性值,为其中最典型的 UITextField 的 _placeholderLabel、UISearchBar 的 _searchField。
造成影响:在iOS 13下App闪退
错误代码:
// placeholderLabel私有属性访问 [textField setValue:[UIColor redColor] forKeyPath:@"_placeholderLabel.textColor"]; [textField setValue:[UIFont boldSystemFontOfSize:16] forKeyPath:@"_placeholderLabel.font"]; // searchField私有属性访问 UISearchBar *searchBar = [[UISearchBar alloc] init]; UITextField *searchTextField = [searchBar valueForKey:@"_searchField"];
解决方案:
使用 NSMutableAttributedString 富文本来替代KVC访问 UITextField 的 _placeholderLabel
textField.attributedPlaceholder = [[NSAttributedString alloc] initWithString:@"placeholder" attributes:@{NSForegroundColorAttributeName: [UIColor darkGrayColor], NSFontAttributeName: [UIFont systemFontOfSize:13]}];
因此,可以为UITextFeild创建Category,专门用于处理修改placeHolder属性提供方法
#import "UITextField+ChangePlaceholder.h" @implementation UITextField (Change) - (void)setPlaceholderFont:(UIFont *)font { [self setPlaceholderColor:nil font:font]; } - (void)setPlaceholderColor:(UIColor *)color { [self setPlaceholderColor:color font:nil]; } - (void)setPlaceholderColor:(nullable UIColor *)color font:(nullable UIFont *)font { if ([self checkPlaceholderEmpty]) { return; } NSMutableAttributedString *placeholderAttriString = [[NSMutableAttributedString alloc] initWithString:self.placeholder]; if (color) { [placeholderAttriString addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, self.placeholder.length)]; } if (font) { [placeholderAttriString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, self.placeholder.length)]; } [self setAttributedPlaceholder:placeholderAttriString]; } - (BOOL)checkPlaceholderEmpty { return (self.placeholder == nil) || ([[self.placeholder stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] length] == 0); }
关于 UISearchBar,可遍历其所有子视图,找到指定的 UITextField 类型的子视图,再根据上述 UITextField 的通过富文本方法修改属性。
#import "UISearchBar+ChangePrivateTextFieldSubview.h" @implementation UISearchBar (ChangePrivateTextFieldSubview) /// 修改SearchBar系统自带的TextField - (void)changeSearchTextFieldWithCompletionBlock:(void(^)(UITextField *textField))completionBlock { if (!completionBlock) { return; } UITextField *textField = [self findTextFieldWithView:self]; if (textField) { completionBlock(textField); } } /// 递归遍历UISearchBar的子视图,找到UITextField - (UITextField *)findTextFieldWithView:(UIView *)view { for (UIView *subview in view.subviews) { if ([subview isKindOfClass:[UITextField class]]) { return (UITextField *)subview; }else if (subview.subviews.count > 0) { return [self findTextFieldWithView:subview]; } } return nil; } @end