1. 이전 포스팅 확인하기

 

https://growingsaja.tistory.com/945

 

[Objective-C] 앱 만들기 입문 - 39 : 선물 futures 괴리율 개요 서비스 개발 3 - 정보 가공해 노출

1. 이전 포스팅 확인하기 https://growingsaja.tistory.com/944 2. 작업 전 앱 실행 결과 화면 3. 이번 목표 a. 우측에 데이터 노출 고가 Futures가 있는 A 거래소 이미지 / A거래소 Future의 괴리율 / A거래소의 Spot

growingsaja.tistory.com

 

 

 

 

 

2. 목표

 

  a. default.json 데이터 model 설계 소스 파일 제작

  b. 그를 대비한 Model 설계 소스 파일 제작

  c. dictionary 데이터에 직접 붙어서 데이터를 가져오는 방식이 아닌, 사전에 세팅한 형식으로 불러와 사용하기 구현

 

 

    - 추후에는 Model 구조를 만들어서, NSDictionary로 방대한 데이터를 받아 처리하는 부분을 수정할 예정입니다. 현재 아래와 같은 오류와 함께 앱이 갑자기 죽어버리는 현상이 있는데, 이것이 그와 관련있는 것으로 예상되어서 진행합니다.

Thread 1: EXC_BAD_ACCESS (code=1, address=0xc9aa2f054390)

    - 해당 오류가 아니더라도 더 방대해질 데이터를 불안정한 상태로 관리하고 활용하는 구조인 듯 하여 개선 작업을 진행합니다.

 

 

 

 

 

3. default.json 수정 : rates information & fiatList 부분 정보 부분 수정

 

// vim default.json



// ...



    "ratesInfo": {
        "apiInfo": {
            "OpenExchangeRates":  {
                "key": "jf294pg834ahltga34l32hi",
                "url": "https://openexchangerates.org/api/latest.json",
                "image": "apiOpenExchangeRates.png"
            },
            "KoreaExim": {
                "key": "nkfbsjurhg49832guh2ofdgrr",
                "url": "https://www.koreaexim.go.kr/site/program/financial/exchangeJSON",
                "image": ""
            },
            "DunamuQuotation": {
                "key": "fj4o387ywt4ohlsu3ih5944gjiod",
                "url": "https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes=FRX.",
                "image": "apiHanaBank.png"
            }
        },
        "fiatList": ["EUR", "JPY", "GBP", "CHF", "CAD", "AUD", "CNY", "HKD", "SEK", "NZD", "KRW", "SGD", "NOK", "MXN", "INR", "RUB", "ZAR", "TRY", "BRL", "AED", "BHD", "BND", "CNH", "CZK", "DKK", "IDR", "ILS", "MYR", "QAR", "SAR", "THB", "TWD", "CLP", "COP", "EGP", "HKD", "HUF", "KWD", "OMR", "PHP", "PLN", "PKR", "RON", "BRL", "BDT", "DZD", "ETB", "FJD", "JOD", "KES", "KHR", "KZT", "LKR", "LYD", "MMK", "MNT", "MOP", "NPR", "TZS", "UZS", "VND"]
    },
    
    
    
// ...

 

 

 

 

 

4. 반복되는 형태의 rates info api 데이터 model 설계

 

// vim RatesApiInfoModel.h

@interface RatesApiInfoModel : NSObject

@property (copy, nonatomic) NSString *key;
@property (copy, nonatomic) NSString *url;
@property (copy, nonatomic) NSString *image;

-(instancetype) initWithDictionary: (NSDictionary *)dictionary;

@end

 

// vim RatesApiInfoModel.m

// Foundation 프레임워크를 가져옵니다. Foundation 프레임워크는 애플리케이션 또는 시스템에서 사용하는 기본 기능이 포함되어 있는 라이브러리입니다.
#import <Foundation/Foundation.h>
// 헤더파일을 가져옵니다. 이 파일은 현재 구현하고 있는 클래스의 선언을 포함하고 있습니다.
#import "RatesApiInfoModel.h"

// 클래스의 구현을 시작한다는 것을 나타냅니다.
@implementation RatesApiInfoModel

// 메서드를 정의하고 있습니다. 이 메서드는 초기화에 사용되는 메서드로, NSDictionary 타입의 dictionary 매개변수를 받아 클래스의 인스턴스를 초기화합니다.
- (instancetype) initWithDictionary:(NSDictionary *)dictionary {
    // 상위 클래스의 init 메서드를 호출합니다. self는 현재 객체 인스턴스를 참조하는 포인터입니다.
    self = [super init];
    // init 메서드에 의해 반환된 값이 nil이 아닌 경우, 코드 블록 안에 있는 로직을 실행하도록 합니다. 즉, 초기화 작업이 성공적으로 수행된 경우 객체 인스턴스를 초기화할 로직을 수행합니다.
    if (self) {
        // 객체의 프로퍼티 값을 dictionary에 있는 값으로 설정합니다. 이렇게 함으로써 해당 객체의 각 프로퍼티를 초기화하게 됩니다.
        _key = [dictionary objectForKey:@"key"];
        _url = [dictionary objectForKey:@"url"];
        _image = [dictionary objectForKey:@"image"];
    }
    // 초기화된 객체 인스턴스를 반환합니다.
    return self;
}

// 금까지 작성한 RatesApiInfoModel 클래스의 구현을 완료한다는 것을 나타냅니다.
@end

 

 

 

 

 

