iOS7 最佳實踐:一個天氣應用案例(上)

發表於2014-03-11

在這個兩部分的系列教程中,您將探索如何使用以下工具和技術來建立自己的App:

本教程專為熟悉基本知識的、但還沒有接觸到太多高階主題的中級開發者而設計。本教程也是想要去探索Objective-C函式程式設計一個很好的開始。

開始

開啟Xcode並執行File\New\Project。選擇Application\Empty Application。將專案命名為SimpleWeather,單擊下一步,選擇一個目錄去儲存你的專案,然後點選Create。 現在,你的基礎專案已經完成。下一步是整合你的第三方工具。但首先你要關閉Xcode,確保他不會影響下一步。

Cocoapods

你將要下載Cocoapods的程式碼,在Xcode專案中新增檔案來使用,並配置專案需要的設定。

Mantle

Mantle是由於Github團隊開發的,目的是去除Objective-C把JSON資料轉為NSObject子類的所有樣板程式碼。Mantle也能做資料轉換,通過一種神奇的方式把JSON原始資料(strings, ints, floats)轉換為複雜資料,比如NSDate, NSURL, 甚至是自定義類。

LBBlurredImage

LBBlurredImage是一個繼承自UIImageView,輕而易舉使影象模糊的專案。你將僅僅用一行程式碼來建立一個神奇的模糊效果。

TSMessages

TSMessages 是另一個非常簡單的庫,用來顯示浮層警告和通知。當出現錯誤資訊而不直接影響使用者的時候,最好使用浮層來代替模態視窗(例如UIAlertView),這樣你將盡可能減少對使用者的影響。

你將只用TSMessages,在網路失去連線或API錯誤的時候。如果發生錯誤,你將看到類似這樣的一個浮層:

TSefegfergrefgerMessage

ReactiveCocoa

最後,你將使用到ReactiveCocoa,他也來自於GitHub團隊。ReactiveCocoa給Objective-C帶來了函式程式設計,類似與.NET的Reactive Extensions。你將在第二部分花費大部分時間去實現ReactiveCocoa。

設定你的Cocoapods

設定你的Cocoapods,先要確保你已經安裝了Cocoapods。為此,開啟命令列程式,並輸入。

你將會看到類似這樣的輸出:

這決定於你如何管理Ruby gems,例如你使用rbenvRVM,路徑可能有所不同。

如果命令列簡單的返回提示,或顯示pod not found,表示Cocoapods未安裝在你的機器上。可以檢視我們的Cocoapods教程作為安裝說明。這也是一個很好的資源,如果你想更多得了解Cocoapods的話。

Podfiles是用來告訴Cocoapods哪些開源專案需要匯入。

要建立你的第一個Cocoapod,首先在命令列中用cd命令導航到你的XCode專案所在的資料夾,在命令列中啟動編輯器,輸入

這檔案做了兩件事情:

  • 告訴Cocoapods你的目標平臺與版本,這裡的你目標是iOS 7.0。
  • 列給Cocoapods一個專案所有需要引入和安裝的三方庫清單。

在命令列中輸入pod install進行安裝。

這可能需要花一到兩分鐘的時間去安裝各種包。你的命令列應該輸出如下所示:


Cocoapods會在你的專案目錄中建立一堆新檔案,但是,只有一個需要你關心,SimpleWeather.xcworkspace

用Xcode開啟SimpleWeather.xcworkspace。看看你的專案設定,現在有一個Pods專案在你的專案工作區,以及在Pods資料夾放著每一個你引入的庫,如下所示:

SimpleWeather-Cocoapods

SimprefregfleWeather-Project

確保你已經選擇SimpleWeather專案,如圖所示:

構建並執行您的App,以確保一切工作正常:

blfvvgregergank-app


建立你的主檢視控制器

雖然這個App看起來複雜,但它還會通過一個單一的View Controller完成。現在,你將新增他。

選中SimpleWeather專案,單擊File\New\File,並且選擇Cocoa Touch\Objective-C class. 命名為WXController,並設定為UIViewController的子類。

確保Targeted for iPadWith XIB for user interface都沒有選中,如下圖所示:

create-rtgregecontroller

開啟WXController.m然後用如下所示替換-viewDidLoad方法:

現在開啟AppDelegate.m,並且引入如下兩個class:

眼尖的讀者會注意到WXController使用引號引入,TSMessage使用單括號引入。

回頭看下當你建立Podfile的時候,你使用Cocoapods引入TSMessage。Cocoapods建立TSMessage專案,並把它加入到工作空間。既然你從工作區的其他專案匯入,可以使用尖括號代替引號。

代替-application:didFinishLaunchingWithOptions的內容:

標號註釋的解釋:

  1. 初始化並設定WXController例項作為App的根檢視控制器。通常這個控制器是一個的UINavigationControllerUITabBarController,但在當前情況下,你使用WXController的單個例項。
  2. 設定預設的檢視控制器來顯示你的TSMessages。這樣做,你將不再需要手動指定要使用的控制器來顯示警告。

構建並執行,看看你的新檢視控制器起作用了。

wxcontfvdvroller-red

