原文地址前端
題外話:
此篇文章以一個iOS新手的角度解釋一款新聞類iOS APP誕生的過程,詳細介紹在這過程當中碰到的問題和個人解決思路。歡迎你們指正。android
菜單界面:git
主界面:github
詳細頁面:web
關於咱們頁面:數據庫
具體項目背景跳過,咱們着重看如何實現一款新聞類APP。安全
在開始項目計劃前,我下載了大量的新聞類APP進行研究,不管是android仍是iOS,充斥着大量的此類APP,好比網易新聞,一點諮詢,新浪微博(暫歸位新聞類),知乎,知乎日報等,而後我從零開始點開每一個應用,思考它的流程以及佈局和要點。發現核心不外乎如下兩點:服務器
但是咱們的應用不可能就這個樣子,須要有不一樣的新聞模塊,因此又有如下幾點:網絡
固然,有了APP後咱們的客戶端從哪請求數據呢?因而有了如下問題:架構
OK,暫先咱們只想到這,至於優化本地存儲和用戶友好展現等,咱們後面會涉及到。
一開始咱們只是個想法,即使想了不少,依然仍是覺的不踏實,沒有清晰的項目概念,因此我把項目的草圖畫了下來,以下:
這下內心踏實多了,起碼知道本身想讓它長個什麼樣子了。
ok,草圖已經有了,那想必你們已經知道我選用了流行的側邊欄(抽屜導航)佈局。你們都知道蓋一棟大樓最重要的是先把整棟大樓的骨架先搭起來,一樣一個APP首先要作的是把本身的架構搭起來,而這就是咱們的佈局。
iOS有着衆多開源的項目,這是我之前就知道的(PS:這些都是經驗才能獲得的,你能夠經過看書,看博客,瀏覽官網,與大牛交流等各類渠道獲取這些信息),而對於相似咱們這種側邊欄的佈局,開源界有着衆多的解決方案,我選用了SWRevealViewController **這套開源庫,地址是:
https://github.com/John-Lluch/SWRevealViewController (fork: **440 star: 1660)
經過內部的示例,相信你們很快就能搭建好項目的基本骨架。這裏有一個另外的小源碼,但願對你掌握這塊開源框架提供幫助。附連接:http://mexiqq.qiniudn.com/VReaderSidebarDemo.zip
案例效果:
核心頁面是一個主頁面和一個詳細頁面:
OK,核心界面有了(PS:我這裏使用的是Xcode的storboard構建頁面,不使用舊式的xib)
效果以下:
終於到了這個移動開發人員頭疼的問題了,因爲項目須要,咱們必須有能夠提供數據的接口,對於前端移動開發人員來講若是能夠本身構建後臺無疑減小了大量的溝通問題,然而人的精力有限,沒法同時兼顧,咋麼辦?
OK,如今這個問題獲得了不錯的解決,愈來愈多的雲服務開始出現,小編今天給你們推薦一款移動端後臺開發平臺Bomb(固然同類型的很多,不如facebook的Parse,不過國內你們都懂的),它提供了一套後臺開發所使用的SDK,方便的爲你的前端產品搭建後臺,適合中小企業或者獨立開發者使用。
附官方連接:http://www.bmob.cn/
附個人推薦連接:
http://www.mexiqq.com/2014/09/09/Bomb%E4%BA%91%E6%9C%8D%E5%8A%A1%E4%BB%8B%E7%BB%8D%E6%8A%95%E7%A5%A8/
給出個人平臺數據庫圖片:
如圖所示個人雲端數據庫有7個表,User是用戶的註冊表,由Bomb自動幫咱們創建,由於咱們是簡單的新聞資訊類APP,因此未使用。接下來有四個module表,分別對應我新聞內容的四個模塊(我添加了title,publishTime,content三個字段)。GameScore暫時未用。Question用於用戶提交問題反饋的表(我添加了Question 和 Reply兩個字段)。
OK,對於一個簡單的新聞諮詢類APP這個後臺我想已經足夠了。
雖然這裏用不着,但我說些題外話,在iOS開發中,對於web service的訪問是重中之重,主要涉及如下三個方面:
上面的看起來對於初學者有些恐怖,不過好消息是Bomb提供了封裝好的SDK,使用自帶的BombQuery去查詢數據庫。現面給出個人一個例子:
(PS:在使用以前記得將應用祕鑰加入項目,方法見Bomb官網)
//請求數據 BmobQuery *bquery = [BmobQuery queryWithClassName:module]; [bquery selectKeys:@[@"title",@"publishTime"]]; [bquery setLimit:15]; [bquery orderByDescending:@"createdAt"]; [bquery findObjectsInBackgroundWithBlock:^(NSArray *array, NSError *error) { if(!error){ local = false;(步驟1) myarray = array;(步驟2) [NSThread detachNewThreadSelector:@selector(saveContent:) toTarget:self withObject:array];(步驟3) [self performSelector:@selector(reloadData) withObject:nil afterDelay:0];(步驟4) }else{ [self.refreshControl endRefreshing]; UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"友情提示" message:@"沒法獲取數據,請檢查網絡(☆_☆)" delegate:self cancelButtonTitle:@"關閉" otherButtonTitles:nil, nil]; [alertView show]; } }];
上述例子查詢了數據庫的15條例子,採用異步訪問的方式返回數據。發生錯誤時給出提示,若是成功,會有四步操做:
後面會詳細涉及到數據持久話操做,在這裏咱們沒必要細究。
OK,咱們使用Bomb本身提供的查詢方法訪問Bomb服務,成功的將應用與服務器鏈接起來。
這是我訪問數據後展現新聞列表的頁面:
OK,其實咱們幾乎不涉及業務邏輯,由於咱們只是把最新的新聞數據展現給用戶看,不過仍然有一些邏輯須要咱們注意:
解決方案:
示例代碼:
self.refreshControl = [[UIRefreshControl alloc] init]; self.refreshControl.backgroundColor = [UIColor lightGrayColor]; self.refreshControl.tintColor = [UIColor whiteColor]; [self.refreshControl addTarget:self action:@selector(getLatestLoans) forControlEvents:UIControlEventValueChanged];
效果圖案:
(PS:以上代碼和示例只是用於展現,不推薦直接使用,建議先找幾篇文章系統學習如下)
在這裏我推薦兩篇教程,很簡明的講述了Core Data的基本使用,附連接:
http://www.appcoda.com/introduction-to-core-data/
http://www.appcoda.com/core-data-tutorial-update-delete/
再給出我處理保存動做時執行的代碼:
- (IBAction)saveNews:(id)sender { NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"CollectionNews"]; NSPredicate *predicate = [NSPredicate predicateWithFormat: @"newsTitle == %@",titleName]; [fetchRequest setPredicate:predicate]; NSArray *news = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy]; if (news.count == 0) { NSManagedObject *newRecentlyNews = [NSEntityDescription insertNewObjectForEntityForName:@"CollectionNews" inManagedObjectContext:managedObjectContext]; [newRecentlyNews setValue:titleName forKey:@"newsTitle"]; [newRecentlyNews setValue:publishTime forKey:@"newsPublishTime"]; [newRecentlyNews setValue:newsContent.text forKey:@"newsContent"]; //[newRecentlyNews setValue:[obj objectForKey:@"playerName"] forKey:@"newsContent"]; NSError *error = nil; if (![managedObjectContext save:&error]) { UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"友情提示" message:@"發生意外(☆_☆)" delegate:self cancelButtonTitle:@"關閉" otherButtonTitles:nil, nil]; [alertView show]; }else{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"友情提示" message:@"保存成功Y(^_^)Y" delegate:self cancelButtonTitle:@"關閉" otherButtonTitles:nil, nil]; [alertView show]; } }else{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"友情提示" message:@"重複保存哦,親(☆_☆)" delegate:self cancelButtonTitle:@"關閉" otherButtonTitles:nil, nil]; [alertView show]; } }
首先查詢表中有無重複的信息,若是有提示重複保存,若是沒有則新建一個NSManageObject保存信息。
效果圖:
- 使用Bomb提供的服務提交問題到Question表
Bomb不只給我提供了查詢的API,一樣提供了增刪改查一整套API,因此咱們能使用Bomb提供的服務將用戶的問題進行提交,給出個人代碼和運行效果:
- (IBAction)submitQuestion:(id)sender { if(![_myQuestion.text isEqualToString:@"在此輸入:"]){ BmobObject *gameScore = [BmobObject objectWithClassName:@"Questions"]; [gameScore setObject:_myQuestion.text forKey:@"question"]; [gameScore saveInBackgroundWithResultBlock:^(BOOL isSuccessful, NSError *error) { //進行操做 if(error ==nil){ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"友情提示" message:@"提交成功Y(^_^)Y" delegate:self cancelButtonTitle:@"關閉" otherButtonTitles:nil, nil]; [alertView show]; }else{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"友情提示" message:@"提交失敗,請檢查網絡(☆_☆)" delegate:self cancelButtonTitle:@"關閉" otherButtonTitles:nil, nil]; [alertView show]; } }]; }else{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"友情提示" message:@"請輸入有效文字(☆_☆)" delegate:self cancelButtonTitle:@"關閉" otherButtonTitles:nil, nil]; [alertView show]; } }
咱們本着主要功能去優化用戶的體驗,我想到如下兩點,其實也是最基本的兩點:
好伐,以上兩點應該是咱們應用中用戶體驗感最強的兩點,下面給出個人解決思路:
對於須要用戶等待的時間段內我會展現一個旋轉的進度條,告訴用戶我在加載數據,這個進度條可使用iOS 提供的UIActivityIndicatorView類,只須要經過如下三行代碼便可改善用戶體驗:
[myprogress setHidesWhenStopped:YES];//設置進度條中止時隱藏 [myprogress startAnimating];//設置進度條開始旋轉 [myprogress stopAnimating];//設置進度條中止旋轉
只須要在加載前設置進度條開始旋轉,異步加載完數據後設置進度條中止旋轉便可。
代碼以下:
-(BOOL)isLocalData{ //NSLog(@"titlename%@",titleName); NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:myEntimty]; NSPredicate *predicate = [NSPredicate predicateWithFormat: @"newsTitle == %@",titleName]; [fetchRequest setPredicate:predicate]; NSArray *news = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy]; if(news.count > 0) { NSManagedObject *entiy = [news objectAtIndex:0]; if(![entiy valueForKey:@"newsContent"]){ return false; }else{ [newsContent setText:[entiy valueForKey:@"newsContent"]]; [self changeFrameSizeOfTextView]; return true; } } return false; }
上述代碼在用戶進入詳細頁面後執行,檢測本地是否已經擁有此條新聞內容,若是已經存在,則從本地獲取,若不存在,則遠程獲取數據。(PS:因爲我本地最多存取15條新聞,每次刷新時會清空原先的數據,因此直接經過新聞標題查取,不推薦)
OK,通過以上七步,基本已經搭建起一個簡單的新聞類APP了,可是咱們的應用會不會太單調了呢?咱們能夠給本身的應用增長一些額外的模塊,具體選擇什麼要視本身的狀況。這裏由於是給學校作了一個就業信息發佈的APP,因此添加了校車查詢,地圖顯示的富類模塊。
https://github.com/mexiQQ/VReader-iOS.git
歡迎各位大牛們指點一二 Y(^_^)Y