5. 기존 rates info 정보 가져오는걸, 위에 설계한 model 토대로 불러오는 기능 구현

 

// vim RatesInfo.h

#import "RatesApiInfoModel.h"

@interface RatesInfo: NSObject

@property (readwrite, strong, nonatomic) NSArray *fiatList;
@property (readwrite, strong, nonatomic) RatesApiInfoModel *openExchangeRates;
@property (readwrite, strong, nonatomic) RatesApiInfoModel *dunamuQuotation;
@property (readwrite, strong, nonatomic) RatesApiInfoModel *koreaExim;


+(instancetype) sharedInstance;

@end

 

// vim RatesInfo.m

#import <Foundation/Foundation.h>
#import "RatesInfo.h"
#import "CRTJSONReader.h"

@implementation RatesInfo

+(instancetype)sharedInstance {
    static RatesInfo *sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[RatesInfo alloc] init];
        [sharedInstance loadFile];
    });
    return sharedInstance;
}

-(void)loadFile {
    // 설정 파일을 로드하는 코드를 작성하십시오.
    CRTJSONReader *defaultInfo = [CRTJSONReader sharedInstance];
    [defaultInfo tryReadJsonFile:@"default.json"];
    NSDictionary *ratesInfo = [defaultInfo.loadData objectForKey:@"ratesInfo"];
    // 취급 법정화폐 목록
    _fiatList = [ratesInfo objectForKey:@"fiatList"];
    // 환율
    NSDictionary *ratesApiInfo = [ratesInfo objectForKey:@"apiInfo"];
    _openExchangeRates = [[RatesApiInfoModel alloc] initWithDictionary:ratesApiInfo[@"OpenExchangeRates"]];
    _dunamuQuotation = [[RatesApiInfoModel alloc] initWithDictionary:ratesApiInfo[@"DunamuQuotation"]];
    _koreaExim = [[RatesApiInfoModel alloc] initWithDictionary:ratesApiInfo[@"KoreaExim"]];
}

@end

 

 

 

 

 

6. OpenExchangeRates 기능에서 변경사항 반영

 

 - 아래 2가지로 업데이트 진행

ratesInfo.openExchangeRates;

ratesInfo.fiatList;

// vim OpenExchangeRates.h

@interface OpenExchangeRates : NSObject

// ****** 활용하게 될 krw 관련 주요 데이터 ****** //
// 최신 정보가 업데이트된 시간
@property (readwrite, strong, nonatomic) NSString *recentUpdateDatetime;
// 최신 usdkrw 환율
@property (readwrite, strong, nonatomic) NSString *usdkrw;
// 최신 usdkrw 환율 기준 단위 - ex. USD
@property (readwrite, strong, nonatomic) NSString *paymentCurrency;
// 출처 = OpenExchangeRates
@property (readwrite, strong, nonatomic) NSString *provider;

// ****** 활용하게 될 글로벌 관련 주요 데이터 ****** //
// 최신 여러 currency 환율
@property (readwrite, strong, nonatomic) NSMutableDictionary *usdRates;

+(instancetype)sharedInstance;
-(void)fetchDataWithCompletion;

@end

 

// vim OpenExchangeRates.m

#import <Foundation/Foundation.h>
#import "OpenExchangeRates.h"
// api 통신
#import "APIManager.h"
// api 정보 가져오기 위해
#import "RatesInfo.h"
// unix를 string으로 timestamp 데이터 변경
#import "CRTunixToString.h"

@implementation OpenExchangeRates

+(instancetype)sharedInstance {
    
    static OpenExchangeRates *sharedInstance = nil;
    static dispatch_once_t oneToken;
    dispatch_once(&oneToken, ^{
        sharedInstance = [[self alloc] init];
        sharedInstance.usdRates = [@{} mutableCopy];
    });
    return sharedInstance;
}