在紅色背景下,狀態列有點不夠清晰。幸運的是,有一個簡單的方法,使狀態列更清晰易讀。

在iOS7,UIViewController有一個新的API,用來控制狀態列的外觀。開啟WXController,直接新增下面的程式碼到-viewDidLoad:方法下:

 

再次構建並執行,你將看到狀態列如下的變化:

wxcontroller-red-status1

設定你的App檢視

現在是時候讓你的App接近生活。下載這個專案的圖片,並解壓縮到一個合適的位置。這個壓縮包的背景圖片出自Flickr使用者idleformat之手,天氣圖片出自Dribbble使用者heeyeun之手。

切換回Xcode,單擊File\Add Files to “SimpleWeather”….定位到你剛剛解壓縮的圖片資料夾並選擇它。選擇Copy items into destination group’s folder (if needed),然後單擊Add

開啟WXController.h, 新增如下委託協議:

現在開啟WXController.m。 小提示:你可以使用Control-Command-Up的快捷鍵來實現.h.m檔案之間的快速切換。

新增如下程式碼到WXController.m頂部:

LBBlurredImage.h包含在Cocoapods引入的LBBlurredImage專案,你會使用這個庫來模糊背景圖片。

應該有一個空的私有介面樣板在WXController imports的下方。它具有以下屬性:

現在,是時候在專案中建立並設定檢視。

下面是你App的分解圖,記住,table view將是透明的:

scrervververveens

為了實現動態模糊效果,在你的App中,你會根據App的滾動來改變模糊影象的alpha值。

開啟WXController.m,使用如下程式碼來,替換掉-viewDidLoad中設定背景色的程式碼:

這是非常簡單的程式碼:

  1. 獲取並儲存螢幕高度。之後,你將在用分頁的方式來顯示所有天氣​​資料時,使用它。
  2. 建立一個靜態的背景圖,並新增到檢視上。
  3. 使用LBBlurredImage來建立一個模糊的背景影象,並設定alpha為0,使得開始backgroundImageView是可見的。
  4. 建立tableview來處理所有的資料呈現。 設定WXController為delegate和dataSource,以及滾動檢視的delegate。請注意,設定pagingEnabledYES

新增如下UITableView的delegate和dataSource的程式碼到WXController.m@implementation塊中:

  1. Pragma mark組織程式碼的很好的一種方式。
  2. 你的table view有兩個部分,一個是每小時的天氣預報,另一個用於每日播報。table view的section數目,設定為2。
  3. 天氣預報的cell是不可選擇的。給他們一個半透明的黑色背景和白色文字。

最後,新增如下程式碼到WXController.m:

WXController.m中,你的檢視控制器呼叫該方法來編排其子檢視。

構建並執行你的App,看看你的檢視如何堆疊。

backgrferfreferound

仔細看,你會看到所有空的table cell的cell分隔線。

仍然在-viewDidLoad中,新增下面的程式碼來設定你的佈局框架和邊距:

這是相當常規設定程式碼,但這裡是怎麼回事:

  1. 設定table的header大小與螢幕相同。你將利用的UITableView的分頁來分隔頁面頁頭和每日每時的天氣預報部分。
  2. 建立inset(或padding)變數,以便您的所有標籤均勻分佈並居中。
  3. 建立並初始化為各種檢視建立的高度變數。設定這些值作為常量,使得可以很容易地在需要的時候,配置和更改您的檢視設定。
  4. 使用常量和inset變數,為label和view建立框架。
  5. 複製圖示框,調整它,使文字具有一定的擴充套件空間,並將其移動到該圖示的右側。當我們把標籤新增到檢視,你會看到佈局的效果。

新增如下程式碼到-viewDidLoad

這是相當長的一塊程式碼,但它真的只是在做設定各種控制元件的繁重工作。簡單的說:

  1. 設定當前view為你的table header。
  2. 構建每一個顯示氣象資料的標籤。
  3. 新增一個天氣圖示的影象檢視。

構建並執行你的App,你應該可以看到你之前佈局的所有所有view。下面的螢幕截圖顯示了使用手工佈局的、所有標籤框在視覺上的顯示。

built-layfbberreou1t

用手指輕輕推動table,當你滾動它的時候,應該會反彈。

獲取氣象資料

你會注意到,App顯示“Loading…”,但它不是真正地在工作。是時候獲取一些真正的天氣資料。

你會從OpenWeatherMap的API拉取資料。 OpenWeatherMap是一個非常棒的服務,旨在提供實時,準確,免費的天氣資料給任何人。雖然有很多天氣API,但他們大多要麼使用較舊的資料格式,如XML,或是有償服務 – 並且有時還相當昂貴。

你會遵循以下基本步驟,來獲你裝置的位置的氣象資料:

  1. 找到裝置的位置
  2. API端下載JSON資料
  3. 對映JSON到WXConditionsWXDailyForecasts
  4. 告訴UI有新資料了

開始建立你的天氣模型和資料管理類。單擊File\New\File…並選擇Cocoa Touch\Objective-C class。命名為WXClient並使其為NSObject的子類。

