评论

收藏

[其他] iOS14适配【解决UITableViewCell兼容问题(往cell添加子视图的方式不规范)】

网络安全 网络安全 发布于:2021-07-01 19:36 | 阅读数:278 | 评论:0

  文章目录

  •   前言
  •   I、问题分析


    •   1.0 其他分析视图层级的方法:私有API _printHierarchy 和recursiveDescription
    •   1.1 注意事项

  •   II、使用方法交换,全局修改


    •   2.2.1 cell.subviews
    •   2.2.2 通过superview 获取cell的也需做相关修改
    •   2.1 全局修改
    •   2.2 注意事项

    •   2.3 使用到的工具类

  •   see also
前言  今天升级最新IDE Xcode,准备适配iOS14 API,结果发现app首页的cell中按钮也无法点击了。
I、问题分析  iOS14 UITableViewCell的子试图不能点击或者滑动等手势响应问题,发现有问题的cell基本都是直接
cell.addSubView(tempView1)

  •  

  这种方式添加的,通过Xcode自带的DebugViewHierarchy视图分析发现问题的原因是:被系统自带的UITableViewCellContentView遮挡在底部了
DSC0000.png

DSC0001.png

  所以需要改规范的做法
cell.contentView.addSubView(tempView1)

  •  

  温馨提示:如果你用旧版的Xcode打包,而非使用Xcode12以上版本编译打包的话,是不会有问题。一旦你使用了Xcode12打包,就会出现此问题。(但是苹果迟早会限制高于Xcode12才可以上传appstore,所以一旦使用了不规范的代码,早晚都要面临这个问题)

1.0 其他分析视图层级的方法:私有API _printHierarchy 和recursiveDescription
  关于视图层级分析你也可以使用私有API _printHierarchy和recursiveDescription 在lldb 窗口进行分析:
  例如先打印VC层级(lldb) po [[[UIWindow keyWindow] rootViewController] _printHierarchy]
  再使用目标View的地址进行recursiveDescription打印子视图的层级。

  •   po [0x10ff5e5e0 recursiveDescription]
(lldb) po [0x10ff5e5e0 recursiveDescription]<UITableViewCell: 0x10ff5e5e0; frame = (0 767.5; 375 120); hidden = YES; autoresize = W; layer = <CAGradientLayer: 0x280b80860>>| <_UISystemBackgroundView: 0x10fe2d170; frame = (0 0; 375 120); layer = <CAGradientLayer: 0x280c58500>; configuration = <UIBackgroundConfiguration: 0x283aa54a0; Base Style = List Grouped Cell; backgroundColor = <UIDynamicSystemColor: 0x2818d3140; name = tableCellGroupedBackgroundColor>>>|  | <UIView: 0x10fe2d310; frame = (0 0; 375 120); clipsToBounds = YES; layer = <CAGradientLayer: 0x280c58640>>| <UIView: 0x10ff9a820; frame = (0 0; 375 120); layer = <CAGradientLayer: 0x280b9db60>>|  | <UIButton: 0x10ff9ab10; frame = (17 0; 170.5 60); opaque = NO; layer = <CAGradientLayer: 0x280b9dc40>>|  |  | <UIImageView: 0x10fe70710; frame = (0 16; 28 28); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280be9520>>|  |  | <UIButtonLabel: 0x10ff9af70; frame = (38 21.5; 86 17); text = '商户交易汇总'; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b9dc80>>|  | <UIButton: 0x10ff9bd40; frame = (187.5 0; 170.5 60); opaque = NO; tag = 1; layer = <CAGradientLayer: 0x280b9e1c0>>|  |  | <UIImageView: 0x10ffacfd0; frame = (0 16; 28 28); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b93220>>|  |  | <UIButtonLabel: 0x10ff9c1a0; frame = (38 21.5; 100 17); text = '代理商交易汇总'; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b9e340>>|  | <UIButton: 0x10ff9cda0; frame = (17 60; 170.5 60); opaque = NO; tag = 2; layer = <CAGradientLayer: 0x280b9e540>>|  |  | <UIImageView: 0x10ffab1f0; frame = (0 16; 28 28); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b92f40>>|  |  | <UIButtonLabel: 0x10ff9d200; frame = (38 21.5; 86 17); text = '终端激活汇总'; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b9e680>>|  | <UIButton: 0x10ff9db20; frame = (187.5 60; 170.5 60); opaque = NO; tag = 3; layer = <CAGradientLayer: 0x280b9ea20>>|  |  | <UIImageView: 0x10ffa95d0; frame = (0 16; 28 28); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b92ce0>>|  |  | <UIButtonLabel: 0x10ff9df80; frame = (38 21.5; 86 17); text = '商户终端汇总'; opaque = NO; userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b9eb80>>|  | <UIView: 0x10ff9e8a0; frame = (15 60; 345 0.5); layer = <CAGradientLayer: 0x280b9ef00>>|  | <UIView: 0x10ff9ea10; frame = (15 120; 345 0.5); layer = <CAGradientLayer: 0x280b9f0c0>>| <UITableViewCellContentView: 0x10ffaafa0; frame = (0 0; 375 120); gestureRecognizers = <NSArray: 0x281fc73c0>; layer = <CAGradientLayer: 0x280b808e0>>|  | <UIImageView: 0x110f07d00; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CAGradientLayer: 0x280b7e220>>

  •  


