「iOS」行車服務(wù)app 「客戶端、后端思路+代碼」

  • 最近開發(fā)了一個行車服務(wù)項目,iOS客戶端采用Objective-C編寫, 后端采用PHP搭建,部署在阿里云,操作系統(tǒng)為Linux CentOS 7.3,數(shù)據(jù)庫MySQL,服務(wù)器為Apache,是比較基礎(chǔ)的LAMP組合。
  • iOS端代碼部分我會講述整體的開發(fā)思路,一些有意思的功能點也會詳細說說。
  • 后端代碼比較簡單,想要自己嘗試開發(fā)API的iOS開發(fā)者可以參考。
  • 發(fā)這篇文的主要目的是對最近的開發(fā)做一個整體回顧,同時希望對有需要的同學提供到一些幫助,有很多不盡合理和完善的地方,也請求各位同學不吝賜教,感謝大家!

首先上整體的效果圖:


show.gif

在POI檢索結(jié)果頁面,地圖控件顯示為空白,是因為模擬器運行的原因,真機效果良好

這里是 iOS項目地址后端項目地址 。如果有幫助,希望點一下Star以示鼓勵,感謝~

這里是后端代碼簡析的文章后端代碼簡析

「Tips」:對于發(fā)現(xiàn)代碼運行報錯的同學,項目使用CocoaPods進行第三方庫的集成。之前為了方便我對Pods文件夾做了ignore操作。剛剛已經(jīng)更新,大家可以直接打開后綴為xcworkspace的項目文件運行。不過這樣Github上面的項目體積會比較大。

簡單介紹:項目UI整體盡量保持了餓了么的藍色風格,其中某些頁面參考了高德地圖餓了么Max+的設(shè)計風格。

項目功能點

  • 賬戶、用戶資料管理
  • 參照餓了么UI的定位、天氣模塊
  • 基于高德地圖API開發(fā)的POI檢索,同時界面也加入了一些和高德地圖app類似的特性
  • 自定義交互邏輯的預定及結(jié)果通知功能
  • 簡單參照Max+app的資訊模塊
  • 用戶歷史足跡、歷史事件維護

項目使用到的API及第三方庫

  • 高德地圖API
  • 和風天氣API
  • 自己搭建的后端相關(guān)接口
  • AFNetworking 3.0
  • SDWebImage
  • MBProgressHUD
  • 項目內(nèi)的Icon大量使用阿里巴巴的iconfont圖標,極力推薦

項目涉及的技術(shù)點

  • 高德地圖API的相關(guān)使用。包括地圖POI檢索導航等功能。
  • GCD的使用示例。包括耗時操作的后臺執(zhí)行、UI更新相關(guān)操作等。
  • NSUserDefaults維護賬戶信息。這里是為使用方便,僅供參考。
  • Core Animation的使用。由于TableView加載時采用HUD的用戶體驗不是很友善,我自己封裝了Loading頁面。

開發(fā)思路

  • 登錄注冊頁面

IMG_2008.PNG
  • 項目初始化時采用Tabbar VC作為rootController,如果此時沒有賬戶信息,則采用模態(tài)彈出方式彈出登錄頁面。

  • 這部分比較簡單,客戶端會先對用戶輸入的信息進行簡單的合法判斷,然后調(diào)用登錄接口。

  • 有一些關(guān)于TextField的點擊空白和Return回收鍵盤以及呼出鍵盤時控件移位防止遮擋的代碼可以注意一下。

  • Tabbar VC初始化時,第一個tab欄的VC會進行定位操作,如果此時為已登錄狀態(tài),則直接調(diào)用發(fā)送歷史足跡的接口。在未登錄狀態(tài)下,用戶點擊登錄按鈕,登錄成功時,會向第一個tab欄VC發(fā)送一個調(diào)用歷史足跡接口的通知

  • 主界面(tabbar欄首頁)