這樣再做三次建立以下類:

  • WXManager作為NSObject的子類
  • WXCondition作為MTLModel的子類
  • WXDailyForecast作為WXCondition的子類

全部完成?現在,你可以開始下一節,其中涉及對映和轉換您的天氣資料。

建立你的天氣模型

你的模型將使用Mantle,這使得資料對映和轉型非常簡單。

開啟WXCondition.h如下列程式碼,修改介面:

  1. MTLJSONSerializing協議告訴Mantle序列化該物件如何從JSON對映到Objective-C的屬性。
  2. 這些都是你的天氣資料的屬性。你將會使用這些屬性的get set方法,但是當你要擴充套件App,這是一種很好的方法來訪問資料。
  3. 這是一個簡單的輔助方法,從天氣狀況對映到影象檔案。

構建並執行App。失敗了……

原因是你沒有從你的Cocoapods專案中引入Mantle。解決方法是,在WXCondition.h中,你需要把MTLModel.h替換為#import <Mantle.h>

現在構建並執行App。成功了。你會看到一些新的警告,但你可以忽略他們。

首先,你需要處理未實現的-imageName方法。

開啟WXCondition.m,新增如下方法:

  1. 建立一個靜態的NSDictionary,因為WXCondition的每個例項都將使用相同的資料對映。
  2. 天氣狀況與影象檔案的關係(例如“01d”代表“weather-clear.png”)。
  3. 宣告獲取影象檔名的公有方法。

看一看從OpenWeatherMap返回的JSON響應資料:

 

你需要把巢狀的JSON值對映到Objective-C的屬性。巢狀的JSON值是元素,如溫度,即上面看到的main節點。

要做到這一點,你將利用的Objective-C的Key-Value Coding和Mantle的MTLJSONAdapter

還在WXCondition.m,通過新增+JSONKeyPathsByPropertyKey方法,“JSON到模型屬性”的對映,且該方法是MTLJSONSerializing協議的require

在這個方法裡,dictionary的key是WXCondition的屬性名稱,而dictionary的value是JSON的路徑。

您可能已經注意到,這裡有一個從JSON資料對映到Objective-C屬性的問題。屬性dateNSDate型別的,但JSON有一個Unix時間型別(sjpsega注:即從1970年1月1日0時0分0秒起至現在的總秒數)的NSInteger值。你需要完成兩者之間的轉換。

Mantle正好有一個功能來為你解決這個問題:MTLValueTransformer。這個類允許你宣告一個block,詳細說明值的相互轉換。

Mantle的轉換器語法有點怪。要建立一個為一個特定屬性的轉換器,,您可以新增一個以屬性名開頭和JSONTransformer結尾的類方法。 可能看實際程式碼比試圖解釋它更容易理解,所以在WXCondition.m中新增以下為NSDate屬性設定的轉換器。

  1. 使用blocks做屬性的轉換的工作,並返回一個MTLValueTransformer返回值。
  2. 您只需要詳細說明Unix時間和NSDate之間進行轉換一次,就可以重用-dateJSONTransformer方法為sunrise和sunset屬性做轉換。

下一個值轉型有點討厭,但它只是使用OpenWeatherMap的API,並自己的格式化JSON響應方式的結果。weather鍵對應的值是一個JSON陣列,但你只關注單一的天氣狀況。

WXCondition.m中,使用dateJSONTransformer相同的結構,您可以建立一個NSArray和NSString的之間的轉換。該解決方案提供如下:

最後的轉換器只是為了格式化。 OpenWeatherAPI使用每秒/米的風速。由於您的App使用英制系統,你需要將其轉換為每小時/英里。

WXCondition.m的實現中新增以下轉換器的方法和巨集定義。

在OpenWeatherMap的API中有一個小的差異,你必須處理。看一看在位於當前狀況的響應每日預測反應之間的溫度:

current的第一個key是main,最高溫度儲存在key temp_max中,而daily forecast的第一個key是temp,最高溫度儲存在key max中。

key Temperature的差異放在一邊,其他都一樣。所以,你真正需要做的是修改daily forecasts的鍵對映。

開啟WXDailyForecast.m重寫+JSONKeyPathsByPropertyKey方法:

  1. 獲取WXCondition的對映,並建立它的可變副本。
  2. 你需要為daily forecast做的是改變max和min鍵對映。
  3. 返回新的對映。

構建並執行您的App,看起來和上次執行沒什麼改變,但好的一點是,App編譯和執行沒有任何錯誤。

built-gergergerglayout

何去何從?

你可以從這裡下載完整程式。

在這部分教程中,您使用Cocoapods設定專案,增加檢視到控制器,編排檢視,並建立模型來反映你抓取的氣象資料。該App還沒有充分發揮作用,但是你成功用純程式碼建立檢視,並學習瞭如何使用Mantle對映和轉換JSON資料。

接下來看看教程的第二部分,你將充實你的App,從weather API獲取資料,並在UI上顯示。您將使用新的iOS7 NSURLSession去下載資料,以及使用ReactiveCocoa把位置查詢,天氣資料抓取和UI更新事件綁在一起。

相關文章