// 매 1시간마다 업데이트되며, 00분 00초부터 00분 30초 사이에 업데이트된 수치가 노출됨
-(void)fetchDataWithCompletion {
    // **************************************** [Start] api 콜 준비 **************************************** //
    RatesInfo *ratesInfo = [RatesInfo sharedInstance];
    RatesApiInfoModel *openExchangeRates = ratesInfo.openExchangeRates;
    NSArray *paymentCurrencyList = ratesInfo.fiatList;
    APIManager* tryApiCall = [APIManager sharedInstance];
    // **************************************** [Start] Binance 데이터 가져오기 **************************************** //
    NSString *apiURL = [openExchangeRates.url stringByAppendingString:@"?app_id="];
    apiURL = [apiURL stringByAppendingString:openExchangeRates.key];
    [tryApiCall fetchDataFromAPI:apiURL withCompletionHandler:^(NSDictionary *jsonResponse, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error.localizedDescription);
        } else {
            // 여기에서 jsonResponse를 가공 한 후 앱에서 사용하실 수 있습니다.
            if ([[jsonResponse allKeys] containsObject:@"error"]) {
                // error 발생한 경우 error, status, message라는 키값을 포함합니다.
                NSLog(@"[ERROR] status code 4** error");
            } else {
                // 에러가 발생하지 않은 경우 error, status, message라는 키값을 가지지 않으며 timestamp, base, rates라는 키값을 포함합니다.
                // ****** api return된 timestamp 가져와서 string으로 변경 = 환율 최신 수치 ****** //
                NSNumber *unixTimestampRecent = jsonResponse[@"timestamp"];
                // unix를 string으로 바꾸기
                CRTunixToString *updateDatetime = [CRTunixToString sharedInstance];
                [updateDatetime stringFromUnix:unixTimestampRecent andFormat:@"yyyy-MM-dd HH:mm:ss"];
                if ([self.recentUpdateDatetime isEqual:updateDatetime.stringDateTime]) {
                    // " 내 최근 update 시간 == api 최신 update 시간 " 인 경우
                    // 최근 업데이트 시간과 같으면 어차피 같은 데이터이므로 업데이트 미진행
                    // 업데이트할게 없음. api call을 더 적게 해야한다고 알리는 NSLog입니다.
                    // 1달에 1,000건만 가능하니까 어차피 업데이트할 게 없는 상황인데도 api call을 했기 때문에 여기 WARN 문구를 출력합니다.
                    NSLog(@"[WARN] OpenExchangeRates API Call Is Wasted! recentUpdateTime: %@, now: %@", self.recentUpdateDatetime, updateDatetime.stringDateTime);
                }
                NSLog(@"[INFO] OpenExchangeRates update confirmed! recentUpdateTime : %@, now: %@", self.recentUpdateDatetime, updateDatetime.stringDateTime);
                // 최근 환율 업데이트 시간 변경됨 감지
                // 최근 업데이트 시간 최신화 from api
                self.recentUpdateDatetime = updateDatetime.stringDateTime;
                // 최근 업데이트 환율값 최신화 (소수점 2자리까지 반올림 진행)
                NSDictionary *ratesNow = jsonResponse[@"rates"];
                
                for (NSString *paymentCurrency in paymentCurrencyList) {
                    // 글로벌 환율 size에 따라 반올림해서 저장 진행
                    float usdRateFloat = [ratesNow[paymentCurrency] floatValue];
                    if (usdRateFloat >= 10000) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.1f", usdRateFloat];
                    } else if (usdRateFloat >= 1000) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.2f", usdRateFloat];
                    } else if (usdRateFloat >= 100) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.3f", usdRateFloat];
                    } else if (usdRateFloat >= 10) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.4f", usdRateFloat];
                    } else if (usdRateFloat >= 1) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.5f", usdRateFloat];
                    } else if (usdRateFloat >= 0.1) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.6f", usdRateFloat];
                    } else if (usdRateFloat >= 0.01) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.7f", usdRateFloat];
                    } else if (usdRateFloat >= 0.001) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.8f", usdRateFloat];
                    } else if (usdRateFloat >= 0.0001) {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%.9f", usdRateFloat];
                    } else {
                        self.usdRates[paymentCurrency] = [NSString stringWithFormat:@"%f", usdRateFloat];
                    }
                }
                // 한국 환율
                float usdkrwFloat = [ratesNow[@"KRW"] floatValue];
                if (usdkrwFloat >= 10000) {
                    self.usdkrw = [NSString stringWithFormat:@"%.1f", usdkrwFloat];
                } else if (usdkrwFloat >= 1000) {
                    self.usdkrw = [NSString stringWithFormat:@"%.2f", usdkrwFloat];
                } else if (usdkrwFloat >= 100) {
                    self.usdkrw = [NSString stringWithFormat:@"%.3f", usdkrwFloat];
                } else if (usdkrwFloat >= 10) {
                    self.usdkrw = [NSString stringWithFormat:@"%.4f", usdkrwFloat];
                } else if (usdkrwFloat >= 1) {
                    self.usdkrw = [NSString stringWithFormat:@"%.5f", usdkrwFloat];
                } else if (usdkrwFloat >= 0.1) {
                    self.usdkrw = [NSString stringWithFormat:@"%.6f", usdkrwFloat];
                } else if (usdkrwFloat >= 0.01) {
                    self.usdkrw = [NSString stringWithFormat:@"%.7f", usdkrwFloat];
                } else if (usdkrwFloat >= 0.001) {
                    self.usdkrw = [NSString stringWithFormat:@"%.8f", usdkrwFloat];
                } else if (usdkrwFloat >= 0.0001) {
                    self.usdkrw = [NSString stringWithFormat:@"%.9f", usdkrwFloat];
                } else {
                    self.usdkrw = [NSString stringWithFormat:@"%f", usdkrwFloat];
                }
                // payment currency 최신화 (ex.KRW)
                self.paymentCurrency = @"KRW";
                // 출처
                self.provider = @"OpenExchangeRates";
            }
        }
    }];
}
@end

 

 

 

 

 

7. DunamuQuotation 기능에서 변경사항 반영

 

// vim DunamuQuotation.h

@interface DunamuQuotation : NSObject

// ****** 활용하게 될 krw 관련 주요 데이터 ****** //
// 최근 데이터 일시
@property (readwrite, strong, nonatomic) NSString *recentDateTime;
// 최근 데이터 환율
@property (readwrite, strong, nonatomic) NSString *usdkrw;
// 최근 데이터 거래 기준 화폐
@property (readwrite, strong, nonatomic) NSString *paymentCurrency;
// 시가
@property (readwrite, strong, nonatomic) NSString *openUsdkrw;
// 한국 기준 오늘의 변동가
@property (readwrite, strong, nonatomic) NSString *changeUsdkrw;
// 한국 기준 오늘의 변동률
@property (readwrite, strong, nonatomic) NSString *changePercentUsdkrw;
// 출처
@property (readwrite, strong, nonatomic) NSString *provider;

