#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive
state. This can occur for certain types of temporary interruptions (such as an
incoming phone call or SMS message) or when the user quits the application and
it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and
invalidate graphics rendering callbacks. Games should use this method to pause
the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data,
invalidate timers, and store enough application state information to restore
your application to its current state in case it is terminated later.
// If your application supports background execution, this method is
called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active
state; here you can undo many of the changes made on entering the
background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the
application was inactive. If the application was previously in the background,
optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if
appropriate. See also applicationDidEnterBackground:.
}
@end
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
//// エラーメッセージ
#define kCFNetworkErrorsMessage @"通信に失敗しました。\nCFNetworkErrors =
%ld"
#define kHttpStatusCodesErrorMessage @"通信に失敗しました。\nHttpStatusCode =
%ld"
// タイムアウト値(デフォルト)
#define kDefaultTimeoutInterval 120.0f
/*
* URLパラメータタイプ定義
*/
typedef NS_ENUM(NSInteger, NMUrlParameterType) {
NMUrlParameterTypeJson = 0, // JSON
NMUrlParameterTypeString, // 文字列
NMUrlParameterTypeReserved // 予約(未使用)
};
// ブロック
typedef void (^NetworkJsonSuccessBlock)(id json);
typedef void (^NetworkJsonFailureBlock)(NSString *message, NSError
*error);
typedef void (^NetworkDictSuccessBlock)(NSMutableDictionary *dict);
typedef void (^NetworkDictFailureBlock)(NSString *message, NSError
*error);
typedef void (^NetworkImageSuccessBlock)(UIImage *image);
typedef void (^NetworkImageFailureBlock)(NSString *message, NSError
*error);
typedef void (^NetworkFileSuccessBlock)(NSURL *location);
typedef void (^NetworkFileFailureBlock)(NSString *message, NSError
*error);
/**
* サーバーからJSONデータを取得する通信管理クラス。
* @warning
* 独自アプリ用に作成されたクラスであるので、他の用途では、正常に動作しない可能性があります。
* 従って、使用するに当たっては、全て自己責任でお願い致します。
*/
@interface NetworkManager : NSObject
{
/// ネットワークアクティビティ数
NSInteger _activityCount;
}
#pragma mark - property
/// URLパラメータタイプ
@property (assign, nonatomic) NMUrlParameterType urlParameterType;
/// デモモード(JSONファイル読込)有無
@property (assign, nonatomic) BOOL isDemoMode;
/// タイムアウト(double型)
@property (assign, nonatomic) NSTimeInterval timeoutInterval;
/// ベースURL
@property (strong, nonatomic) NSString *baseURL;
/// ベースURL(シミュレーター用)
@property (strong, nonatomic) NSString *baseURL4Simulator;
#pragma mark - ClassMethod
/**
* NetworkManagerを取得する
* @return NetworkManagerインスタンス
*/
+ (NetworkManager *)sharedManager;
#pragma mark - PublicMethod
/**
* バイナリデータをJSONデータに変換する。
* @param data バイナリデータ
* @return JSONデータ
*/
- (NSDictionary *)convertJSONFromData:(NSData *)data;
/**
* イメージデータをBASE64(文字列)に変換する。
* @param image イメージデータ
* @return BASE64(文字列)
*/
- (NSString *)encodeToBase64StringFromImage:(UIImage *)image;
/**
* バイナリデータをBASE64(文字列)に変換する。
* @param data バイナリデータ
* @return BASE64(文字列)
*/
- (NSString *)encodeToBase64StringFromData:(NSData *)data;
/**
* BASE64(文字列)をイメージデータに変換する。
* @param strEncodeData BASE64(文字列)
* @return JSONデータ
*/
- (UIImage *)decodeBase64ToImage:(NSString *)strEncodeData;
#pragma mark - RequestJSONWithBlock
/**
* JSONデータをリクエストする。(URLクラス指定)
* @param url プロトコル
* @param parameters パラメータ
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURL:(NSURL *)url
parameters:(NSDictionary
*)parameters
success:(NetworkJsonSuccessBlock)success
failure:(NetworkJsonFailureBlock)failure;
/**
* JSONデータをリクエストする。(URL文字列指定)
* @param urlString URL文字列
* @param parameters パラメータ
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURLString:(NSString
*)urlString
parameters:(NSDictionary
*)parameters
success:(NetworkJsonSuccessBlock)success
failure:(NetworkJsonFailureBlock)failure;
/**
* JSONデータをリクエストする。(プロトコル指定)
* @param protocol プロトコル
* @param parameters パラメータ
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithProtocol:(NSString
*)protocol
parameters:(NSDictionary
*)parameters
success:(NetworkJsonSuccessBlock)success
failure:(NetworkJsonFailureBlock)failure;
#pragma mark - RequestJSONWithDelegate
/**
* JSONデータをリクエストする。(URLインスタンス指定、デリゲート有)
* @param url プロトコル
* @param parameters パラメータ
* @param delegate デリゲート
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURL:(NSURL *)url
parameters:(NSDictionary
*)parameters
delegate:(id<NSURLSessionDelegate>)delegate;
/**
* JSONデータをリクエストする。(URL文字列指定、デリゲート有)
* @param urlString URL文字列
* @param parameters パラメータ
* @param delegate デリゲート
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURLString:(NSString
*)urlString
parameters:(NSDictionary
*)parameters
delegate:(id<NSURLSessionDelegate>)delegate;
/**
* JSONデータをリクエストする。(プロトコル指定指定、デリゲート有)
* @param protocol プロトコル
* @param parameters パラメータ
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithProtocol:(NSString
*)protocol
parameters:(NSDictionary
*)parameters
delegate:(id<NSURLSessionDelegate>)delegate;
#pragma mark - DownloadImageWithBlock
/**
* イメージををダウンロードする。
* @param urlString URL(文字列)
* @param success 成功ブロック
* @param failure 失敗ブロック
*/
- (void)downloadImageWithURL:(NSString *)urlString
success:(NetworkImageSuccessBlock)success
failure:(NetworkImageFailureBlock)failure;
#pragma mark - DownloadFileWithBlock
/**
* ファイルをダウンロードする。(プログレス非表示)
* @param urlString URL文字列
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDownloadTaskインスタンス
*/
- (NSURLSessionDownloadTask *)downloadFileWithURL:(NSString
*)urlString
success:(NetworkFileSuccessBlock)success
failure:(NetworkFileFailureBlock)failure;
#pragma mark - DownloadFileWithDelegate
/**
* ファイルをダウンロードする。(プログレス表示用)
* @param urlString URL文字列
* @param delegate デリゲート
* @return NSURLSessionDownloadTaskインスタンス
*/
- (NSURLSessionDownloadTask *)downloadFileWithURL:(NSString
*)urlString
delegate:(id<NSURLSessionDelegate>)delegate
background:(BOOL)isBackground;
@end
#import "NetworkManager.h"
/// シングルトンオブジェクト
static NetworkManager *sharedManager_ = nil;
@implementation NetworkManager
#pragma mark - Class Method
/**
* NetworkManagerを取得する。
* @return NetworkManagerインスタンス
*/
+ (NetworkManager *)sharedManager
{
// 初回のみシングルトンオブジェクトを生成する
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager_ = [[NetworkManager alloc] init];
});
return sharedManager_;
}
/**
* 初期化する。
* @return 初期化後のインスタンス
*/
- (id)init
{
self = [super init];
if (self) {
_activityCount = 0;
_isDemoMode = NO;
_timeoutInterval = kDefaultTimeoutInterval;
_urlParameterType = NMUrlParameterTypeJson;
}
return self;
}
/**
* アクティビティカウントを管理する。
* @param isCountUp カウントアップ有無
*/
- (void)manageActivityCountUp:(BOOL)isCountUp
{
// アクティビティの管理は排他制御する
@synchronized(self) {
_activityCount += (isCountUp)? 1 : -1;
if (_activityCount < 0) _activityCount = 0;
dispatch_async(dispatch_get_main_queue(), ^{
[UIApplication
sharedApplication].networkActivityIndicatorVisible = (self->_activityCount
> 0);
});
}
}
#pragma mark - PrivateMethod
/**
* パラメータをクエリデータに変換する。
* @param params パラメータ
* @return クエリデータ
*/
- (NSData *)buildQueryWithDictionary:(NSDictionary *)params
{
if (_urlParameterType == NMUrlParameterTypeJson) {
// JSON の場合
return [NSJSONSerialization dataWithJSONObject:params options:0
error:nil];
} else {
// 文字列の場合
// 連想配列のキーと値をそれぞれ URL エンコードし、 key=value の形で配列に追加していく
NSMutableArray *parts = [NSMutableArray array];
for (id key in params) {
[parts addObject: [NSString stringWithFormat: @"%@=%@",
[self encodeURIComponent: (NSString
*)key],
[self encodeURIComponent: (NSString
*)[params objectForKey: key]]]];
}
// それぞれを & で結ぶ
NSString *queryString = [parts componentsJoinedByString:
@"&"];
// NSURLRequest setHTTPBody: に渡せるよう NSData に変換する
return [queryString dataUsingEncoding:NSUTF8StringEncoding];
}
}
/**
* URLエンコードする。
* @param string エンコード対象文字列
* @return コンコード文字列
*/
- (NSString *)encodeURIComponent:(NSString *)string
{
NSMutableCharacterSet *allowedCharacterSet = [NSMutableCharacterSet
alphanumericCharacterSet];
[allowedCharacterSet addCharactersInString:@"-._~"];
NSString *escapedString =[string
stringByAddingPercentEncodingWithAllowedCharacters:
allowedCharacterSet];
return escapedString;
}
/**
* シミュレーータ有無を判定する
* @return シミュレーター有無
*/
- (BOOL)isSimulator
{
return TARGET_OS_SIMULATOR != 0;
}
/**
* デフォルト(共通)通信設定を取得する。
* @param url プロトコル
* @param parameters パラメータ
* @return デフォルト(共通)通信設定
*/
- (NSMutableURLRequest *)defaultURLRequestWithURL:(NSURL *)url
parameters:(NSDictionary
*)parameters
{
NSData *query = [self buildQueryWithDictionary:parameters];
NSMutableURLRequest *request = [NSMutableURLRequest
requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:_timeoutInterval];
[request setHTTPMethod:@"POST"];
if (_urlParameterType == NMUrlParameterTypeJson) {
[request setValue:@"application/json" forHTTPHeaderField:
@"Content-Type"];
} else {
[request setValue:@"application/x-www-form-urlencoded"
forHTTPHeaderField: @"Content-Type"];
}
NSString *queryLength = [NSString stringWithFormat:@"%lu", (unsigned
long)[query length]];
[request setValue:queryLength
forHTTPHeaderField:@"Content-Length"];
[request setValue:@"gzip"
forHTTPHeaderField:@"Accept-Encoding"];
[request setHTTPBody:query];
return request;
}
/**
* デフォルト(共通)通信設定を取得する。
* @param path ファイルパス
* @return デフォルト(共通)通信設定
*/
- (NSURL *)properURLWithPath:(NSString *)path
{
// 文字列の先頭に「http」がある場合、URLパスとする。左記以外、FILEパスとする
return ([path hasPrefix:@"http"])? [NSURL URLWithString:path]:
[NSURL fileURLWithPath:path];
}
/**
* 適切なファイルパスを取得する。
* @param protocol プロトコル
* @return 適切なファイルパス
*/
- (NSString *)properPathWithProtocol:(NSString *)protocol
{
NSString *urlString = nil;
if (_isDemoMode) {
// デモモードの場合、JSONファイルからJSONデータを取得する
urlString = [[NSBundle mainBundle] pathForResource:protocol
ofType:@"json"];
}
else {
// 上記以外の場合、サーバーからJSONデータを取得する場合
// シミュレーター有無により、URLを切換える
NSString *baseURL = ([self isSimulator])?
_baseURL4Simulator:_baseURL;
urlString = [NSString stringWithFormat:@"%@%@", baseURL,
protocol];
}
return (urlString)? urlString: @"";
}
#pragma mark - PublicMethod
/**
* バイナリデータをJSONデータに変換する。
* @param data バイナリデータ
* @return JSONデータ
*/
- (NSDictionary *)convertJSONFromData:(NSData *)data
{
NSError *error = nil;
id json = [NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:&error];
if (json) {
// NSDictionary型のみ有効とする
if ([json isKindOfClass:[NSDictionary class]]) {
return json;
}
}
// 変換失敗の場合
return nil;
}
/**
* イメージデータをBASE64(文字列)に変換する。
* @param image イメージデータ
* @return BASE64(文字列)
*/
- (NSString *)encodeToBase64StringFromImage:(UIImage *)image
{
// 圧縮率は考慮する(一定?)
NSData *imageData = [[NSData alloc]
initWithData:UIImageJPEGRepresentation(image, 1.0f)];
// NSData* imageData = [[NSData alloc]
initWithData:UIImagePNGRepresentation(image)]; // PNGの場合
NSData *data = [imageData
base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
return [[NSString stringWithUTF8String:[data bytes]]
stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
}
/**
* バイナリデータをBASE64(文字列)に変換する。
* @param data バイナリデータ
* @return BASE64(文字列)
*/
- (NSString *)encodeToBase64StringFromData:(NSData *)data
{
NSData *encodeData = [data
base64EncodedDataWithOptions:NSDataBase64Encoding64CharacterLineLength];
return [[NSString alloc] initWithData:encodeData
encoding:NSUTF8StringEncoding];
// return [[NSString stringWithUTF8String:[data bytes]]
stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
}
/**
* BASE64(文字列)をイメージデータに変換する。
* @param strEncodeData BASE64(文字列)
* @return JSONデータ
*/
- (UIImage *)decodeBase64ToImage:(NSString *)strEncodeData
{
NSData *data = [[NSData
alloc]initWithBase64EncodedString:strEncodeData
options:NSDataBase64DecodingIgnoreUnknownCharacters];
return [UIImage imageWithData:data];
}
#pragma mark - RequestJSONWithBlock
/**
* JSONデータをリクエストする。(URL指定)
* @param url プロトコル
* @param parameters パラメータ
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURL:(NSURL *)url
parameters:(NSDictionary
*)parameters
success:(NetworkJsonSuccessBlock)success
failure:(NetworkJsonFailureBlock)failure
{
NSMutableURLRequest *request = [self defaultURLRequestWithURL:url
parameters:parameters];
[self manageActivityCountUp:YES];
NSURLSession *session = [NSURLSession sharedSession];
NetworkManager *__weak weakSelf = self;
NSURLSessionDataTask *task =
[session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response,
NSError *error) {
[weakSelf manageActivityCountUp:NO];
// デモモードの場合
if (weakSelf.isDemoMode) {
[NSThread sleepForTimeInterval:.5f];
NSDictionary *responseData =
[NSJSONSerialization JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:&error];
success(responseData);
return;
}
NSString *message = nil;
// 成功の場合
if (response && !error) {
NSInteger statusCode = ((NSHTTPURLResponse
*)response).statusCode;
if (statusCode == 200) {
NSDictionary *responseData =
[NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingAllowFragments
error:&error];
// JSONデータの場合
if (responseData) {
// Object(NSDictionary)
if ([responseData
isKindOfClass:[NSDictionary class]]) {
success(responseData);
}
else {
NSString *className =
NSStringFromClass([responseData class]);
message = [NSString
stringWithFormat:@"not NSDitonary format:\n %@", className];
failure(message, nil);
}
}
else {
NSString *log = [[NSString alloc]
initWithData:data encoding:NSUTF8StringEncoding];
message = [NSString stringWithFormat:@"not
JSON format:\n %@", log];
failure(message, nil);
}
}
// HTTPステータスコード「200」以外は、エラーとする
else {
NSString *message = [NSString
stringWithFormat:@"通信に失敗しました。\nHttpStatusCode = %ld",
(long)statusCode];
failure(message, error);
}
}
// 失敗の場合
else {
// コードの詳細は、CFNetworkErrors.h 参照
NSString *message = (error.code ==
kCFURLErrorCancelled)?
@"キャンセルされました。":
[NSString
stringWithFormat:@"通信に失敗しました。\nCFNetworkErrors = %ld", (long)error.code];
failure(message, error);
}
// sharedSession(共有)なので、後始末は不要
// 下記を行うと、2回目以降の呼び出しでエラーとなる
// [session invalidateAndCancel];
// [session finishTasksAndInvalidate];
}];
[task resume];
return task;
}
/**
* JSONデータをリクエストする。(URL文字列)
* @param urlString URL文字列
* @param parameters パラメータ
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURLString:(NSString
*)urlString
parameters:(NSDictionary
*)parameters
success:(NetworkJsonSuccessBlock)success
failure:(NetworkJsonFailureBlock)failure
{
return [self requestJsonWithURL:[self
properURLWithPath:urlString]
parameters:parameters
success:success
failure:failure];
}
/**
JSONデータをリクエストする。(プロトコル指定)
@param protocol プロトコル
@param parameters パラメータ
@param success 成功ブロック
@param failure 失敗ブロック
@return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithProtocol:(NSString
*)protocol
parameters:(NSDictionary
*)parameters
success:(NetworkJsonSuccessBlock)success
failure:(NetworkJsonFailureBlock)failure
{
return [self requestJsonWithURLString:[self
properPathWithProtocol:protocol]
parameters:parameters
success:success
failure:failure];
}
#pragma mark - RequestJSONWithDelegate
/**
* JSONデータをリクエストする。(URLインスタンス指定、デリゲート有)
* @param url プロトコル
* @param parameters パラメータ
* @param delegate デリゲート
* @param isBackground バックグランド処理有無
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURL:(NSURL *)url
parameters:(NSDictionary
*)parameters
delegate:(id<NSURLSessionDelegate>)delegate
{
NSMutableURLRequest *request = [self defaultURLRequestWithURL:url
parameters:parameters];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration
defaultSessionConfiguration];
NSURLSession *session = [NSURLSession
sessionWithConfiguration:config
delegate:delegate
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDataTask *task = [session
dataTaskWithRequest:request];
[task resume];
return task;
}
/**
* JSONデータをリクエストする。(URL文字列指定、デリゲート有)
* @param urlString URL文字列
* @param parameters パラメータ
* @param delegate デリゲート
* @param isBackground バックグランド処理有無
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithURLString:(NSString
*)urlString
parameters:(NSDictionary
*)parameters
delegate:(id<NSURLSessionDelegate>)delegate
{
return [self requestJsonWithURL:[self
properURLWithPath:urlString]
parameters:parameters
delegate:delegate];
}
/**
* JSONデータをリクエストする。(プロトコル指定指定、デリゲート有)
* @param protocol プロトコル
* @param parameters パラメータ
* @param delegate デリゲート
* @param isBackground バックグランド処理有無
* @return NSURLSessionDataTaskインスタンス
*/
- (NSURLSessionDataTask *)requestJsonWithProtocol:(NSString
*)protocol
parameters:(NSDictionary
*)parameters
delegate:(id<NSURLSessionDelegate>)delegate
{
return [self requestJsonWithURLString:[self
properPathWithProtocol:protocol]
parameters:parameters
delegate:delegate];
}
#pragma mark - DownloadImageWithBlock
/**
* イメージををダウンロードする。
* @param urlString URL(文字列)
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return 無し
*/
- (void)downloadImageWithURL:(NSString *)urlString
success:(NetworkImageSuccessBlock)success
failure:(NetworkImageFailureBlock)failure
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration
defaultSessionConfiguration];
NSURLSession *session = [NSURLSession
sessionWithConfiguration:config];
// NSURLSessionDataTaskクラスを使用する
[self manageActivityCountUp:YES];
[[session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response,
NSError *error) {
[self manageActivityCountUp:NO];
NSString *message = nil;
// HTTPステータスコード「200」以外は、エラーとする
NSInteger statusCode = ((NSHTTPURLResponse
*)response).statusCode;
if (statusCode == 200) {
if (data && !error) {
UIImage *image = [UIImage
imageWithData:data];
if (image) success(image);
else failure(@"イメージの取得に失敗しました。",
error);
}
else {
if (error) {
message = (error.code ==
kCFURLErrorCancelled)?
@"キャンセルされました。":
[NSString
stringWithFormat:kCFNetworkErrorsMessage, (long)error.code];
}
failure(message, error);
}
}
else {
message = [NSString
stringWithFormat:kHttpStatusCodesErrorMessage, (long)statusCode];
failure(message, error);
}
[session invalidateAndCancel];
}] resume];
}
#pragma mark - DownloadFileWithBlock
/**
* ファイルをダウンロードする。(プログレス非表示)
* @param urlString URL文字列
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDownloadTaskインスタンス
*/
- (NSURLSessionDownloadTask *)downloadFileWithURL:(NSString
*)urlString
success:(NetworkFileSuccessBlock)success
failure:(NetworkFileFailureBlock)failure
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration
defaultSessionConfiguration];
NSURLSession *session = [NSURLSession
sessionWithConfiguration:config];
[self manageActivityCountUp:YES];
NSURLSessionDownloadTask *task =
[session downloadTaskWithURL:url
completionHandler:^(NSURL *location, NSURLResponse
*response, NSError *error) {
[self manageActivityCountUp:NO];
/*
即、キャンセルすると、ステータスコードは「0」となる為、
HTTPステータスコードではなく、まずNSErrorで判定しないと、キャンセルが判断できない。
また、URL指定間違い時等、初回?だけ、NSErrorのインスタンスはnilとなるので、
ステータスコードによる判定も必要となる。2回目以降は、NSErrorによる判定でOK。
エラーの詳細は、CFNetworkErrors.h 参照。
*/
NSString *message = nil;
if (error) {
// キャンセルの場合
if (error.code == kCFURLErrorCancelled) {
message = @"キャンセルされました。";
}
// 上記以外の場合
else {
message = [NSString
stringWithFormat:kCFNetworkErrorsMessage, (long)error.code];
}
failure(message, error);
}
else {
// HTTPステータスコードが「200」以外はエラーとする
NSInteger statusCode = ((NSHTTPURLResponse
*)response).statusCode;
if (statusCode == 200) {
if (location) {
success(location);
}
}
else {
message = [NSString
stringWithFormat:kHttpStatusCodesErrorMessage, (long)statusCode];
// message =
[NSHTTPURLResponse localizedStringForStatusCode:statusCode];
failure(message, nil);
}
}
[session invalidateAndCancel];
}];
[task resume];
return task;
}
#pragma mark - DownloadFileWithDelegates
/**
* ファイルをダウンロードする。(デリゲート有)
* @param urlString URL文字列
* @param delegate デリゲート
* @param success 成功ブロック
* @param failure 失敗ブロック
* @return NSURLSessionDownloadTaskインスタンス
*/
- (NSURLSessionDownloadTask *)downloadFileWithURL:(NSString
*)urlString
delegate:(id<NSURLSessionDelegate>)delegate
background:(BOOL)isBackground
{
NSURL *url = [NSURL URLWithString:urlString];
// バックグランド有無により、切換える
NSURLSessionConfiguration *config = (isBackground)?
// [NSURLSessionConfiguration
backgroundSessionConfiguration:@"backgroundTask"]:
//------iOS9対応-------//
[NSURLSessionConfiguration
backgroundSessionConfigurationWithIdentifier:@"backgroundTask"]:
[NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession
sessionWithConfiguration:config
delegate:delegate
delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionDownloadTask *task = [session
downloadTaskWithURL:url];
[task resume];
return task;
}
@end
#import <UIKit/UIKit.h>
#import "NetworkManager.h"
#import "SVProgressHUD.h"
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UISwitch *demoSwitch;
@property (strong, nonatomic) NSURLSessionDataTask
*sessionDataTask;
@property (weak, nonatomic) IBOutlet UITextField *urlTextField;
@property (weak, nonatomic) IBOutlet UITextView *textView;
@property (weak, nonatomic) IBOutlet UITextField *idTextField;
@property (weak, nonatomic) IBOutlet UITextField *pwTextField;
- (IBAction)didTouchButton:(UIButton *)sender;
@end
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a
nib.
_urlTextField.text =
@"https://shwww.smd.sekisuihouse.co.jp/iJsonParser3/";
_idTextField.text = @"kt01";
_pwTextField.text = @"111";
_textView.text = @"";
_demoSwitch.on = NO;
NetworkManager *nm = [NetworkManager sharedManager];
nm.baseURL = _urlTextField.text;
nm.baseURL4Simulator = _urlTextField.text;
nm.urlParameterType = NMUrlParameterTypeString;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)didTouchButton:(UIButton *)sender
{
_textView.text = @"";
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(hudTapped:)
name:SVProgressHUDDidTouchDownInsideNotification object:nil];
[SVProgressHUD showWithStatus:@"通信中"
maskType:SVProgressHUDMaskTypeGradient];
NSString *protocol = @"loginAction.do";
NSDictionary *parameters = @{@"privateId": _idTextField.text,
@"password": _pwTextField.text};
NetworkManager *nm = [NetworkManager sharedManager];
nm.baseURL = _urlTextField.text;
nm.baseURL4Simulator = _urlTextField.text;
nm.isDemoMode = _demoSwitch.isOn;
typeof(self) __weak wself = self;
_sessionDataTask = [nm requestJsonWithProtocol:protocol
parameters:parameters
success:^(id json) {
// 成功の場合
NSDictionary *dict =
json;
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD
dismiss];
[wself.textView
setContentOffset:CGPointZero animated:YES];
wself.textView.text =
dict.description;
[wself
finishNetwork];
});
dict = nil;
}
failure:^(NSString *message,
NSError *error) {
if (error.code ==
kCFURLErrorCancelled) {
// キャンセルの場合
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD
showErrorWithStatus:message];
[wself
finishNetwork];
});
} else {
// 通信エラー等の場合
dispatch_async(dispatch_get_main_queue(), ^{
[SVProgressHUD
showErrorWithStatus:message];
[wself
finishNetwork];
});
}
}];
}
/**
* 通信終了処理を行う
*/
- (void)finishNetwork
{
// 通知削除
[[NSNotificationCenter defaultCenter] removeObserver:self
name:SVProgressHUDDidTouchDownInsideNotification
object:nil];
}
#pragma mark - NSNotificationCenter
/**
* 通信をキャンセルされると呼ばれる
*
* @param notification 通知
*/
- (void)hudTapped:(NSNotification *)notification
{
if (_sessionDataTask) {
[_sessionDataTask cancel];
_sessionDataTask = nil;
}
[SVProgressHUD dismiss];
[self finishNetwork];
}
@end
SVProgressHUD.h
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
#import "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive
state. This can occur for certain types of temporary interruptions (such as an
incoming phone call or SMS message) or when the user quits the application and
it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and
invalidate graphics rendering callbacks. Games should use this method to pause
the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data,
invalidate timers, and store enough application state information to restore
your application to its current state in case it is terminated later.
// If your application supports background execution, this method is
called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the active
state; here you can undo many of the changes made on entering the
background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the
application was inactive. If the application was previously in the background,
optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if
appropriate. See also applicationDidEnterBackground:.
}
@end
#import "UnevennessSettingViewController.h"
#import "UnevennessRankDataCtrl.h"
/**
* 凹凸基準設定画面
*/
@implementation UnevennessSettingViewController
#pragma mark - Override
/**
* ロード時に呼ばれる
*/
- (void)viewDidLoad
{
[super viewDidLoad];
// 「初期設定に戻す」ボタン
NSString *imageName = NSLocalizedString(@"T_RES_BTN_DEFAULT",
@"T_RES_BTN_DEFAULT");
UIImage *image = [UIImage imageNamed:NSLocalizedString(imageName,
imageName)];
[_defaultSettingButton setImage:image
forState:UIControlStateNormal];
imageName = NSLocalizedString(@"T_RES_BTN_DEFAULT_HLT",
@"T_RES_BTN_DEFAULT_HLT");
image = [UIImage imageNamed:NSLocalizedString(imageName,
imageName)];
[_defaultSettingButton setImage:image
forState:UIControlStateHighlighted];
// 保存ボタン
imageName = NSLocalizedString(@"T_RES_SAVE_MENTE",
@"T_RES_SAVE_MENTE");
image = [UIImage imageNamed:NSLocalizedString(imageName,
imageName)];
[_saveButton setImage:image forState:UIControlStateNormal];
imageName = NSLocalizedString(@"T_RES_SAVE_MENTE_HLT",
@"T_RES_SAVE_MENTE_HLT");
image = [UIImage imageNamed:NSLocalizedString(imageName,
imageName)];
[_saveButton setImage:image forState:UIControlStateHighlighted];
// 設定モード(デフォルト、凹設定とする)
_currentSetMode = UnevennessSettingViewControllerModeSetDent;
// 凹凸閾値情報
NSDictionary *info =
@{
// 凹ランク閾値
DentThreshold12: @"112",
DentThreshold23: @"104",
DentThreshold34: @"96",
DentThreshold45: @"88",
// 凸ランク閾値
BumpThreshold12: @"100",
BumpThreshold23: @"94",
BumpThreshold34: @"87",
BumpThreshold45: @"80"
};
_defaultThresholdInfo = [NSMutableDictionary
dictionaryWithDictionary:info];
_currentThresholdInfo = [NSMutableDictionary
dictionaryWithDictionary:info];
// 既に保存データがあれば、上記情報を上書きする
NSDictionary *thresholdInfo = [UnevennessRankDataCtrl
loadUnevennessThresholdInfo];
if (thresholdInfo) {
_currentThresholdInfo = [NSMutableDictionary
dictionaryWithDictionary:thresholdInfo];
}
// 凹凸タブ
NSArray *labels = @[_dentLabel, _bumpLabel];
for (UILabel *label in labels) {
UITapGestureRecognizer *tapGestureRecognizer =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(detectedTapGesture:)];
tapGestureRecognizer.numberOfTapsRequired = 1;
[label addGestureRecognizer:tapGestureRecognizer];
label.userInteractionEnabled = YES;
[label drawBorderWithColor:[UIColor clearColor] width:1.0f
radius:8.0f];
}
[self updateUnevennessSettingView];
}
/**
* メモリ警告時に呼ばれる
*/
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - Private
/**
* 凹凸基準設定画面を更新する
*/
- (void)updateUnevennessSettingView
{
BOOL isSetDentMode = (_currentSetMode ==
UnevennessSettingViewControllerModeSetDent);
NSString *keyThreshold12 = @"";
NSString *keyThreshold23 = @"";
NSString *keyThreshold34 = @"";
NSString *keyThreshold45 = @"";
if (isSetDentMode) {
// 凹の場合
keyThreshold12 = DentThreshold12;
keyThreshold23 = DentThreshold23;
keyThreshold34 = DentThreshold34;
keyThreshold45 = DentThreshold45;
}
else {
// 凸の場合
keyThreshold12 = BumpThreshold12;
keyThreshold23 = BumpThreshold23;
keyThreshold34 = BumpThreshold34;
keyThreshold45 = BumpThreshold45;
}
// ラベル表示
_thresholdRank12Label.text =
_currentThresholdInfo[keyThreshold12];
_thresholdRank23Label.text =
_currentThresholdInfo[keyThreshold23];
_thresholdRank34Label.text =
_currentThresholdInfo[keyThreshold34];
_thresholdRank45Label.text =
_currentThresholdInfo[keyThreshold45];
// スライダー表示
_thresholdRank12Slider.value =
_thresholdRank12Label.text.floatValue;
_thresholdRank23Slider.value =
_thresholdRank23Label.text.floatValue;
_thresholdRank34Slider.value =
_thresholdRank34Label.text.floatValue;
_thresholdRank45Slider.value =
_thresholdRank45Label.text.floatValue;
// 凹凸タブ表示
UIColor *selectedTextColor = [UIColor hexToUIColor:@"909090"
alpha:1.0f];
UIColor *selectedBackgroundColor = [UIColor hexToUIColor:@"F2F2F2"
alpha:1.0f];
UIColor *defaultTextColor = [UIColor hexToUIColor:@"A1A1A1"
alpha:1.0f];
UIColor *defaultBackgroundColor = [UIColor hexToUIColor:@"C7C7C7"
alpha:1.0f];
UIFont *selectedFont = [UIFont boldSystemFontOfSize:21.0f];
UIFont *defaultFont = [UIFont systemFontOfSize:21.0f];
_dentLabel.textColor = (isSetDentMode)?
selectedTextColor:
defaultTextColor;
_dentLabel.backgroundColor = (isSetDentMode)?
selectedBackgroundColor:
defaultBackgroundColor;
_dentLabel.font = (isSetDentMode)?
selectedFont:
defaultFont;
_bumpLabel.textColor = (!isSetDentMode)?
selectedTextColor:
defaultTextColor;
_bumpLabel.backgroundColor = (!isSetDentMode)?
selectedBackgroundColor:
defaultBackgroundColor;
_bumpLabel.font = (!isSetDentMode)?
selectedFont:
defaultFont;
// 背景画像表示
UIImage *rankBackgroundImage = (isSetDentMode)?
[UIImage imageNamed:@"bg_convex.png"]:
[UIImage imageNamed:@"bg_depression.png"];
_rankBackgroundView.backgroundColor = [UIColor
colorWithPatternImage:rankBackgroundImage];
}
#pragma mark - UITapGestureRecognizer
/**
* タップ検出時に呼ばれる
* @param sender UITapGestureRecognizerインスタンス
* @return 無し
*/
- (void)detectedTapGesture:(UITapGestureRecognizer *)sender
{
UIView *view = sender.view;
if (! [view isMemberOfClass:[UILabel class]]) {
return;
}
UILabel *label = (UILabel *)view;
UnevennessSettingViewControllerSetMode willSetMode = (label ==
_dentLabel)?
UnevennessSettingViewControllerModeSetDent:
UnevennessSettingViewControllerModeSetBump;
if (_currentSetMode == willSetMode) {
return;
}
_currentSetMode = willSetMode;
[self updateUnevennessSettingView];
}
#pragma mark - IBAction
/**
* メニューボタンをタップ時に呼ばれる
* @param sender UIButtonインスタンス
*/
- (IBAction)didTouchMenuButton:(UIButton *)sender
{
NSArray *viewControllers =
self.navigationController.viewControllers;
if (viewControllers.count > 1) {
[self.navigationController
popToViewController:self.navigationController.viewControllers[1]
animated:YES];
} else {
[self.navigationController popViewControllerAnimated:YES];
}
}
/**
* ログアウトボタンをタップ時に呼ばれる
* @param sender UIButtonインスタンス
*/
- (IBAction)didTouchLogoutButton:(UIButton *)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
/**
* 「初期設定に戻す」ボタンをタップ時に呼ばれる
* @param sender UIButtonインスタンス
*/
- (IBAction)didTouchDefaultSettingButton:(UIButton *)sender
{
if (_currentSetMode == UnevennessSettingViewControllerModeSetDent)
{
// 凹の場合
_currentThresholdInfo[DentThreshold12] =
_defaultThresholdInfo[DentThreshold12];
_currentThresholdInfo[DentThreshold23] =
_defaultThresholdInfo[DentThreshold23];
_currentThresholdInfo[DentThreshold34] =
_defaultThresholdInfo[DentThreshold34];
_currentThresholdInfo[DentThreshold45] =
_defaultThresholdInfo[DentThreshold45];
}
else {
// 凸の場合
_currentThresholdInfo[BumpThreshold12] =
_defaultThresholdInfo[BumpThreshold12];
_currentThresholdInfo[BumpThreshold23] =
_defaultThresholdInfo[BumpThreshold23];
_currentThresholdInfo[BumpThreshold34] =
_defaultThresholdInfo[BumpThreshold34];
_currentThresholdInfo[BumpThreshold45] =
_defaultThresholdInfo[BumpThreshold45];
}
[self updateUnevennessSettingView];
}
/**
* 保存ボタンをタップ時に呼ばれる
* @param sender UIButtonインスタンス
*/
- (IBAction)didTouchSaveButton:(UIButton *)sender
{
// 保存データ取得後、対象データのみを更新する
NSDictionary *thresholdInfo = [UnevennessRankDataCtrl
loadUnevennessThresholdInfo];
NSMutableDictionary *info = [NSMutableDictionary
dictionaryWithDictionary:thresholdInfo];
if (_currentSetMode == UnevennessSettingViewControllerModeSetDent)
{
// 凹の場合
info[DentThreshold12] = _thresholdRank12Label.text;
info[DentThreshold23] = _thresholdRank23Label.text;
info[DentThreshold34] = _thresholdRank34Label.text;
info[DentThreshold45] = _thresholdRank45Label.text;
}
else {
// 凸の場合
info[BumpThreshold12] = _thresholdRank12Label.text;
info[BumpThreshold23] = _thresholdRank23Label.text;
info[BumpThreshold34] = _thresholdRank34Label.text;
info[BumpThreshold45] = _thresholdRank45Label.text;
}
NSDictionary *imInfo = [NSDictionary
dictionaryWithDictionary:info];
[UnevennessRankDataCtrl updateUnevennessThresholdInfo:imInfo];
typeof(self) __weak wself = self;
dispatch_async(dispatch_get_main_queue(), ^{
[wself.navigationController popViewControllerAnimated:YES];
});
}
/**
* スライダーを移動時に呼ばれる
* @param sender UISliderインスタンス
*/
- (IBAction)didSliderValueChanged:(UISlider *)sender
{
NSString *text = [NSString stringWithFormat:@"%.f",
sender.value];
NSString *key = @"";
NSInteger threshold12 = _thresholdRank12Label.text.integerValue;
NSInteger threshold23 = _thresholdRank23Label.text.integerValue;
NSInteger threshold34 = _thresholdRank34Label.text.integerValue;
NSInteger threshold45 = _thresholdRank45Label.text.integerValue;
if (_currentSetMode == UnevennessSettingViewControllerModeSetDent)
{
// 凹の場合
if (sender == _thresholdRank12Slider) {
// ランク1、2間の閾値の場合
if (sender.value <= threshold23) {
// 上下の閾値を超過(同一含)しないように抑制する(以降、同様)
sender.value = threshold23 + 1;
text = @(threshold23 + 1).stringValue;
}
key = DentThreshold12;
}
else if (sender == _thresholdRank23Slider) {
// ランク2、3間の閾値の場合
if (sender.value <= threshold34) {
sender.value = threshold34 + 1;
text = @(threshold34 + 1).stringValue;
} else if (sender.value >= threshold12) {
sender.value = threshold12 - 1;
text = @(threshold12 - 1).stringValue;
}
key = DentThreshold23;
}
else if (sender == _thresholdRank34Slider) {
// ランク3、4間の閾値の場合
if (sender.value <= threshold45) {
sender.value = threshold45 + 1;
text = @(threshold45 + 1).stringValue;
} else if (sender.value >= threshold23) {
sender.value = threshold23 - 1;
text = @(threshold23 - 1).stringValue;
}
key = DentThreshold34;
}
else if (sender == _thresholdRank45Slider) {
// ランク4、5間の閾値の場合
if (sender.value >= threshold34) {
sender.value = threshold34 - 1;
text = @(threshold34 - 1).stringValue;
}
key = DentThreshold45;
}
else {
return;
}
}
else {
// 凸の場合
if (sender == _thresholdRank12Slider) {
if (sender.value <= threshold23) {
sender.value = threshold23 + 1;
text = @(threshold23 + 1).stringValue;
}
key = BumpThreshold12;
}
else if (sender == _thresholdRank23Slider) {
if (sender.value <= threshold34) {
sender.value = threshold34 + 1;
text = @(threshold34 + 1).stringValue;
} else if (sender.value >= threshold12) {
sender.value = threshold12 - 1;
text = @(threshold12 - 1).stringValue;
}
key = BumpThreshold23;
}
else if (sender == _thresholdRank34Slider) {
if (sender.value <= threshold45) {
sender.value = threshold45 + 1;
text = @(threshold45 + 1).stringValue;
} else if (sender.value >= threshold23) {
sender.value = threshold23 - 1;
text = @(threshold23 - 1).stringValue;
}
key = BumpThreshold34;
}
else if (sender == _thresholdRank45Slider) {
if (sender.value >= threshold34) {
sender.value = threshold34 - 1;
text = @(threshold34 - 1).stringValue;
}
key = BumpThreshold45;
}
else {
return;
}
}
_currentThresholdInfo[key] = text;
[self updateUnevennessSettingView];
}
@end
最終更新:2019年05月28日 22:20