背景:前几天,写了一个登录状态的判定与处理,感觉写得不是很简洁,而且处理不好很容易出现多次持有,造成登录控制器不能释放的问题。于是在上班的间隙重新写了一个,作为“优化版”。
工具
#import <UIKit/UIKit.h>
@interface UIViewController (LoginStatus)
/**
适用于:
跳转前需要检查登录状态,并且处于登录状态或登录成功后由`自己`处理的情况
说明:目前逻辑是当用户处于未登录状态,但点击了需要登录才能跳转的页面时,会先跳转到登录页面;
如果登录不成功会停留在登录页面,用户可以点击“关闭”来返回当前页面,故只存在登录成功回调
*/
- (void)beforePushCheckLoginStatusWithSuccess:(void (^)(void))successBlock;
@end
#import "UIViewController+LoginStatus.h"
#import "MZAccountManager.h"
#import <objc/runtime.h>
/** 登录状态的判定依据 */
static NSString *const kToken = @"token";
/** 登录控制器的类名 */
static NSString *const kLoginVCClassName = @"LoginViewController";
@interface UIViewController ()
@property (nonatomic, copy) dispatch_block_t successBlock;
@end
@implementation UIViewController (LoginStatus)
- (void)beforePushCheckLoginStatusWithSuccess:(void (^)(void))successBlock {
self.successBlock = successBlock;
// 如果没有登录
if ([self isEmpty:MZUserManager.token] || [MZUserManager.token isEqualToString:@"##"]) {
UIViewController *loginVC = [[NSClassFromString(kLoginVCClassName) alloc] init];
if (loginVC) {
[MZUserManager addObserver:self forKeyPath:kToken options:NSKeyValueObservingOptionNew context:nil];
UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController:loginVC];
[self presentViewController:navVC animated:YES completion:nil];
}
} else {
!self.successBlock ?: self.successBlock();
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
if ([keyPath isEqualToString:kToken]) {
// 登录成功
if (![self isEmpty:change[NSKeyValueChangeNewKey]] && ![change[NSKeyValueChangeNewKey] isEqualToString:@"##"]) {
!self.successBlock ?: self.successBlock();
}
[MZUserManager removeObserver:self forKeyPath:kToken];
}
}
#pragma mark - Private Methods
- (BOOL)isEmpty:(NSString *)scrString {
return (scrString == nil || scrString.length == 0 || [scrString isKindOfClass:[NSNull class]]);
}
- (dispatch_block_t)successBlock {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setSuccessBlock:(dispatch_block_t)successBlock {
objc_setAssociatedObject(self, @selector(successBlock), successBlock, OBJC_ASSOCIATION_COPY);
}
@end
登录控制器的处理
#import "LoginViewController.h"
#import "MZAccountManager.h"
@interface LoginViewController ()
@end
@implementation LoginViewController
#pragma mark - Life Cycle
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"%@创建了&&token=%@", [self.class description], MZUserManager.token);
}
#pragma mark - Private Methods
// 点击登录按钮
- (IBAction)loginAction:(id)sender {
MZUserManager.token = @"点击登录,并且登录成功了";
[self dismissLoginVC];
}
// 点击关闭按钮
- (IBAction)closeAction:(id)sender {
MZUserManager.token = @"##";
[self dismissLoginVC];
}
- (void)dismissLoginVC {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)dealloc {
NSLog(@"%@释放了", self.class);
}
@end