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

jopen 10年前發布 | 42K 次閱讀 iOS7 iOS開發 移動開發

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

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

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

開始

打開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錯誤的時候。如果發生錯誤,你將看到類似這樣的一個浮層:

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

ReactiveCocoa

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

設置你的Cocoapods

設置你的Cocoapods,先要確保你已經安裝了Cocoapods。為此,打開命令行程序,并輸入。

which pod

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

/usr/bin/pod

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

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

sjpsega注:Cocoapods中文安裝教程可以看這篇 http://geeklu.com/2013/06/cocoapods-101/

Podfiles是用來告訴Cocoapods哪些開源項目需要導入。

要創建你的第一個Cocoapod,首先在命令行中用cd命令導航到你的XCode項目所在的文件夾,在命令行中啟動編輯器,輸入

platform :ios, '7.0'

pod 'Mantle'
pod 'LBBlurredImage'
pod 'TSMessages'
pod 'ReactiveCocoa'

這文件做了兩件事情:

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

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

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

$ pod install
Analyzing dependencies

CocoaPods 0.28.0 is available.

Downloading dependencies
Installing HexColors (2.2.1)
Installing LBBlurredImage (0.1.0)
Installing Mantle (1.3.1)

Installing ReactiveCocoa (2.1.7)
Installing TSMessages (0.9.4)
Generating Pods project
Integrating client project

[!] From now on use `SimpleWeather.xcworkspace`.
sjpsega注:若你之前安裝過Cocoapods的話,這里安裝報錯的話,可以看看http://blog.cocoapods.org/Repairing-Our-Broken-Specs-Repository/ 修復問題

Cocoapods會在你的項目目錄中創建一堆新文件,但是,只有一個需要你關心,SimpleWeather.xcworkspace

用Xcode打開SimpleWeather.xcworkspace。看看你的項目設置,現在有一個Pods項目在你的項目工作區,以及在Pods文件夾放著每一個你引入的庫,如下所示:

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

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

確保你已經選擇SimpleWeather項目,如圖所示:

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

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

提示:您可能會注意到有一些項目生成警告。因為Cocoapods引入的項目,是由不同的開發者開發,并且不同的開發者對生成警告有不同的態度。通常,你應該可以忽略它們。只要確保沒有任何編譯器錯誤!

創建你的主視圖控制器

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

選中SimpleWeather項目,單擊File\New\File,并且選擇Cocoa Touch\Objective-C class. 命名為WXController,并設置為UIViewController的子類。

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

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

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

- (void)viewDidLoad {
    [super viewDidLoad];

    // Remove this later
    self.view.backgroundColor = [UIColor redColor];
}

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

#import "WXController.h"
#import <TSMessage.h>

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

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

代替-application:didFinishLaunchingWithOptions的內容:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    // 1
    self.window.rootViewController = [[WXController alloc] init];
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    // 2
    [TSMessage setDefaultViewController: self.window.rootViewController];
    return YES;
}

標號注釋的解釋:

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

構建并運行,看看你的新視圖控制器起作用了。

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

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

在iOS7,UIViewController有一個新的API,用來控制狀態欄的外觀。打開WXController,直接添加下面的代碼到-viewDidLoad:方法下:

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

 

再次構建并運行,你將看到狀態欄如下的變化:

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

設置你的App視圖

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

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

打開WXController.h, 添加如下委托協議:

<UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate>

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

添加如下代碼到WXController.m頂部:

#import <LBBlurredImage/UIImageView+LBBlurredImage.h>

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

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

@interface WXController ()

@property (nonatomic, strong) UIImageView *backgroundImageView;
@property (nonatomic, strong) UIImageView *blurredImageView;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, assign) CGFloat screenHeight;

@end

現在,是時候在項目中創建并設置視圖。

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

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

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

打開WXController.m,使用如下代碼來,替換掉-viewDidLoad中設置背景色的代碼:

// 1
self.screenHeight = [UIScreen mainScreen].bounds.size.height;

UIImage *background = [UIImage imageNamed:@"bg"];

// 2
self.backgroundImageView = [[UIImageView alloc] initWithImage:background];
self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:self.backgroundImageView];