// ****** 활용하게 될 글로벌 관련 주요 데이터 ****** //
// 최신 여러 currency 환율
@property (readwrite, strong, nonatomic) NSMutableDictionary *ratesData;


+(instancetype)sharedInstance;
-(void)fetchDataWithCompletion;

@end

 

// vim DunamuQuotation.m

#import <Foundation/Foundation.h>
#import "DunamuQuotation.h"
// api 통신
#import "APIManager.h"
// 정보 가져오기
#import "RatesInfo.h"

@implementation DunamuQuotation

+(instancetype)sharedInstance {
    
    static DunamuQuotation *sharedInstance = nil;
    static dispatch_once_t oneToken;
    dispatch_once(&oneToken, ^{
        sharedInstance = [[self alloc] init];
        sharedInstance.ratesData = [@{} mutableCopy];
        sharedInstance.ratesData[@"recentUsdRates"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"recentOpenUsdRates"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"recentUsdChange"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"recentUsdChangePercent"] = [@{} mutableCopy];
        // krw 기본 정보
        sharedInstance.ratesData[@"country"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"provider"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"currencyName"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"currencyUnit"] = [@{} mutableCopy];
        // krw 기준
        sharedInstance.ratesData[@"recentKrwRates"] = [@{} mutableCopy];
        // KRW api에서의 정보
        sharedInstance.ratesData[@"recentOpenKrwRates"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"recentKrwChange"] = [@{} mutableCopy];
        sharedInstance.ratesData[@"recentKrwChangePercent"] = [@{} mutableCopy];
    });
    return sharedInstance;
}