IMG_2009.PNG
IMG_2010.PNG
  • 地理位置和天氣部分。
    • 這部分是單獨封裝的View,UI參考了餓了么。地理位置和通知列表按鈕的點擊事件采用代理交由當前VC實現(xiàn)。
    • 由于模擬器定位獲取的坐標無法使用高德地圖的國內(nèi)API,我對運行環(huán)境做了一下判斷,如果是模擬器運行,則設(shè)置了默認坐標,對應(yīng)地點大概是北京市海淀區(qū)北京理工大學
    • 當前VC加載過程中,開啟定位,在地理位置反編碼的成功回調(diào)中調(diào)用天氣信息的接口。注意地理位置和天氣信息的UI更新放在主線程執(zhí)行。
    • 點擊地理位置的文字時,會模態(tài)彈出重新定位的界面,重新定位按鈕的點擊事件使用代理交由主界面VC實現(xiàn),避免在此界面再次實例化定位相關(guān)的對象。
  • 功能欄
    • 使用UICollectionView展示。各個CellIcon使用阿里巴巴的iconfont圖標,將以往的圖片素材轉(zhuǎn)為字體來使用,對于素材整理、高清保真、代碼方便來說有極大的效率提升。在Web移動客戶端開發(fā)領(lǐng)域已經(jīng)非常廣泛地在使用。
  • 某一功能VC
IMG_2011.PNG
  • 這部分UI參考了高德地圖附近界面UI以及部分特性。導航欄隱去,最上面是一個地圖控件,以及透明的返回按鈕。下面是POI信息的tableview。在tableview向下滑動時,地圖隱去,tableviewframe上移,導航欄出現(xiàn)。向上滑動到頂部時,tableview下移,地圖出現(xiàn),導航欄隱去。
  • tableview滑動時特性的實現(xiàn):通過scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate代理方法,判斷滑動的方向,從而對tableviewframe以及導航欄等元素進行操作。
    代碼如下:
//判斷滑動手勢方向,決定tableview的frame改變
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
  CGPoint translation = [scrollView.panGestureRecognizer translationInView:scrollView.superview];
  if (translation.y>0) {
      NSLog(@"ssssss");
      {
          NSIndexPath *dic = self.poiList.indexPathsForVisibleRows.firstObject;
          if (self.poiList.frame.origin.y == 64 && dic.row == 0){
              [UIView animateWithDuration:0.2 animations:^{
                  
                  NSLog(@"visible:::%@",dic);
                  showMap = YES;
                  self.navigationController.navigationBar.hidden = YES;
                  self.poiList.frame = listFrame;
              }];
          }
      }
  }else if(translation.y<0){
      NSLog(@"tttt");
      if (self.poiList.frame.origin.y == 300){
          [UIView animateWithDuration:0.2 animations:^{
              showMap = NO;
              self.navigationController.navigationBar.hidden = NO;
              self.poiList.frame = listFullFrame;
          }];
      }
  }
}
  • 在界面加載時,使用了自己封裝的loading頁面:

    IMG_2018.PNG

    • 在頁面view加載的最開始,將loading頁的view加入到當前VC的view中。在頁面數(shù)據(jù)加載完成的回調(diào)中,調(diào)用tableviewreload方法,而后將loading頁移除。
    • loading頁使用basicAnimation制作了簡單的呼吸動畫,keyPath為logo圖標的透明度。
  • 第一個cell的POI地點默認可預約,顯示預約圖標,點擊進入預約界面。

    IMG_2012.PNG

    • 這個部分的和后端的交互邏輯是自己定義的。一般的預約過程是預約請求發(fā)送成功后,一段時間內(nèi)由店家進行同意或拒絕操作,而后客戶端收到結(jié)果回執(zhí)。由于本項目簡單模擬此過程,均使用http協(xié)議進行通信。所以我的實現(xiàn)方式是后端收到預約請求后,直接采用隨機數(shù)方式模擬店家的接受或拒絕。一定時間后,客戶端調(diào)用結(jié)果查詢的接口來獲取預約結(jié)果。
    • 實現(xiàn)方式為,點擊預約按鈕,若預約接口調(diào)用成功,按鈕字樣變?yōu)?code>預約中,鐘表icon開始轉(zhuǎn)動,并且按鈕變?yōu)椴豢牲c擊狀態(tài)。與此同時,使用performSelector方式延時調(diào)用獲取預約結(jié)果的接口。在此網(wǎng)絡(luò)請求的成功回調(diào)中,向主界面發(fā)送通知,而后主界面通知按鈕右側(cè)顯示通知數(shù)量的紅色圖標。如圖。
    • 這里通知列表的數(shù)據(jù)是存在UserDefaults中的,不同設(shè)備之間無法同步。其中涉及到一些userDefaults中數(shù)據(jù)要求的知識,具體可以參考代碼。這里是因為需求是臨時想出,如果常規(guī)實現(xiàn)方式需要開發(fā)獲取通知數(shù)據(jù)的接口。我為了節(jié)省開發(fā)時間所以采用這種方式來模擬實現(xiàn)了。這個地方在以后可以完善~
      IMG_2013.PNG
  • 資訊Tab欄