// 3
self.blurredImageView = [[UIImageView alloc] init];
self.blurredImageView.contentMode = UIViewContentModeScaleAspectFill;
self.blurredImageView.alpha = 0;
[self.blurredImageView setImageToBlur:background blurRadius:10 completionBlock:nil];
[self.view addSubview:self.blurredImageView];

// 4
self.tableView = [[UITableView alloc] init];
self.tableView.backgroundColor = [UIColor clearColor];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.separatorColor = [UIColor colorWithWhite:1 alpha:0.2];
self.tableView.pagingEnabled = YES;
[self.view addSubview:self.tableView];

這是非常簡單的代碼:

  1. 獲取并存儲屏幕高度。之后,你將在用分頁的方式來顯示所有天氣??數據時,使用它。
  2. 創建一個靜態的背景圖,并添加到視圖上。
  3. 使用LBBlurredImage來創建一個模糊的背景圖像,并設置alpha為0,使得開始backgroundImageView是可見的。
  4. 創建tableview來處理所有的數據呈現。 設置WXController為delegate和dataSource,以及滾動視圖的delegate。請注意,設置pagingEnabledYES

添加如下UITableView的delegate和dataSource的代碼到WXController.m@implementation塊中:

// 1
#pragma mark - UITableViewDataSource

// 2
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    // TODO: Return count of forecast
    return 0;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"CellIdentifier";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (! cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
    }

    // 3
    cell.selectionStyle = UITableViewCellSelectionStyleNone;
    cell.backgroundColor = [UIColor colorWithWhite:0 alpha:0.2];
    cell.textLabel.textColor = [UIColor whiteColor];
    cell.detailTextLabel.textColor = [UIColor whiteColor];

    // TODO: Setup the cell

    return cell;
}

#pragma mark - UITableViewDelegate

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    // TODO: Determine cell height based on screen
    return 44;
}
  1. Pragma mark組織代碼的很好的一種方式。
  2. 你的table view有兩個部分,一個是每小時的天氣預報,另一個用于每日播報。table view的section數目,設置為2。
  3. 天氣預報的cell是不可選擇的。給他們一個半透明的黑色背景和白色文字。
注意:使用格式化的注釋 // TODO:可以幫助Xcode找到需要以后完成的代碼。你還可以使用 Show Document Items(Control-6)來查看TODO項。

最后,添加如下代碼到WXController.m:

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];

    CGRect bounds = self.view.bounds;

    self.backgroundImageView.frame = bounds;
    self.blurredImageView.frame = bounds;
    self.tableView.frame = bounds;
}

WXController.m中,你的視圖控制器調用該方法來編排其子視圖。

構建并運行你的App,看看你的視圖如何堆疊。

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

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

仍然在-viewDidLoad中,添加下面的代碼來設置你的布局框架和邊距:

// 1
CGRect headerFrame = [UIScreen mainScreen].bounds;
// 2
CGFloat inset = 20;
// 3
CGFloat temperatureHeight = 110;
CGFloat hiloHeight = 40;
CGFloat iconHeight = 30;
// 4
CGRect hiloFrame = CGRectMake(inset,
                              headerFrame.size.height - hiloHeight,
                              headerFrame.size.width - (2 * inset),
                              hiloHeight);

CGRect temperatureFrame = CGRectMake(inset,
                                     headerFrame.size.height - (temperatureHeight + hiloHeight),
                                     headerFrame.size.width - (2 * inset),
                                     temperatureHeight);

CGRect iconFrame = CGRectMake(inset,
                              temperatureFrame.origin.y - iconHeight,
                              iconHeight,
                              iconHeight);
// 5
CGRect conditionsFrame = iconFrame;
conditionsFrame.size.width = self.view.bounds.size.width - (((2 * inset) + iconHeight) + 10);
conditionsFrame.origin.x = iconFrame.origin.x + (iconHeight + 10);

這是相當常規設置代碼,但這里是怎么回事:

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

添加如下代碼到-viewDidLoad

// 1
UIView *header = [[UIView alloc] initWithFrame:headerFrame];
header.backgroundColor = [UIColor clearColor];
self.tableView.tableHeaderView = header;

