IOS開(kāi)發(fā)用戶(hù)登錄注冊(cè)模塊所遇到的問(wèn)題
最近和另外一位同事負(fù)責(zé)公司登錄和用戶(hù)中心模塊的開(kāi)發(fā)工作,開(kāi)發(fā)周期計(jì)劃兩周,減去和產(chǎn)品和接口的協(xié)調(diào)時(shí)間,再減去由于原型圖和接口的問(wèn)題,導(dǎo)致強(qiáng)迫癥糾結(jié)癥狀高發(fā),情緒不穩(wěn)定耗費(fèi)的時(shí)間,能在兩周基本完成也算是個(gè)不小的奇跡了。本文就總結(jié)一下如何滿(mǎn)足產(chǎn)品需要的情況下,高效開(kāi)發(fā)一個(gè)登錄注冊(cè)模塊。
1.利用繼承解決界面重復(fù)性功能。通常登錄注冊(cè)會(huì)有一個(gè)獨(dú)立的設(shè)計(jì),而模塊內(nèi)部會(huì)有有相似的背景,相似的導(dǎo)航欄樣式,相似返回和退出行為,相似的輸入框,按鈕樣式等。
比如上面的的注冊(cè)和登錄模塊,就有相同的返回按鈕,相同的背景,相同的導(dǎo)航欄樣式,甚至相同的按鈕和輸入框樣式。所以為了加快我們的開(kāi)發(fā),我們完全先定義一個(gè)父控制器,然后通過(guò)的繼承實(shí)現(xiàn)多態(tài),從而實(shí)現(xiàn)我們快速設(shè)計(jì)頁(yè)面和基本功能的實(shí)現(xiàn)。下圖是我的個(gè)人項(xiàng)目《丁丁印記》的登錄注冊(cè)模塊的目錄結(jié)構(gòu),其中HooEntryBaseViewController就定義了這個(gè)模塊通用的行為和樣式:
2.彈出鍵盤(pán)和退出鍵盤(pán)機(jī)制開(kāi)發(fā)。
這點(diǎn)使我們開(kāi)發(fā)者容易忽略的一點(diǎn),我也因?yàn)榭吹揭恍〢PP因?yàn)閺棾鲦I盤(pán)遮擋輸入,導(dǎo)致怒刪APP的行為。這模塊的設(shè)計(jì)就根據(jù)產(chǎn)品的設(shè)計(jì)來(lái)決定采用什么代碼實(shí)現(xiàn)我們的目的了。
•單擊空白區(qū)域退出鍵盤(pán)代碼:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(closeKeyboard:)]; tap.numberOfTapsRequired = 1; tap.numberOfTouchesRequired = 1; [self.view addGestureRecognizer:tap]; - (void)closeKeyboard:(id)sender { [self.view endEditing:YES]; }
•避免鍵盤(pán)遮擋,登錄表單或按鈕上移代碼:
- (void)textViewDidBeginEditing:(UITextField *)textView { CGRect frame = textView.frame; int offset = frame.origin.y + 120 - (self.view.frame.size.height - 216.0);//鍵盤(pán)高度216 NSTimeInterval animationDuration = 0.30f; [UIView beginAnimations:@"ResizeForKeyBoard" context:nil]; [UIView setAnimationDuration:animationDuration]; float width = self.view.frame.size.width; float height = self.view.frame.size.height; if(offset > 0) { CGRect rect = CGRectMake(0.0f, -offset,width,height); self.view.frame = rect; } [UIView commitAnimations]; }
3.接入第三方登錄,必須要判斷用戶(hù)是否安裝該第三方客戶(hù)端,否則蘋(píng)果可能審核無(wú)法通過(guò)。血的教訓(xùn)。
比如我的APP《丁丁印記》接入了QQ登錄功能,程序會(huì)客戶(hù)端是否安裝了QQ,如果未安裝則隱藏QQ登錄圖標(biāo)。
if (![QQApi isQQInstalled]) { self.QQLoginButton.hidden = YES; self.QQLoginLabel.hidden = YES; }
4.特殊情景處理。這容易是一個(gè)空白點(diǎn),通常年輕的開(kāi)發(fā)的者不會(huì)考慮到這一塊,而通常產(chǎn)品和UE也不太會(huì)記得定義清楚臨界點(diǎn)的行為。
• 加載狀態(tài)。當(dāng)用戶(hù)發(fā)起登錄或者注冊(cè)請(qǐng)求時(shí)需要給用戶(hù)友好的提示。
#pragma mark - 登錄按鈕點(diǎn)擊 - (IBAction)login:(UIButton *)sender { if([self.userNameTextField.text isEmpty] || [self.passwordTextField.text isEmpty]){ [SVProgressHUD showErrorWithStatus:@"用戶(hù)名或密碼不能為空"]; }else{ __weak typeof(self) weakSelf = self; [[HooUserManager manager] LoginWithUserName:self.userNameTextField.text andPassword:self.passwordTextField.text block:^(BmobUser *user, NSError *error) { __strong __typeof(weakSelf)strongSelf = weakSelf; if (error) { [SVProgressHUD showErrorWithStatus:@"登錄失敗"]; }else if(user){ [SVProgressHUD showSuccessWithStatus:@"登錄成功"]; [strongSelf loginSuccessDismiss]; } }]; } }
• 賬號(hào)或者密碼各種錯(cuò)誤判斷
NSString *emailStr; NSString *phoneStr; NSString *passwordStr = weakSelf.passwordView.inputTextField.text; emailStr = weakSelf.accountView.inputTextField.text; if (![NSString validateEmail:emailStr] || !emailStr.length) { [weakSelf showErrorTipViewWithMessage:@"郵箱格式錯(cuò)誤"]; return; } } else { phoneStr = weakSelf.accountView.inputTextField.text; if (phoneStr.length < 5) { [weakSelf showErrorTipViewWithMessage:@"手機(jī)長(zhǎng)度錯(cuò)誤")]; return; } if ([weakSelf.accountView.countryCode isEqualToString:@"+86"]) { if (![phoneStr isValidateMobileNumber]) { [weakSelf showErrorTipViewWithMessage:@"手機(jī)號(hào)碼格式錯(cuò)誤")]; return; } } } if (passwordStr.length < kPasswordMinLength) { [weakSelf showErrorTipViewWithMessage:ATLocalizedString(@"密碼長(zhǎng)度超過(guò)少于6個(gè)字符")]; return; } if (passwordStr.length > kPasswordMaxLength) { [weakSelf showErrorTipViewWithMessage:@"密碼長(zhǎng)度超過(guò)20個(gè)字符")]; return; }
5.手機(jī)找回密碼,發(fā)送驗(yàn)證碼按鈕的處理。這個(gè)行為也容易被產(chǎn)品忽略需要我們開(kāi)發(fā)者主動(dòng)想到,然后跟產(chǎn)品確定這個(gè)需求,然后確定按鈕的觸發(fā)后的行為,否則用戶(hù)可能多次點(diǎn)擊發(fā)送驗(yàn)證碼,這會(huì)造成服務(wù)器負(fù)擔(dān),并且可能返回給用戶(hù)多條短信,造成困擾。下面這段代碼可以實(shí)現(xiàn)單擊驗(yàn)證碼按鈕,然后倒計(jì)時(shí)2分鐘后恢復(fù)按鈕的可點(diǎn)擊狀態(tài)。
- (void)verifedCodeButtonWithTitle:(NSString *)title andNewTitle:(NSString *)newTitle { WS(weakSelf); __block int timeout = kTimeout; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue); dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); dispatch_source_set_event_handler(_timer, ^{ if(timeout<=0){ dispatch_source_cancel(_timer); dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf setTitle:title forState:UIControlStateNormal]; weakSelf.userInteractionEnabled = YES; }); }else{ int seconds = timeout; NSString *strTime = [NSString stringWithFormat:@"%.2d", seconds]; dispatch_async(dispatch_get_main_queue(), ^{ [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:1]; [weakSelf setTitle:[NSString stringWithFormat:@"%@(%@)",newTitle,strTime] forState:UIControlStateNormal]; [UIView commitAnimations]; weakSelf.userInteractionEnabled = NO; }); timeout--; } }); dispatch_resume(_timer); }
5.用戶(hù)登錄信息和狀態(tài)持久化。我們通常會(huì)有業(yè)務(wù)層處理登錄的數(shù)據(jù)的持久,并且使用單例,但是不能依賴(lài)單例記錄用狀態(tài),因?yàn)橛脩?hù)可能會(huì)退出,所以需要從沙盒去讀取用戶(hù)狀態(tài)的字段是否存在,如用戶(hù)的ID,或者AccessToken。
下面這段代碼,用來(lái)持久化用戶(hù)信息
-
(void)saveUserInfoWithData:(NSDictionary *)dict { NSString *userID = dict[kUserId]; NSString *email = dict[kEmail]; NSString *mobile = dict[kMobile]; [HooNSUserDefaultSerialzer setObject:memberID forKey:kUserID]; [HooNSUserDefaultSerialzer setObject:email forKey:kEmail]; [HooNSUserDefaultSerialzer setObject:mobile forKey:kMobile]; }
5.對(duì)外開(kāi)發(fā)用戶(hù)信息的接口。封裝我們的模塊。對(duì)外提供我們的接口,通常其他頁(yè)面需要判斷用戶(hù)是否登錄,也可能需要用戶(hù)的唯一標(biāo)示符來(lái)請(qǐng)求數(shù)據(jù)。這一塊如果我們做的混亂,則容易導(dǎo)致其他頁(yè)面獲取用戶(hù)信息的隨意性,比如給他們開(kāi)發(fā)了讀取沙盒里讀取用戶(hù)信息的字段。我們應(yīng)該在登錄模塊統(tǒng)一其他頁(yè)面獲取這些用戶(hù)信息的行為。
#import <Foundation/Foundation.h> #import "HooSingleton.h" @interface HooUserManager : NSObject @property (nonatomic, strong) NSString *userID; SingletonH(Manager) /** * Verify user if login or not * * @return if login in return YES ,otherwise return NO */ - (BOOL)isUserLogin; /** * login out */ - (void)loginOut; @end #import "HooUserManager.h" #import "HooNSUserDefaultSerialzer.h" static NSString * const kMobile = @"Mobile"; static NSString * const kEmail = @"Email"; static NSString * const kUserID = @"UserID"; @implementation HooUserManager SingletonM(Manager) #pragma mark - getter and setter - (NSString *)userID { NSString *userID = [HooNSUserDefaultSerialzer objectForKey:kUserID]; return userID; } - (BOOL)isUserLogin { NSString *userID = [HooNSUserDefaultSerialzer objectForKey:kUserID]; if (userID.length) { return YES; } return NO; } - (void)loginOut { [HooNSUserDefaultSerialzer removeObjectForKey:kMobile]; [HooNSUserDefaultSerialzer removeObjectForKey:kEmail]; [HooNSUserDefaultSerialzer removeObjectForKey:kUseID]; } @end
6.其他。
其實(shí)為了更好的用戶(hù)體驗(yàn),我們還會(huì)提供其他功能,如明文顯示密碼選擇按鈕、從服務(wù)器讀取郵箱格式提示、錯(cuò)誤字符糾正、當(dāng)然還有最重要的動(dòng)畫(huà)效果。
相關(guān)文章
iOS 頁(yè)面滑動(dòng)與標(biāo)題切換顏色漸變的聯(lián)動(dòng)效果實(shí)例
本篇文章主要介紹了iOS 頁(yè)面滑動(dòng)與標(biāo)題切換顏色漸變的聯(lián)動(dòng)效果實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-04-04iOS Xcode創(chuàng)建文件時(shí)自動(dòng)生成的注釋方法
下面小編就為大家分享一篇iOS Xcode創(chuàng)建文件時(shí)自動(dòng)生成的注釋方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01IOS UITableViewCell詳解及按鈕點(diǎn)擊事件處理實(shí)例
這篇文章主要介紹了IOS UITableViewCell詳解及按鈕點(diǎn)擊事件處理實(shí)例的相關(guān)資料,這里附有示例代碼,大家可以看下如何實(shí)現(xiàn)按鍵點(diǎn)擊事件,需要的朋友可以參考下2016-12-12iOS開(kāi)發(fā)底層探索界面優(yōu)化示例詳解
這篇文章主要為大家介紹了iOS開(kāi)發(fā)底層探索界面優(yōu)化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07查看iOS已上架App的Crash信息定位、應(yīng)對(duì)處理方式的實(shí)例
下面小編就為大家?guī)?lái)一篇查看iOS已上架App的Crash信息定位、應(yīng)對(duì)處理方式的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2017-12-12iOS中在APP內(nèi)加入AppStore評(píng)分功能的實(shí)現(xiàn)方法
這篇文章主要介紹了iOS中在APP內(nèi)加入AppStore評(píng)分功能的實(shí)現(xiàn)方法,文中筆者給大家整理了三種方式,大家可以根據(jù)自己的需求選擇,需要的朋友可以參考下2017-11-11簡(jiǎn)單好用的iOS導(dǎo)航欄封裝.runtime屬性控制實(shí)例代碼
這篇文章主要給大家介紹了簡(jiǎn)單好用的iOS導(dǎo)航欄封裝.runtime屬性控制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10IOS 開(kāi)發(fā)之Object-C中的對(duì)象詳解
這篇文章主要介紹了IOS 開(kāi)發(fā)之Object-C中的對(duì)象詳解的相關(guān)資料,需要的朋友可以參考下2017-06-06