IMG_2014.PNG
  • 這里沒有花費過多的精力。數(shù)據(jù)預置了網(wǎng)易新聞相關(guān)數(shù)據(jù)。界面UI參考了我常常使用的Max+iOS客戶端的資訊功能。第一個Cell以全圖為背景,可以用來突出顯示重點內(nèi)容。

  • 資訊詳情頁是一個簡單的webView。同樣使用了自己封裝的Loading圖。移除時機就簡單放在了webViewfinishLoad回調(diào)方法中。其實對于Webview真正加載完成時機的判斷還有很多可以聊的東西,日后補充。

  • 設(shè)置頁面

IMG_2015.PNG
  • 這個頁面顯而易見是采用兩個sectiontableview實現(xiàn)。在頁面的viewWillAppear方法中,需要調(diào)用獲取緩存數(shù)據(jù)大小的方法,單獨更新清除緩存cell的內(nèi)容。因為在每次切換tab的過程中,緩存數(shù)據(jù)都有可能發(fā)生變化。

  • 個人信息
    • 頁面依然采用tableview實現(xiàn)。在信息編輯頁面,仿照了微信信息更改頁面的邏輯。頁面出現(xiàn)時,立即彈出鍵盤。關(guān)于使textField在頁面加載完成時即成為第一響應(yīng)者的問題,需要重寫- (BOOL)becomeFirstResponder方法。代碼如下:
    - (BOOL)becomeFirstResponder
    

{
[super becomeFirstResponder];
return [self.textInput becomeFirstResponder];
}
```


IMG_2016.PNG
  • 歷史足跡、歷史預定、積分信息

IMG_2017.PNG

IMG_2019.PNG

- 這部分也依然使用了封裝的loading頁面。如果數(shù)據(jù)條目為空,則不顯示tableview,提示暫無相關(guān)信息,如圖。

  • 清除緩存
    • 這里其實只使用了SDImageCache的相關(guān)方法。我們還可以清除本app的緩存數(shù)據(jù)所在目錄來達到真正清除緩存的目的,日后討論。
    • 緩存數(shù)據(jù)獲取的初始單位是B,我們需要除以10241次、2次來判斷當前數(shù)據(jù)是在KB級別還是MB級別,并作正確顯示。
  • 退出登錄
    • 點擊此按鈕,清除userDefaults中相關(guān)數(shù)據(jù),然后模態(tài)彈出登錄頁面。
    • 這里可以注意的一點是,我們在模態(tài)彈出登陸頁,并且再次登錄之后,界面是在退出登錄之前的頁面的,也就是tab欄的第三個頁面。如果想要再次登錄之后,界面出現(xiàn)在tab欄的首頁,我們可以在模態(tài)彈出登錄頁的完成回調(diào)中,對當前tabVC的selected index進行設(shè)置。代碼如下:
    DELoginViewController *loginVC = [[DELoginViewController alloc] init];
            [self presentViewController:loginVC animated:YES completion:^{
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    // 耗時的操作
                    dispatch_async(dispatch_get_main_queue(), ^{
                        // 更新界面
                        AppDelegate * appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
                        appDelegate.tabbarVC.selectedIndex = 0;
                    });
                });
            }];
    

代碼的主要開發(fā)思路基本講述完,具體的細節(jié)大家可以和我繼續(xù)交流~項目中有許多不盡合理的實現(xiàn)方式,小部分是考慮到時間因素。歡迎大家進行討論、指教。
有相關(guān)的問題,歡迎大家進行留言。項目中使用的自有接口,部署在我的阿里云服務(wù)器中,可外網(wǎng)訪問。請求大家合理使用。

后端項目數(shù)據(jù)庫相關(guān)的sql代碼,我已上傳至后端項目

如果大家有興趣,以后我可以再講述一下server端的代碼,當然,后端我也是初學者的水平,僅供想要入門的同學參考。

我的個人博客網(wǎng)站地址: Halo的個人博客 ,歡迎大家訪問。

代碼已開源,地址在文章首部。如果點一下star,我真的會非常感謝~
halo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容