// 2
// bottom left
UILabel *temperatureLabel = [[UILabel alloc] initWithFrame:temperatureFrame];
temperatureLabel.backgroundColor = [UIColor clearColor];
temperatureLabel.textColor = [UIColor whiteColor];
temperatureLabel.text = @"0°";
temperatureLabel.font = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:120];
[header addSubview:temperatureLabel];

// bottom left
UILabel *hiloLabel = [[UILabel alloc] initWithFrame:hiloFrame];
hiloLabel.backgroundColor = [UIColor clearColor];
hiloLabel.textColor = [UIColor whiteColor];
hiloLabel.text = @"0° / 0°";
hiloLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:28];
[header addSubview:hiloLabel];

// top
UILabel *cityLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, self.view.bounds.size.width, 30)];
cityLabel.backgroundColor = [UIColor clearColor];
cityLabel.textColor = [UIColor whiteColor];
cityLabel.text = @"Loading...";
cityLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:18];
cityLabel.textAlignment = NSTextAlignmentCenter;
[header addSubview:cityLabel];

UILabel *conditionsLabel = [[UILabel alloc] initWithFrame:conditionsFrame];
conditionsLabel.backgroundColor = [UIColor clearColor];
conditionsLabel.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:18];
conditionsLabel.textColor = [UIColor whiteColor];
[header addSubview:conditionsLabel];

// 3
// bottom left
UIImageView *iconView = [[UIImageView alloc] initWithFrame:iconFrame];
iconView.contentMode = UIViewContentModeScaleAspectFit;
iconView.backgroundColor = [UIColor clearColor];
[header addSubview:iconView];

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

  1. 設置當前view為你的table header。
  2. 構建每一個顯示氣象數據的標簽。
  3. 添加一個天氣圖標的圖像視圖。

構建并運行你的App,你應該可以看到你之前布局的所有所有view。下面的屏幕截圖顯示了使用手工布局的、所有標簽框在視覺上的顯示。

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

用手指輕輕推動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
@interface WXCondition : MTLModel <MTLJSONSerializing>

// 2
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSNumber *humidity;
@property (nonatomic, strong) NSNumber *temperature;
@property (nonatomic, strong) NSNumber *tempHigh;
@property (nonatomic, strong) NSNumber *tempLow;
@property (nonatomic, strong) NSString *locationName;
@property (nonatomic, strong) NSDate *sunrise;
@property (nonatomic, strong) NSDate *sunset;
@property (nonatomic, strong) NSString *conditionDescription;
@property (nonatomic, strong) NSString *condition;
@property (nonatomic, strong) NSNumber *windBearing;
@property (nonatomic, strong) NSNumber *windSpeed;
@property (nonatomic, strong) NSString *icon;

// 3
- (NSString *)imageName;

@end
  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,添加如下方法:

+ (NSDictionary *)imageMap {
    // 1
    static NSDictionary *_imageMap = nil;
    if (! _imageMap) {
        // 2
        _imageMap = @{
                      @"01d" : @"weather-clear",
                      @"02d" : @"weather-few",
                      @"03d" : @"weather-few",
                      @"04d" : @"weather-broken",
                      @"09d" : @"weather-shower",
                      @"10d" : @"weather-rain",
                      @"11d" : @"weather-tstorm",
                      @"13d" : @"weather-snow",
                      @"50d" : @"weather-mist",
                      @"01n" : @"weather-moon",
                      @"02n" : @"weather-few-night",
                      @"03n" : @"weather-few-night",
                      @"04n" : @"weather-broken",
                      @"09n" : @"weather-shower",
                      @"10n" : @"weather-rain-night",
                      @"11n" : @"weather-tstorm",
                      @"13n" : @"weather-snow",
                      @"50n" : @"weather-mist",
                      };
    }
    return _imageMap;
}

// 3
- (NSString *)imageName {
    return [WXCondition imageMap][self.icon];
}
  1. 創建一個靜態的NSDictionary,因為WXCondition的每個實例都將使用相同的數據映射。
  2. 天氣狀況與圖像文件的關系(例如“01d”代表“weather-clear.png”)。
  3. 聲明獲取圖像文件名的公有方法。