// 매 1시간마다 업데이트되며, 00분 00초부터 00분 30초 사이에 업데이트된 수치가 노출됨
-(void)fetchDataWithCompletion {
    // **************************************** [Start] api 콜 준비 **************************************** //
    RatesInfo *ratesInfo = [RatesInfo sharedInstance];
    RatesApiInfoModel *dunamuQuotation = ratesInfo.dunamuQuotation;
    NSArray *paymentCurrencyList = ratesInfo.fiatList;
    APIManager* tryApiCall = [APIManager sharedInstance];
    /* #################### [Start] open exchange rates KRW 환율 데이터 가져오기 #################### */
    NSString *apiURL = dunamuQuotation.url;
    // 1USD 당 몇KRW인지 알기 위한 url 조합
    apiURL = [apiURL stringByAppendingString:@"KRW"];
    apiURL = [apiURL stringByAppendingString:@"USD"];
    [tryApiCall fetchDataFromAPI:apiURL withCompletionHandler:^(NSDictionary *jsonResponse, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error.localizedDescription);
        } else {
            // 여기에서 jsonResponse를 가공 한 후 앱에서 사용하실 수 있습니다.
            if ([jsonResponse isKindOfClass:[NSDictionary class]]) {
                // error 발생한 경우 error, status, message라는 키값을 포함합니다.
                NSLog(@"[ERROR] DunamuQuotation status: %@, message: %@", jsonResponse[@"status"], jsonResponse[@"message"]);
            } else if ([jsonResponse isKindOfClass:[NSArray class]]) {
                // 정상 처리시, dictionary가 아니라 array입니다.
                if ([jsonResponse isEqual:@[]]) {
                    // 빈 array가 나오면 해당 api 비활성화 또는 잘못된 요청을 한 것입니다.
                    NSLog(@"[ERROR] DunamuQuotation empty array return.");
                } else {
                    // 정상 return으로 환율 정보 업데이트, 사용하기 편한 형태로 변경
                    NSDictionary *result = ((NSArray *)jsonResponse)[0];
                    // 최근 환율 업데이트 시간 정보
                    NSString *recentDateTime = [result[@"date"] stringByAppendingString:@" "];
                    recentDateTime = [recentDateTime stringByAppendingString:result[@"time"]];
                    self.recentDateTime = recentDateTime;
                    // 환율
                    float usdkrwFloat = [result[@"basePrice"] floatValue];
                    if (usdkrwFloat >= 10000) {
                        self.usdkrw = [NSString stringWithFormat:@"%.1f", usdkrwFloat];
                    } else if (usdkrwFloat >= 1000) {
                        self.usdkrw = [NSString stringWithFormat:@"%.2f", usdkrwFloat];
                    } else if (usdkrwFloat >= 100) {
                        self.usdkrw = [NSString stringWithFormat:@"%.3f", usdkrwFloat];
                    } else if (usdkrwFloat >= 10) {
                        self.usdkrw = [NSString stringWithFormat:@"%.4f", usdkrwFloat];
                    } else if (usdkrwFloat >= 1) {
                        self.usdkrw = [NSString stringWithFormat:@"%.5f", usdkrwFloat];
                    } else if (usdkrwFloat >= 0.1) {
                        self.usdkrw = [NSString stringWithFormat:@"%.6f", usdkrwFloat];
                    } else if (usdkrwFloat >= 0.01) {
                        self.usdkrw = [NSString stringWithFormat:@"%.7f", usdkrwFloat];
                    } else if (usdkrwFloat >= 0.001) {
                        self.usdkrw = [NSString stringWithFormat:@"%.8f", usdkrwFloat];
                    } else if (usdkrwFloat >= 0.0001) {
                        self.usdkrw = [NSString stringWithFormat:@"%.9f", usdkrwFloat];
                    } else {
                        self.usdkrw = [NSString stringWithFormat:@"%f", usdkrwFloat];
                    }
                    // 환율 변동가
                    self.changeUsdkrw = [NSString stringWithFormat:@"%@", result[@"signedChangePrice"]];
                    // 한국 환율 시가 = api에서 주는 openingPrice 정보를 사용하는게 아니라 "현재가-변동가"로 계산해서 사용합니다.
                    self.openUsdkrw = [NSString stringWithFormat:@"%.2f", [self.usdkrw floatValue] - [self.changeUsdkrw floatValue]];
                    // 환율 변동률 소수 2째자리수까지 반올림
                    self.changePercentUsdkrw = [NSString stringWithFormat:@"%.2f", [result[@"signedChangeRate"] floatValue] * 100];
                    // payment currency 추출해서 저장 : KRW, EUR 등
                    // ex. "name": "미국 (USD/KRW)" => 제일 뒤에 있는 문자 )를 삭제하고, / 기준으로 뒤쪽 string 가져오기
                    self.paymentCurrency = result[@"currencyUnit"];
                    // 데이터 출처
                    self.provider = result[@"provider"];
                }
            }
        }
    }];
    
    /* #################### [Start] open exchange rates global 환율 데이터 가져오기 #################### */
    for (NSString *paymentCurrency in paymentCurrencyList) {
        apiURL = dunamuQuotation.url;
        // 1USD 당 몇{paymentCurrency}}인지 알기 위한 url 조합
        apiURL = [apiURL stringByAppendingString:paymentCurrency];
        apiURL = [apiURL stringByAppendingString:@"USD"];
        [tryApiCall fetchDataFromAPI:apiURL withCompletionHandler:^(NSDictionary *jsonResponse, NSError *error) {
            if (error) {
                NSLog(@"Error: %@", error.localizedDescription);
            } else {
                // 여기에서 jsonResponse를 가공 한 후 앱에서 사용하실 수 있습니다.
                if ([jsonResponse isKindOfClass:[NSDictionary class]]) {
                    // error 발생한 경우 error, status, message라는 키값을 포함합니다.
                    NSLog(@"[ERROR] DunamuQuotation USD status: %@, message: %@", jsonResponse[@"status"], jsonResponse[@"message"]);
                } else if ([jsonResponse isKindOfClass:[NSArray class]]) {
                    // 정상 처리시, dictionary가 아니라 array입니다.
                    if ([jsonResponse isEqual:@[]]) {
                        // 빈 array가 나오면 해당 화폐에 대한 정보를 api에서 제공하지 않는 것입니다. 해당 화폐 정보는 skip해줍니다.
                        NSLog(@"[ERROR] DunamuQuotation USD empty array return. %@", paymentCurrency);
                        self.ratesData[@"recentUsdRates"][paymentCurrency] = @"-";
                        self.ratesData[@"recentOpenUsdRates"][paymentCurrency] = @"-";
                        self.ratesData[@"recentUsdChange"][paymentCurrency] = @"-";
                        self.ratesData[@"recentUsdChangePercent"][paymentCurrency] = @"-";
                        self.ratesData[@"country"][paymentCurrency] = @"-";
                        self.ratesData[@"provider"][paymentCurrency] = @"-";
                        self.ratesData[@"currencyName"][paymentCurrency] = @"-";
                        self.ratesData[@"currencyUnit"][paymentCurrency] = @"-";
                        self.ratesData[@"recentKrwRates"][paymentCurrency] = @"-";
                    } else {
                        // 정상 return으로 환율 정보 업데이트, 사용하기 편한 형태로 변경
                        NSDictionary *result = ((NSArray *)jsonResponse)[0];
                        // 최근 환율 업데이트 시간 정보
                        NSString *recentDateTime = [result[@"date"] stringByAppendingString:@" "];
                        recentDateTime = [recentDateTime stringByAppendingString:result[@"time"]];
                        self.recentDateTime = recentDateTime;
                        // 환율
                        float usdRateFloat = [result[@"basePrice"] floatValue];
                        if (usdRateFloat >= 10000) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.1f", usdRateFloat];
                        } else if (usdRateFloat >= 1000) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.2f", usdRateFloat];
                        } else if (usdRateFloat >= 100) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.3f", usdRateFloat];
                        } else if (usdRateFloat >= 10) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.4f", usdRateFloat];
                        } else if (usdRateFloat >= 1) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.5f", usdRateFloat];
                        } else if (usdRateFloat >= 0.1) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.6f", usdRateFloat];
                        } else if (usdRateFloat >= 0.01) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.7f", usdRateFloat];
                        } else if (usdRateFloat >= 0.001) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.8f", usdRateFloat];
                        } else if (usdRateFloat >= 0.0001) {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.9f", usdRateFloat];
                        } else {
                            self.ratesData[@"recentUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%f", usdRateFloat];
                        }
                        // ****** 글로벌 각 화폐 환율 변동가 ****** //
                        self.ratesData[@"recentUsdChange"][paymentCurrency] = [NSString stringWithFormat:@"%@", result[@"signedChangePrice"]];
                        // 글로벌 각 화폐 환율 시가 = api에서 주는 openingPrice 정보를 사용하는게 아니라 "현재가-변동가"로 계산해서 사용합니다.
                        self.ratesData[@"recentOpenUsdRates"][paymentCurrency] = [NSString stringWithFormat:@"%.2f", usdRateFloat - [result[@"signedChangePrice"] floatValue]];
                        // ****** 글로벌 각 화폐 환율 변동률 소수 2째자리수까지 반올림 ****** //
                        self.ratesData[@"recentUsdChangePercent"][paymentCurrency] = [NSString stringWithFormat:@"%.2f", [result[@"signedChangeRate"] floatValue] * 100];
                        // ****** 글로벌 각 화폐의 국가 ****** //
                        if (result[@"country"] == [NSNull null]) {
                            NSString *currencyCode = result[@"currencyCode"];
                            if ([currencyCode isEqual:@"CNH"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"홍콩";
                            } else if ([currencyCode isEqual: @"CLP"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"칠레";
                            } else if ([currencyCode isEqual: @"COP"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"콜롬비아";
                            } else if ([currencyCode isEqual: @"OMR"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"오만";
                            } else if ([currencyCode isEqual: @"RON"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"루마니아";
                            } else if ([currencyCode isEqual: @"DZD"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"알제리";
                            } else if ([currencyCode isEqual: @"ETB"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"에티오피아";
                            } else if ([currencyCode isEqual: @"FJD"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"피지";
                            } else if ([currencyCode isEqual: @"KES"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"케냐";
                            } else if ([currencyCode isEqual: @"KHR"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"캄보디아";
                            } else if ([currencyCode isEqual: @"LKR"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"스리랑카";
                            } else if ([currencyCode isEqual: @"LYD"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"리비아";
                            } else if ([currencyCode isEqual: @"MMK"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"미얀마";
                            } else if ([currencyCode isEqual: @"MOP"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"마카오";
                            } else if ([currencyCode isEqual: @"NPR"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"네팔";
                            } else if ([currencyCode isEqual: @"TZS"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"탄자니아";
                            } else if ([currencyCode isEqual: @"UZS"]) {
                                self.ratesData[@"country"][paymentCurrency] = @"우즈베키스탄";
                            } else {
                                // 예외처리 목록에 없으면 currencyCode로 대체
                                self.ratesData[@"country"][paymentCurrency] = result[@"currencyCode"];
                            }
                        } else {
                            // data 있으면 그대로
                            if ([result[@"country"] isEqual:@"미국"]) {
                                // 한국 api라서 그런지, 한국KRW정보인데 미국이라고 나와서 수정 적용
                                self.ratesData[@"country"][paymentCurrency] = @"대한민국";
                            } else {
                                // 이외 api는 데이터 그대로 사용
                                self.ratesData[@"country"][paymentCurrency] = result[@"country"];
                            }
                        }
                        // ****** 데이터 출처 ****** //
                        if (result[@"provider"] == [NSNull null]) {
                            // 없으면 "-"
                            self.ratesData[@"provider"][paymentCurrency] = @"-";
                        } else {
                            // 있으면 있는거 가져오기
                            self.ratesData[@"provider"][paymentCurrency] = result[@"provider"];
                        }
                        // ****** 화폐 단위 한국어로 ****** //
                        if (result[@"currencyName"] == [NSNull null]) {
                            NSString *currencyCode = result[@"currencyCode"];
                            if ([currencyCode isEqual:@"CNH"]) {
                                self.ratesData[@"currencyName"][paymentCurrency] = @"위안";
                            } else if ([currencyCode isEqual: @"CLP"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"페소";
                           } else if ([currencyCode isEqual: @"COP"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"페소";
                           } else if ([currencyCode isEqual: @"OMR"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"리알";
                           } else if ([currencyCode isEqual: @"RON"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"레위";
                           } else if ([currencyCode isEqual: @"DZD"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"디나르";
                           } else if ([currencyCode isEqual: @"ETB"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"비르";
                           } else if ([currencyCode isEqual: @"FJD"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"달러";
                           } else if ([currencyCode isEqual: @"KES"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"실링";
                           } else if ([currencyCode isEqual: @"KHR"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"리얄";
                           } else if ([currencyCode isEqual: @"LKR"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"루피";
                           } else if ([currencyCode isEqual: @"LYD"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"디나르";
                           } else if ([currencyCode isEqual: @"MMK"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"키얏";
                           } else if ([currencyCode isEqual: @"MOP"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"파타카";
                           } else if ([currencyCode isEqual: @"NPR"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"루피";
                           } else if ([currencyCode isEqual: @"TZS"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"실링";
                           } else if ([currencyCode isEqual: @"UZS"]) {
                               self.ratesData[@"currencyName"][paymentCurrency] = @"솜";
                           } else {
                               // 예외처리 목록에 없으면 영어로 = CurrencyCode
                               self.ratesData[@"currencyName"][paymentCurrency] = result[@"currencyCode"];
                           }
                        } else {
                            // 있으면 그대로
                            self.ratesData[@"currencyName"][paymentCurrency] = result[@"currencyName"];
                        }
                    }
                }
            }
        }];
    }
    
    /* #################### [Start] open exchange rates KRW global 환율 데이터 가져오기 #################### */
    
    for (NSString *paymentCurrency in paymentCurrencyList) {
        if ([paymentCurrency isEqual:@"KRW"]) {
            // KRW는 api 미제공일뿐더러 이미 정보가 다 있어서 미진행
            self.ratesData[@"recentKrwRates"][@"KRW"] = @"1.00";
            self.ratesData[@"recentKrwChange"][@"KRW"] = @"0.00";
            self.ratesData[@"recentKrwChangePercent"][@"KRW"] = @"0.00";
            self.ratesData[@"recentOpenKrwRates"][@"KRW"] = @"1.00";
            self.ratesData[@"currencyUnit"][@"KRW"] = @1;
        } else {
            apiURL = dunamuQuotation.url;
            // 1USD 당 몇{paymentCurrency}}인지 알기 위한 url 조합
            apiURL = [apiURL stringByAppendingString:@"KRW"];
            apiURL = [apiURL stringByAppendingString:paymentCurrency];
            [tryApiCall fetchDataFromAPI:apiURL withCompletionHandler:^(NSDictionary *jsonResponse, NSError *error) {
                if (error) {
                    NSLog(@"Error: %@", error.localizedDescription);
                } else {
                    // 여기에서 jsonResponse를 가공 한 후 앱에서 사용하실 수 있습니다.
                    if ([jsonResponse isKindOfClass:[NSDictionary class]]) {
                        // error 발생한 경우 error, status, message라는 키값을 포함합니다.
                        NSLog(@"[ERROR] DunamuQuotation KRW status: %@, message: %@", jsonResponse[@"status"], jsonResponse[@"message"]);
                    } else if ([jsonResponse isKindOfClass:[NSArray class]]) {
                        // 정상 처리시, dictionary가 아니라 array입니다.
                        if ([jsonResponse isEqual:@[]]) {
                            // 빈 array가 나오면 해당 화폐에 대한 정보를 api에서 제공하지 않는 것입니다. 해당 화폐 정보는 skip해줍니다.
                            NSLog(@"[ERROR] DunamuQuotation KRW empty array return. %@", paymentCurrency);
                            self.ratesData[@"recentKrwChange"][paymentCurrency] = @"-";
                            self.ratesData[@"recentKrwChangePercent"][paymentCurrency] = @"-";
                        } else {
                            // 정상 return으로 환율 정보 업데이트, 사용하기 편한 형태로 변경
                            NSDictionary *result = ((NSArray *)jsonResponse)[0];
                            // ****** 한국돈 환전시 최소 화폐 단위 ex. 100엔당 얼마원 ****** //
                            self.ratesData[@"currencyUnit"][paymentCurrency] = result[@"currencyUnit"];
                            // ****** 한국 화폐 원 기준의 환율 호가 정보 recentKrwRates ****** //
                            float krwRateFloat;
                            if ([result[@"basePrice"]  isEqual: @0] || result[@"basePrice"] == [NSNull null]) {
                                // 0이거나 존재하지 않으면 계산해서 구해보기
                                if ([result[@"cashBuyingPrice"] floatValue] == 0 && [result[@"cashSellingPrice"] floatValue] == 0) {
                                    // cash 관련 정보로 평균치 내서 도출
                                    krwRateFloat = ([result[@"cashBuyingPrice"] floatValue] + [result[@"cashSellingPrice"] floatValue]) / 2;
                                } else {
                                    // cash 정보 없으면 그냥 0 넣어주기
                                    krwRateFloat = [@0 floatValue];
                                }
                            } else {
                                // 정상인 경우
                                if ([paymentCurrency isEqual:@"KRW"]) {
                                    // 한국은 항상 1이기 때문에 예외처리
                                    self.ratesData[@"recentKrwRates"][paymentCurrency] = @"1.00";
                                } else {
                                    // 한국 이외 국가는 계속 변동되기 때문에 계산해서 저장
                                    krwRateFloat = [result[@"basePrice"] floatValue];
                                    // 해당 값을 size에 맞게 반올림해서 저장
                                    NSString *krwRateString;
                                    if (krwRateFloat >= 10000) {
                                        krwRateString = [NSString stringWithFormat:@"%.1f", krwRateFloat];
                                    } else if (krwRateFloat >= 1000) {
                                        krwRateString = [NSString stringWithFormat:@"%.2f", krwRateFloat];
                                    } else if (krwRateFloat >= 100) {
                                        krwRateString = [NSString stringWithFormat:@"%.3f", krwRateFloat];
                                    } else if (krwRateFloat >= 10) {
                                        krwRateString = [NSString stringWithFormat:@"%.4f", krwRateFloat];
                                    } else if (krwRateFloat >= 1) {
                                        krwRateString = [NSString stringWithFormat:@"%.5f", krwRateFloat];
                                    } else if (krwRateFloat >= 0.1) {
                                        krwRateString = [NSString stringWithFormat:@"%.6f", krwRateFloat];
                                    } else if (krwRateFloat >= 0.01) {
                                        krwRateString = [NSString stringWithFormat:@"%.7f", krwRateFloat];
                                    } else if (krwRateFloat >= 0.001) {
                                        krwRateString = [NSString stringWithFormat:@"%.8f", krwRateFloat];
                                    } else if (krwRateFloat >= 0.0001) {
                                        krwRateString = [NSString stringWithFormat:@"%.9f", krwRateFloat];
                                    } else {
                                        krwRateString = [NSString stringWithFormat:@"%f", krwRateFloat];
                                    }
                                    // String 값 저장
                                    self.ratesData[@"recentKrwRates"][paymentCurrency] = krwRateString;
                                }
                                
                            }
                            // ****** 글로벌 각 화폐 환율 시작가, 변동가, 변동률 ****** //
                            if (result[@"provider"] == [NSNull null] && [result[@"signedChangePrice"] isEqual:@0]) {
                                // krw 변동 정보는 추정치임! 왜나하면 과거의 환율 정보를 알 수 없기 때문에, 현재의 환율 정보로 역추산해서 오차가 발생할 수 밖에 없음
                                // ****** krw 기준 현재 환율 가져다쓰기 ****** //
                                float krwRateFloat = [result[@"basePrice"] floatValue];
                                // 해당 값을 size에 맞게 반올림해서 저장
                                NSString *krwRateString;
                                if (krwRateFloat >= 10000) {
                                    krwRateString = [NSString stringWithFormat:@"%.1f", krwRateFloat];
                                } else if (krwRateFloat >= 1000) {
                                    krwRateString = [NSString stringWithFormat:@"%.2f", krwRateFloat];
                                } else if (krwRateFloat >= 100) {
                                    krwRateString = [NSString stringWithFormat:@"%.3f", krwRateFloat];
                                } else if (krwRateFloat >= 10) {
                                    krwRateString = [NSString stringWithFormat:@"%.4f", krwRateFloat];
                                } else if (krwRateFloat >= 1) {
                                    krwRateString = [NSString stringWithFormat:@"%.5f", krwRateFloat];
                                } else if (krwRateFloat >= 0.1) {
                                    krwRateString = [NSString stringWithFormat:@"%.6f", krwRateFloat];
                                } else if (krwRateFloat >= 0.01) {
                                    krwRateString = [NSString stringWithFormat:@"%.7f", krwRateFloat];
                                } else if (krwRateFloat >= 0.001) {
                                    krwRateString = [NSString stringWithFormat:@"%.8f", krwRateFloat];
                                } else if (krwRateFloat >= 0.0001) {
                                    krwRateString = [NSString stringWithFormat:@"%.9f", krwRateFloat];
                                } else {
                                    krwRateString = [NSString stringWithFormat:@"%f", krwRateFloat];
                                }
                                // String 값 저장
                                self.ratesData[@"recentKrwRates"][paymentCurrency] = krwRateString;
                                
                                // ****** krw 기준 과거의 환율 구해서 krw 시작 가격을 usd로부터 역추산하기 ****** //
                                float recentOpenKrwRate = [self.openUsdkrw floatValue] / [self.ratesData[@"recentOpenUsdRates"][paymentCurrency] floatValue] * [result[@"currencyUnit"] floatValue];
                                // 해당 값을 size에 맞게 반올림해서 저장
                                if (krwRateFloat >= 10000) {
                                    krwRateString = [NSString stringWithFormat:@"%.1f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 1000) {
                                    krwRateString = [NSString stringWithFormat:@"%.2f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 100) {
                                    krwRateString = [NSString stringWithFormat:@"%.3f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 10) {
                                    krwRateString = [NSString stringWithFormat:@"%.4f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 1) {
                                    krwRateString = [NSString stringWithFormat:@"%.5f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 0.1) {
                                    krwRateString = [NSString stringWithFormat:@"%.6f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 0.01) {
                                    krwRateString = [NSString stringWithFormat:@"%.7f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 0.001) {
                                    krwRateString = [NSString stringWithFormat:@"%.8f", recentOpenKrwRate];
                                } else if (krwRateFloat >= 0.0001) {
                                    krwRateString = [NSString stringWithFormat:@"%.9f", recentOpenKrwRate];
                                } else {
                                    krwRateString = [NSString stringWithFormat:@"%f", recentOpenKrwRate];
                                }
                                // String 값 저장
                                self.ratesData[@"recentOpenKrwRates"][paymentCurrency] = krwRateString;
                                
                                // ****** krw 기준 변동가 구하기 ****** //
                                float usdkrwChange = [result[@"basePrice"] floatValue] - recentOpenKrwRate;
                                self.ratesData[@"recentKrwChange"][paymentCurrency] = [NSString stringWithFormat:@"%.2f", usdkrwChange];
                                // ****** krw 기준 변동률 구하기 ****** //
                                float usdkrwChangePercent = usdkrwChange / recentOpenKrwRate * 100;
                                self.ratesData[@"recentKrwChangePercent"][paymentCurrency] = [NSString stringWithFormat:@"%.2f", usdkrwChangePercent];
                            } else {
                                // 이외의 경우 데이터 정상인 것이므로 그대로 사용
                                self.ratesData[@"recentKrwChange"][paymentCurrency] = [NSString stringWithFormat:@"%@", result[@"signedChangePrice"]];
                                self.ratesData[@"recentKrwChangePercent"][paymentCurrency] = [NSString stringWithFormat:@"%.2f", [result[@"signedChangeRate"] floatValue] * 100];
                                float recentOpenKrwRates = [result[@"basePrice"] floatValue] - [result[@"signedChangePrice"] floatValue];
                                self.ratesData[@"recentOpenKrwRates"][paymentCurrency] = [NSString stringWithFormat:@"%.2f", recentOpenKrwRates];
                            }
                        }
                    }
                }
            }];
        }
    }
    NSLog(@"[INFO] DunamuQuotation fetchDataWithCompletion Worked. => recentDateTime : %@, price : %@", self.recentDateTime, self.usdkrw);
}
@end

 

 

 

 

+ Recent posts