temp

 
#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