注:本文譯自: raywenderlich ios-7-best-practices-part-1 ,去除了跟主題無關的寒暄部分。 歡迎轉載,保持署名
在這個兩部分的系列教程中,您将探索如何使用以下工具和技術來建立自己的App:
- Cocoapods
- Manual layout in code(純代碼布局)
- ReactiveCocoa
- OpenWeatherMap
本教程專為熟悉基本知識的、但還沒有接觸到太多進階主題的中級開發者而設計。本教程也是想要去探索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錯誤的時候。如果發生錯誤,你将看到類似這樣的一個浮層:
ReactiveCocoa
最後,你将使用到 ReactiveCocoa ,他也來自于GitHub團隊。ReactiveCocoa給Objective-C帶來了函數程式設計,類似與.NET的 Reactive Extensions 。你将在第二部分花費大部分時間去實作ReactiveCocoa。
設定你的Cocoapods
設定你的Cocoapods,先要確定你已經安裝了Cocoapods。為此,打開指令行程式,并輸入。
你将會看到類似這樣的輸出:
這決定于你如何管理Ruby gems,例如你使用 rbenv 或 RVM ,路徑可能有所不同。
如果指令行簡單的傳回提示,或顯示
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項目,如圖所示:
建構并運作您的App,以確定一切工作正常:
建立你的主視圖控制器
雖然這個App看起來複雜,但它還會通過一個單一的View Controller完成。現在,你将添加他。
選中
SimpleWeather
項目,單擊
File\New\File
,并且選擇
Cocoa Touch\Objective-C class
. 命名為
WXController
,并設定為
UIViewController
的子類。
確定
Targeted for iPad
和
With XIB for user interface
都沒有選中,如下圖所示:
打開
WXController.m
然後用如下所示替換
-viewDidLoad
方法:
| |
現在打開
AppDelegate.m
,并且引入如下兩個class:
| |
眼尖的讀者會注意到
WXController
使用引号引入,
TSMessage
使用單括号引入。
回頭看下當你建立Podfile的時候,你使用Cocoapods引入
TSMessage
。Cocoapods建立TSMessage項目,并把它加入到工作空間。既然你從工作區的其他項目導入,可以使用尖括号代替引号。
代替
-application:didFinishLaunchingWithOptions
的内容:
| |
标号注釋的解釋:
- 初始化并設定
執行個體作為App的根視圖控制器。通常這個控制器是一個的WXController
或UINavigationController
,但在目前情況下,你使用UITabBarController
的單個執行個體。WXController
- 設定預設的視圖控制器來顯示你的TSMessages。這樣做,你将不再需要手動指定要使用的控制器來顯示警告。
建構并運作,看看你的新視圖控制器起作用了。
在紅色背景下,狀态欄有點不夠清晰。幸運的是,有一個簡單的方法,使狀态欄更清晰易讀。
在iOS7, UIViewController 有一個新的API,用來控制狀态欄的外觀。打開
WXController
,直接添加下面的代碼到
-viewDidLoad:
方法下:
| |
再次建構并運作,你将看到狀态欄如下的變化:
設定你的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将是透明的:
為了實作動态模糊效果,在你的App中,你會根據App的滾動來改變模糊圖像的alpha值。
打開
WXController.m
,使用如下代碼來,替換掉
-viewDidLoad
中設定背景色的代碼:
| |
這是非常簡單的代碼:
- 擷取并存儲螢幕高度。之後,你将在用分頁的方式來顯示所有天氣 資料時,使用它。
- 建立一個靜态的背景圖,并添加到視圖上。
- 使用LBBlurredImage來建立一個模糊的背景圖像,并設定alpha為0,使得開始
是可見的。backgroundImageView
- 建立tableview來處理所有的資料呈現。 設定WXController為delegate和dataSource,以及滾動視圖的delegate。請注意,設定
為pagingEnabled
。YES
添加如下UITableView的delegate和dataSource的代碼到
WXController.m
的
@implementation
塊中:
| |
-
是 組織代碼 的很好的一種方式。Pragma mark
- 你的table view有兩個部分,一個是每小時的天氣預報,另一個用于每日播報。table view的section數目,設定為2。
- 天氣預報的cell是不可選擇的。給他們一個半透明的黑色背景和白色文字。
| |
最後,添加如下代碼到
WXController.m
:
| |
在
WXController.m
中,你的視圖控制器調用該方法來編排其子視圖。
建構并運作你的App,看看你的視圖如何堆疊。
仔細看,你會看到所有空的table cell的cell分隔線。
仍然在
-viewDidLoad
中,添加下面的代碼來設定你的布局架構和邊距:
| |
這是相當正常設定代碼,但這裡是怎麼回事:
- 設定table的header大小與螢幕相同。你将利用的UITableView的分頁來分隔頁面頁頭和每日每時的天氣預報部分。
- 建立inset(或padding)變量,以便您的所有标簽均勻分布并居中。
- 建立并初始化為各種視圖建立的高度變量。設定這些值作為常量,使得可以很容易地在需要的時候,配置和更改您的視圖設定。
- 使用常量和inset變量,為label和view建立架構。
- 複制圖示框,調整它,使文本具有一定的擴充空間,并将其移動到該圖示的右側。當我們把标簽添加到視圖,你會看到布局的效果。
添加如下代碼到
-viewDidLoad
:
| |
這是相當長的一塊代碼,但它真的隻是在做設定各種控件的繁重工作。簡單的說:
- 設定目前view為你的table header。
- 建構每一個顯示氣象資料的标簽。
- 添加一個天氣圖示的圖像視圖。
建構并運作你的App,你應該可以看到你之前布局的所有所有view。下面的螢幕截圖顯示了使用手工布局的、所有标簽框在視覺上的顯示。
用手指輕輕推動table,當你滾動它的時候,應該會反彈。
擷取氣象資料
你會注意到,App顯示“Loading…”,但它不是真正地在工作。是時候擷取一些真正的天氣資料。
你會從 OpenWeatherMap 的API拉取資料。 OpenWeatherMap是一個非常棒的服務,旨在提供實時,準确,免費的天氣資料給任何人。雖然有很多天氣API,但他們大多要麼使用較舊的資料格式,如XML,或是有償服務 – 并且有時還相當昂貴。
你會遵循以下基本步驟,來獲你裝置的位置的氣象資料:
- 找到裝置的位置
- 從 API端 下載下傳JSON資料
- 映射JSON到
和WXConditions
WXDailyForecasts
- 告訴UI有新資料了
開始建立你的天氣模型和資料管理類。單擊
File\New\File…
并選擇
Cocoa Touch\Objective-C class
。命名為
WXClient
并使其為
NSObject
的子類。
這樣再做三次建立以下類:
-
作為WXManager
的子類NSObject
-
作為WXCondition
的子類MTLModel
-
作為WXDailyForecast
的子類WXCondition
全部完成?現在,你可以開始下一節,其中涉及映射和轉換您的天氣資料。
建立你的天氣模型
你的模型将使用 Mantle ,這使得資料映射和轉型非常簡單。
打開
WXCondition.h
如下列代碼,修改接口:
| |
-
協定告訴Mantle序列化該對象如何從JSON映射到Objective-C的屬性。MTLJSONSerializing
- 這些都是你的天氣資料的屬性。你将會使用這些屬性的get set方法,但是當你要擴充App,這是一種很好的方法來通路資料。
- 這是一個簡單的輔助方法,從天氣狀況映射到圖像檔案。
建構并運作App。失敗了……
原因是你沒有從你的Cocoapods項目中引入
Mantle
。解決方法是,在
WXCondition.h
中,你需要把
MTLModel.h
替換為
#import <Mantle.h>
。
現在建構并運作App。成功了。你會看到一些新的警告,但你可以忽略他們。
首先,你需要處理未實作的
-imageName
方法。
打開
WXCondition.m
,添加如下方法:
| |
- 建立一個靜态的NSDictionary,因為WXCondition的每個執行個體都将使用相同的資料映射。
- 天氣狀況與圖像檔案的關系(例如“01d”代表“weather-clear.png”)。
- 聲明擷取圖像檔案名的公有方法。
看一看從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屬性的問題。屬性
date
是
NSDate
類型的,但JSON有一個Unix時間類型(sjpsega注:即從1970年1月1日0時0分0秒起至現在的總秒數)的NSInteger值。你需要完成兩者之間的轉換。
Mantle正好有一個功能來為你解決這個問題: MTLValueTransformer 。這個類允許你聲明一個block,詳細說明值的互相轉換。
Mantle的轉換器文法有點怪。要建立一個為一個特定屬性的轉換器,,您可以添加一個以屬性名開頭和
JSONTransformer
結尾的類方法。 可能看實際代碼比試圖解釋它更容易了解,是以在
WXCondition.m
中添加以下為NSDate屬性設定的轉換器。
| |
- 使用blocks做屬性的轉換的工作,并傳回一個MTLValueTransformer傳回值。
- 您隻需要詳細說明Unix時間和NSDate之間進行轉換一次,就可以重用
方法為sunrise和sunset屬性做轉換。-dateJSONTransformer
下一個值轉型有點讨厭,但它隻是使用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
方法:
| |
- 擷取
的映射,并建立它的可變副本。WXCondition
- 你需要為daily forecast做的是改變max和min鍵映射。
- 傳回新的映射。
建構并運作您的App,看起來和上次運作沒什麼改變,但好的一點是,App編譯和運作沒有任何錯誤。
何去何從?
你可以從 這裡 下載下傳完整程式。
在這部分教程中,您使用Cocoapods設定項目,增加視圖到控制器,編排視圖,并建立模型來反映你抓取的氣象資料。該App還沒有充分發揮作用,但是你成功用純代碼建立視圖,并學習了如何使用Mantle映射和轉換JSON資料。
接下來看看教程的第二部分,你将充實你的App,從weather API擷取資料,并在UI上顯示。您将使用新的iOS7 NSURLSession 去下載下傳資料,以及使用
ReactiveCocoa
把位置查找,天氣資料抓取和UI更新事件綁在一起。