1.1 注意事项
  因为此问题涉及的是添加子视图cell.addSubView,因此与之对应的方法(UITableViewCell *)[SubView superview] 和cell.subviews 都要注意谨慎使用和处理
II、使用方法交换,全局修改  如果错误代码比较多,可以采用hook,进行便捷的方法进行修改。
  例如125个文件的1452个地方使用错误的方法,这个如果不使用hook高质工作量有点大 DSC0002.png
所以通过Runtime hook cell的addSubView 方法强制修改为正确的添加cell 子视图的方式

2.1 全局修改

  •   只允许添加 UITableViewCellContentView,其余都直接添加到self.contentView
////  UITableViewCell+CRMaddSubView.m//  Housekeeper////  Created by mac on 2020/9/18.//  Copyright © 2020 QCT. All rights reserved.//#import "UITableViewCell+CRMaddSubView.h"@implementation UITableViewCell (CRMaddSubView)+ (void)load {// Swizzle addSubView[UITableViewCell sensorsdata_swizzleMethod:@selector(addSubview:) withMethod:@selector(kunnan_addSubview:)];}- (void)kunnan_addSubview:(UIView *)view {if  ([view isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]) {//允许 addSubView UITableViewCellContentView [self kunnan_addSubview:view];//实现方法,因为已经进行了 swizzle,相当于调用原来的方法} else {[self.contentView addSubview:view];}}@end

  •  


2.2 注意事项
  因为此问题涉及的是添加子视图cell.addSubView,因此与之对应的方法(UITableViewCell *)[SubView superview] 和cell.subviews 都要注意谨慎使用和处理
  具体例子如下2.2.1 和2.2.2
2.2.1 cell.subviews
  因为这是针对全局的,所以测试的覆盖面也要广。比如获取子视图采用cell.subviews 也要记得修改为 cell.contentView.subviews.
UIButton * btn = cell.contentView.subviews[2-1];


2.2.2 通过superview 获取cell的也需做相关修改

  •   经过全局hook之后,以下的代码就是错误的
    (UITableViewCell *)[textField superview]
  •   全局搜索进行修改
    DSC0003.png
UITableViewCell * myCell = (UITableViewCell *)[textField superview].superview;

  •  

  所以使用class的时候,最好写得健壮性强点,进行类型判断,避免一旦类型错误,就会找不到对应的方法,发送闪退
UIView * textFieldsuperview = [textField superview];  UITableViewCell * myCell = nil;if([textFieldsuperview isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]){     myCell= (UITableViewCell *)[textFieldsuperview superview];}else{return;}

  •  
  •  


  
关注下面的标签,发现更多相似文章