一.先放问题现象
-
会话列表,有编辑功能,无编辑状态是下图
image.png -
正常的编辑状态
image.png -
异常的编辑状态 ,编辑控件占据两行
image.png - 左动第1行时,编辑状态确在第8行显示 (以上问题大部分出现在列表超过一屏的情况下)。
二.凭借祖传的开发经验猜测问题所在
首先想到的是不是iOS11的 tableView 新方法的问题,或者是开发中使用有问题
// Swipe actions
// These methods supersede -editActionsForRowAtIndexPath: if implemented
// return nil to get the default swipe actions
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)) API_UNAVAILABLE(tvos);
项目中的代码
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0))
{
if (indexPath.row >= self.chatData.count)
return nil;
GZIMChatModel *chatModel = self.chatData[indexPath.row];
WS(weakSelf);
UIContextualAction *deleteAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"删除" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
[weakSelf p_deleteChat:chatModel completeHandler:completionHandler];
}];
UIContextualAction *topRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:(chatModel.chat.isTop?@"取消\n置顶":@"置顶") handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
[weakSelf p_changeTopStatusWithChat:chatModel completeHandler:completionHandler];
}];
UIContextualAction *disturbRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal title:(chatModel.chat.unreadCount?@"标为\n已读":@"标为\n未读") handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
[weakSelf p_changeDisturbStatusWithChat:chatModel completeHandler:completionHandler];
}];
disturbRowAction.backgroundColor = [UIColor lightGrayColor];
UISwipeActionsConfiguration *config;
if (chatModel.chat.chatType==GZIMChatType_Subscription) {
config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction]];
} else {
config = [UISwipeActionsConfiguration configurationWithActions:@[deleteAction,topRowAction,disturbRowAction]];
}
config.performsFirstActionWithFullSwipe = NO;
return config;
}
google查阅很多网上资料使用方式基本没有问题,而且网上也没有类似的问题出现
三、 分析项目多个版本以及最近业务逻辑
通过sourceTree代码回到上一个版本的tag位置,发现没有类似问题
基本能确定这是这一版本出现的问题
最后发现因为项目中最近加了 防止数组越界或者字典传nil 的代码混淆机制导致这个问题
@implementation NSMutableDictionary (NilSafe)
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
Class class = NSClassFromString(@"__NSDictionaryM");
[class exchangeInstanceMethod:@selector(setObject:forKey:) swizzleMethod:@selector(safeSetObject:forKey:)];
//问题出现在这个上
[class exchangeInstanceMethod:@selector(setObject:forKeyedSubscript:) swizzleMethod:@selector(safeSetObject:forKeyedSubscript:)];
[class exchangeInstanceMethod:@selector(removeObjectForKey:) swizzleMethod:@selector(safeRemoveObjectForKey:)];
});
}
- (void)safeSetObject:(id)anObject forKey:(id<NSCopying>)aKey {
if (!aKey || !anObject) {
XLOG_INFO(@"NSMutableDictionary setObjectForKey aKey or anObject is nil");
return;
}
[self safeSetObject:anObject forKey:aKey];
}
- (void)safeSetObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
if (!key || !obj) {
XLOG_INFO(@"NSMutableDictionary setObjectForKeyedSubscript aKey is: %@ or anObject is %@",key,obj);
return;
}
XLOG_INFO(@"NSMutableDictionary aKey is: %@ and anObject is:%@",key,obj);
[self safeSetObject:obj forKeyedSubscript:key];
}
- (void)safeRemoveObjectForKey:(id)aKey
{
if (!aKey) {
XLOG_INFO(@"NSMutableDictionary removeObjectForKey aKey is nil");
return;
}
return [self safeRemoveObjectForKey:aKey];
}
@end
左滑编辑时的 正常的日志
2018-07-03 18:25:19.121977+0800 GZIMClient[30512:2773379] [I][GZIM][NSObject+Swizzling.m, -[NSMutableDictionary(NilSafe) safeSetObject, 247][Info:NSMutableDictionary aKey is: <NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0} and anObject is:<UISwipeOccurrence: 0x6040002f4200>
左滑编辑时的 异常的日志
2018-07-03 18:25:20.076750+0800 GZIMClient[30512:2773379] [I][GZIM][NSObject+Swizzling.m, -[NSMutableDictionary(NilSafe) safeSetObject, 244][Info:NSMutableDictionary setObjectForKeyedSubscript aKey is: <NSIndexPath: 0xc000000000800016> {length = 2, path = 0 - 4} or anObject is (null)
说明iOS11之后 新编辑方法用到了 下边这个方法
- (void)setObject:(nullable ObjectType)obj forKeyedSubscript:(KeyType <NSCopying>)key API_AVAILABLE(macos(10.8), ios(6.0), watchos(2.0), tvos(9.0));
而我们又代码混淆了这个方法,导致了问题的出现,应该是混淆导致 UISwipeOccurrence没有传入,不能正确获取,导致错位
解决方法: 只能先注销到这段方法混淆
四、 疑问
不明白为什么会出现这种问题,应该是内部原理
网友评论