登入狀態的判定與處理(優化版)
背景:前幾天,寫了一個登入狀態的判定與處理,感覺寫得不是很簡潔,而且處理不好很容易出現多次持有,造成登入控制器不能釋放的問題。於是在上班的間隙重新寫了一個,作為“優化版”。
工具
#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