前言
對于IM頁面開發(fā)中,經(jīng)常會碰到跳轉到一個UINavigationController的子控制器棧堆中已經(jīng)存在的ViewController的情況沸移。
出現(xiàn)步驟:
eg1- ab ab 循環(huán)
- 進入IM聊天,
- 點擊頭像吭露,
- 點擊聊天哎甲,
eg2- abc abc循環(huán)
- 進入IM聊天博脑,
- 點擊右上角進入設置,
- 點擊頭像或者搜索聊天記錄屁倔,
- 點擊聊天
這種情況其實微信中也處理的不是特別好:群聊中點擊某個人脑又,發(fā)起聊天后,會退回root,然后再push到與這個人的會話中问麸。
一般我們會認為相同的對象才會沒有存在的價值往衷,而和某人的P2P聊天與之前的Team聊天是完全不同的內(nèi)容。假如是我還想與群內(nèi)別人交涉严卖,就要重新找到這個群再進行額外頻繁操作了席舍。
基于這個設想,我認為減少出現(xiàn)相同控制器的過程哮笆,應該對控制器的唯一屬性也進行一個確認相同操作来颤。
實現(xiàn)思路
- 跳轉前對需要去冗的ViewController設置待判斷的key-values,
- 對UINavigationController的pushViewController:animated:進行方法替換:跳轉前發(fā)現(xiàn)棧堆中有相同Class時疟呐,對兩個ViewController的key-values對應確認脚曾。
- 如果key-values相同,則用方法popToViewController:animated:跳轉回到已經(jīng)存在的ViewController启具,否則就進行正常push操作本讥。
實現(xiàn)代碼
1. UIViewController 分類
添加操作方法和對比屬性,不設置的界面則不受影響鲁冯。
@interface UIViewController (SameControllerInStack)
@property (nonatomic, strong) NSDictionary * sameConfirmPropertys;
- (void)gobackIfAlreadyInStackConfirmBy:(NSDictionary *)propertys;
@end
const void *const kSameConfirmPropertys = &kSameConfirmPropertys;
@implementation UIViewController (SameControllerInStack)
- (NSDictionary *)sameConfirmPropertys {
return objc_getAssociatedObject(self, &kSameConfirmPropertys);
}
- (void)setSameConfirmPropertys:(NSDictionary *)sameConfirmPropertys {
objc_setAssociatedObject(self, kSameConfirmPropertys, sameConfirmPropertys, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)gobackIfAlreadyInStackConfirmBy:(NSDictionary *)propertys {
self.sameConfirmPropertys = propertys;
}
@end
2. UINavigationController 分類
push方法替換拷沸,在方法中進行同屬性控制器的判斷
@interface UINavigationController (SameControllerInStack)
@end
@implementation UINavigationController (SameControllerInStack)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
@autoreleasepool {
[self swizzleMethod:@selector(pushViewController:animated:) swizzledSelector:@selector(swizzle_pushViewController:animated:)];
}
});
}
- (void)swizzle_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
NSDictionary * confirmPropertys = viewController.sameConfirmPropertys;
BOOL isSame;
if (confirmPropertys.count) {
for (UIViewController * vc in self.viewControllers) {
if ([vc isKindOfClass:viewController.class]) {
BOOL isSame = [self samePropertyOfVC1:vc VC2:viewController propertys:confirmPropertys];
if (isSame) {
[self popToViewController:vc animated:animated];
return;
}
}
}
}
[self swizzle_pushViewController:viewController animated:animated];
}
- (BOOL)samePropertyOfVC1:(id)vc1 VC2:(id)vc2 propertys:(NSDictionary *)propertys {
for (NSString * property in propertys) {
id object1 = [vc1 valueForKey:property];
id object2 = [vc2 valueForKey:property];
if (![object1 isEqual:object2]) {
return NO;
}
}
return YES;
}
3. NSObject 分類
進行方法替換需要的簡化方法
@interface NSObject (SwizzleMethod)
- (void)swizzleMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector;
@end
@implementation NSObject (SwizzleMethod)
- (void)swizzleMethod:(SEL)originalSelector swizzledSelector:(SEL)swizzledSelector {
Class class = [self class];
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
@end
實例參考
添加后在個人名片頁面(個人信息),搜索聊天記錄等可能出現(xiàn)重復界面的操作時薯演,
點擊聊天.png
根據(jù)業(yè)務需要撞芍,加上一句gobackIfAlreadyInStackConfirmBy:就可以了。
IM_Session_MessageVC *vc = [[IM_Session_MessageVC alloc] initWithSessionId:self.userId sessionType:0];
[vc gobackIfAlreadyInStackConfirmBy:@{@"sessionId" : self.userId,
@"sessionType" : @(0), // P2P
}];
[self.navigationController pushViewController:vc animated:YES];
PS
本文只是個人見解跨扮,如果發(fā)現(xiàn)有問題或者有更好方案的話序无,請不吝賜教,共同學習進步衡创。
qq:12087014
email: xingjl@outlook.com