はじめに
新人のコードレビューを行っていてどうやらモデルクラスを使ったJSONデータのパースができない、データベースからのクエリパースができない、みたいなことが多いので初学者向けに記事を書きます。
ここまでするか?っていうぐらいの半分ぐらいはします。
環境
- Xcode 7.3.1
- AFNetworking 3.0
- OS X 10.11.6
- CocoaPods 0.39.0
CocoaPodsは導入済み前提で進めます。
プロジェクト作成
Xcodeを閉じておく
閉じた!!かわいい!!
AFNetworkingインストール
$ cd /path/to/project/
$ pod init
$ vim Podfile
target 'Sample' do
pod 'AFNetworking', '~> 3.0'
end
$ pod install
$ open /path/to/project/project.xcworkspace/
使用するAPI
今回は東京都の天気を使用します。
サンプルコード
ATS関係で http
にはアクセスできないのでInfo.plistに書き込みする
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Info.plistにkeyを上記のように追加しても良い
GETリクエスト
モデルわけするのがちょっと面倒なのでViewControllerに書いちゃいます。
# import "ViewController.h"
# import <AFNetworking/AFNetworking.h>
@interface ViewController ()
@property (weak, nonatomic) NSMutableArray *weatherDatas;
@end
static NSString *const accessUrl = @"http://weather.livedoor.com/forecast/webservice/json/v1";
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
_weatherDatas = [NSMutableArray array];
_weatherDatas = [self getWeatherInfoData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (NSMutableArray *)getWeatherInfoData {
NSDictionary<NSString *, NSString *> *parameters = @{@"city" : @"130010"};
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:accessUrl
parameters:parameters
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
// ここに処理
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"Error: %@", error);
}
];
}
@end
モデルクラス作成
File > New > File... からファイルを作成します。
iOS内のSourceからCocoa Touch Classが選択されていたらNext
Weatherクラスを作りました。
今回は「 今日 」「 明日 」「 明後日 」のデータを取得するようにします。
# import <Foundation/Foundation.h>
@interface Weather : NSObject
@property (strong, nonatomic) NSString *dateLabel;
@property (strong, nonatomic) NSString *telop;
@property (strong, nonatomic) NSString *imageUrl;
@end
ざっとこんな感じにしておきましょう!
JSONデータパース
ViewController.m
で Weather.h
をimportしましょう!
結構記事を作るのが面倒になってきたのでいろいろ端折りますが最終的には以下の様になればいいかな?って思います。
# import "ViewController.h"
# import "Weather.h"
# import <AFNetworking/AFNetworking.h>
@interface ViewController ()
typedef void (^apiCallback)(NSMutableArray<Weather *> *weatherDatas);
@end
static NSString *const accessUrl = @"http://weather.livedoor.com/forecast/webservice/json/v1";
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSDictionary<NSString *, NSString *> *parameters = @{@"city" : @"130010"};
[self getWeatherInfoData:parameters callback:^(NSMutableArray<Weather *> *weatherDatas) {
for (Weather *weather in weatherDatas) {
NSLog(@"%@の天気は%@です。", weather.dateLabel, weather.telop);
}
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)getWeatherInfoData:(NSDictionary<NSString *, NSString *> *)parameters callback:(apiCallback)callback {
NSMutableArray *weatherDatas = [NSMutableArray new];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
[manager GET:accessUrl
parameters:parameters
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
for (NSDictionary<NSString *, NSString *> *forecasts in responseObject[@"forecasts"]) {
Weather *weather = [Weather new];
weather.dateLabel = forecasts[@"dateLabel"];
weather.telop = forecasts[@"telop"];
weather.imageUrl = [forecasts valueForKeyPath:@"image.url"];
[weatherDatas addObject:weather];
}
callback(weatherDatas);
}
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"Error: %@", error);
callback(nil);
}
];
}
@end
NSLog自体はこんな感じででてきます!
2016-08-19 16:09:18.008 Sample[57209:10708282] 今日の天気は曇時々晴です。
2016-08-19 16:09:18.008 Sample[57209:10708282] 明日の天気は曇時々雨です。
2016-08-19 16:09:18.008 Sample[57209:10708282] 明後日の天気は曇りです。
今回は画像をそのまま入れただけにしていますが、AFNetworkingを使って非同期で画像をキャッシュしつつ表示させるようにするのは以下のようにする
# import <AFNetworking/UIImageView+AFNetworking.h>
[imageView setImageWithURL:[NSURL URLWithString:@"http://example.com/image.png"]
placeholderImage:[UIImage imageNamed:@"placeholder"]];
みたいにすると行けます