看一看從OpenWeatherMap返回的JSON響應數據:

{
    "dt": 1384279857,
    "id": 5391959,
    "main": {
        "humidity": 69,
        "pressure": 1025,
        "temp": 62.29,
        "temp_max": 69.01,
        "temp_min": 57.2
    },
    "name": "San Francisco",
    "weather": [
        {
            "description": "haze",
            "icon": "50d",
            "id": 721,
            "main": "Haze"
        }
    ]
}

 

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

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

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

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{
             @"date": @"dt",
             @"locationName": @"name",
             @"humidity": @"main.humidity",
             @"temperature": @"main.temp",
             @"tempHigh": @"main.temp_max",
             @"tempLow": @"main.temp_min",
             @"sunrise": @"sys.sunrise",
             @"sunset": @"sys.sunset",
             @"conditionDescription": @"weather.description",
             @"condition": @"weather.main",
             @"icon": @"weather.icon",
             @"windBearing": @"wind.deg",
             @"windSpeed": @"wind.speed"
             };
}

在這個方法里,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屬性設置的轉換器。

+ (NSValueTransformer *)dateJSONTransformer {
    // 1
    return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSString *str) {
        return [NSDate dateWithTimeIntervalSince1970:str.floatValue];
    } reverseBlock:^(NSDate *date) {
        return [NSString stringWithFormat:@"%f",[date timeIntervalSince1970]];
    }];
}

// 2
+ (NSValueTransformer *)sunriseJSONTransformer {
    return [self dateJSONTransformer];
}

+ (NSValueTransformer *)sunsetJSONTransformer {
    return [self dateJSONTransformer];
}
  1. 使用blocks做屬性的轉換的工作,并返回一個MTLValueTransformer返回值。
  2. 您只需要詳細說明Unix時間和NSDate之間進行轉換一次,就可以重用-dateJSONTransformer方法為sunrise和sunset屬性做轉換。

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

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

+ (NSValueTransformer *)conditionDescriptionJSONTransformer {
    return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSArray *values) {
        return [values firstObject];
    } reverseBlock:^(NSString *str) {
        return @[str];
    }];
}

+ (NSValueTransformer *)conditionJSONTransformer {
    return [self conditionDescriptionJSONTransformer];
}

+ (NSValueTransformer *)iconJSONTransformer {
    return [self conditionDescriptionJSONTransformer];
}

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

WXCondition.m的實現中添加以下轉換器的方法和宏定義。

#define MPS_TO_MPH 2.23694f

+ (NSValueTransformer *)windSpeedJSONTransformer {
    return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSNumber *num) {
        return @(num.floatValue*MPS_TO_MPH);
    } reverseBlock:^(NSNumber *speed) {
        return @(speed.floatValue/MPS_TO_MPH);
    }];
}

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

// current
"main": {
    "grnd_level": 1021.87,
    "humidity": 64,
    "pressure": 1021.87,
    "sea_level": 1030.6,
    "temp": 58.09,
    "temp_max": 58.09,
    "temp_min": 58.09
}

// daily forecast
"temp": {
    "day": 58.14,
    "eve": 58.14,
    "max": 58.14,
    "min": 57.18,
    "morn": 58.14,
    "night": 57.18
}

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

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

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

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    // 1
    NSMutableDictionary *paths = [[super JSONKeyPathsByPropertyKey] mutableCopy];
    // 2
    paths[@"tempHigh"] = @"temp.max";
    paths[@"tempLow"] = @"temp.min";
    // 3
    return paths;
}
  1. 獲取WXCondition的映射,并創建它的可變副本。
  2. 你需要為daily forecast做的是改變max和min鍵映射。
  3. 返回新的映射。

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

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

何去何從?

你可以從這里下載完整程序。

在這部分教程中,您使用Cocoapods設置項目,增加視圖到控制器,編排視圖,并建立模型來反映你抓取的氣象數據。該App還沒有充分發揮作用,但是你成功用純代碼創建視圖,并學習了如何使用Mantle映射和轉換JSON數據。

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

原文出處: raywenderlich   譯文出處: sjpsega (@IORI_YAGAMI_7)

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!