1. 이전 포스팅 확인하기

 

https://growingsaja.tistory.com/897

 

[Objective-C] 앱 만들기 입문 - 7 : 프로젝트에 custom font 적용하고 사용하기

1. 이전 포스팅 확인하기 https://growingsaja.tistory.com/896 [Objective-C] 앱 만들기 입문 - 6 : file 데이터과 api return 데이터를 함께 활용해보기 1. 이전 포스팅 확인하기 https://growingsaja.tistory.com/892 [Objective-C

growingsaja.tistory.com

 

 

 

 

 

2. CRTSystem 파일 생성

 

 

 

 

 

 

3. CRTSystem 파일 작성

 

// vim CRTSystem.h

@interface CRTSystem : NSObject

-(NSString *)NowDateTimeGMT;
-(NSString *)NowDateTimeKST;

@end

 

// vim CRTSystem.m

#import <Foundation/Foundation.h>
#import "CRTSystem.h"

@implementation CRTSystem

-(NSString *)NowDateTimeGMT {
    // [현재 GMT 날짜 얻어 오기]
    NSDate *nowGMTDateRaw = [NSDate date];
    
    // [날짜 형식 포맷 + GMT 세팅 :: 24시간 형태]
    NSDateFormatter *dateFormatterGMT = [[NSDateFormatter alloc] init];
    [dateFormatterGMT setDateFormat:@"yyyy-MM-dd(E) kk:mm:ss"];
    NSTimeZone *gmtTimeZone = [NSTimeZone timeZoneWithName:@"GMT"];
    [dateFormatterGMT setTimeZone:gmtTimeZone];
    
    // [현재 GMT 일시 출력]
    NSString *nowGMTString = @"";
    nowGMTString = [dateFormatterGMT stringFromDate:nowGMTDateRaw];
    return nowGMTString;
}

-(NSString *)NowDateTimeKST {
    // [현재 GMT 날짜 얻어 오기]
    NSDate *nowGMTDateRaw = [NSDate date];
    
    // [날짜 형식 포맷 + KST 세팅 :: 24시간 형태
    NSDateFormatter *dateFormatterKST = [[NSDateFormatter alloc] init];
    [dateFormatterKST setDateFormat:@"yyyy-MM-dd(E) kk:mm:ss"];
    NSTimeZone *kstTimeZone = [NSTimeZone timeZoneWithName:@"Asia/Seoul"];
    [dateFormatterKST setTimeZone:kstTimeZone];
    
    // [현재 KST 일시 출력]
    NSString *nowKSTString = @"";
    nowKSTString = [dateFormatterKST stringFromDate:nowGMTDateRaw];
    return nowKSTString;
}


@end

 

 

 

 

 

4. FavoriteAssetTeackerListVC 파일 수정

 

h파일은 수정사항이 없고, m파일은 수정된 내용이 있습니다.

 

// vim Controller/FavoriteAssetTeackerListVC.h

#import <UIKit/UIKit.h>

// SecondViewController라는 이름의 뷰 컨트롤러 클래스를 선언합니다.
@interface FavoriteAssetTeackerListVC : UIViewController
@property (readwrite, strong, nonatomic) UIScrollView *scrollView;
@property (readwrite, strong, nonatomic) UIStackView *stackView;
@end

 

// vim Controller/FavoriteAssetTeackerListVC.m

#import <Foundation/Foundation.h>
#import "FavoriteAssetTeackerListVC.h"
// api 통신 용도
#import "CRTConnect.h"
// default.json 파일 읽기 용도
#import "CRTJSONReader.h"
// 현재 시간 가져오는 용도
#import "CRTSystem.h"

@implementation FavoriteAssetTeackerListVC {
    // json에서 가져온 favoriteList 데이터 각각의 마지막에 append해서 price 기재
    int priceIndexOfFavoriteGoods;
    // json에서 가져온 favoriteList raw 데이터
    NSMutableArray *favoriteListFullInfo;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 스크롤 뷰 생성 및 초기화
    self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    self.scrollView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:self.scrollView];
    
    // 스택 뷰 생성 및 초기화
    self.stackView = [[UIStackView alloc] initWithFrame:self.scrollView.bounds];
    self.stackView.axis = UILayoutConstraintAxisVertical;
    self.stackView.distribution = UIStackViewDistributionEqualSpacing;
    self.stackView.alignment = UIStackViewAlignmentFill;
    self.stackView.spacing = 12;
    [self.scrollView addSubview:self.stackView];
    
    // default.json의 favoriteList 데이터 가져오기
    [self loadFavoriteList];
    
    // NSTimer 생성 및 메서드 호출 설정 - 매 특정시간마다 호출
    [NSTimer scheduledTimerWithTimeInterval:0.5
                                     target:self
                                   selector:@selector(updateDataAndView)
                                   userInfo:nil
                                    repeats:YES];
}
- (void)updateDataAndView {
    // 데이터 가져오기 및 뷰 업데이트 코드
    // ****************************** [Start] Bybit 데이터 가져오기 ****************************** //
    CRTConnect* tryApiCall = [[CRTConnect alloc] init];
    NSString *apiURL = @"https://api.bybit.com/spot/quote/v1/ticker/price";
    [tryApiCall fetchDataFromAPI:apiURL withCompletionHandler:^(NSDictionary *jsonResponse, NSError *error) {
        if (error) {
            NSLog(@"Error: %@", error.localizedDescription);
        } else {
            // 여기에서 jsonResponse를 가공 한 후 앱에서 사용하실 수 있습니다.
            // result 안의 value만 추출
            NSArray* resultOfApi = jsonResponse[@"result"];
            
            // Bybit Api 결과를 Array에서 깔끔한 Dict로 가공하기 위한 데이터 선언
            NSMutableDictionary *allBybitDictTmp = [@{} mutableCopy];
            // api로 받은 데이터 깔끔한 dictionary로 가공하기
            for (int i=0; i<resultOfApi.count; i++) {
                NSString *keyTmp = resultOfApi[i][@"symbol"];
                NSString *valueTmp = resultOfApi[i][@"price"];
                allBybitDictTmp[keyTmp] = valueTmp;
            }
            
            // favorite List에 가격 append하기
            NSString *indexKey = [[NSString alloc] init];
            for (int i=0; i<self->favoriteListFullInfo.count; i++) {
                indexKey = self->favoriteListFullInfo[i][4];
                // 추후 json에는 있는데, bybit api에는 없는 경우에 대한 오류 해결 if문 추가 필요
                self->favoriteListFullInfo[i][self->priceIndexOfFavoriteGoods] = allBybitDictTmp[indexKey];
            }
            // 메인 스레드에서만 UI 업데이트 수행
            dispatch_async(dispatch_get_main_queue(), ^{
                [self updateView];
            });
        }
    }];
    // ****************************** [End] Bybit 데이터 가져오기 ****************************** //
    
}

// default.json 파일의 favoriteList 데이터 읽기
-(void) loadFavoriteList {
    CRTJSONReader *tryReadingDefaultJsonFile = [[CRTJSONReader alloc] init];
    NSDictionary *defaultData = [tryReadingDefaultJsonFile loadJSONFromFile:@"default"];
    favoriteListFullInfo = defaultData[@"favoriteList"];
    int checkDefaultJsonFile = 0;
    for (int i=0; i<favoriteListFullInfo.count-1; i++) {
        if ([favoriteListFullInfo[i] count] == [favoriteListFullInfo[i+1] count]) {
            checkDefaultJsonFile += 1;
        }
    }
    if (checkDefaultJsonFile == [favoriteListFullInfo count]-1) {
        // default.json파일의 favoriteList 안에 있는 Array들 중 길이가 모두 같으면
        priceIndexOfFavoriteGoods = (int)[favoriteListFullInfo[0] count];
    } else {
        // default.json파일의 favoriteList 안에 있는 Array들 중 길이가 다른 것이 1개라도 있으면 WARN 출력 및 앱 dead
        priceIndexOfFavoriteGoods = 9999; // for error
        NSLog(@"****************************************************");
        NSLog(@"[WARN] Check File : default.json - favoriteList");
        NSLog(@"****************************************************");
    }
    
}

-(void) updateView {
    // ****************************** [Start] 뷰 그리기 ****************************** //
    // 기존 뷰 삭제
    for (UIView *subview in self.scrollView.subviews) {
        [subview removeFromSuperview];
    }
    // viewDidLoad 메서드에서 스크롤 뷰를 초기화하고 설정합니다.
    self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    self.scrollView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:self.scrollView];
    
    //카드뷰 배치에 필요한 변수를 설정합니다.
    // 카드 목록 나열될 공간 세팅
    // ****************************** //
    // 목록 상단 공백 margin 설정
    CGFloat cardViewTopStartMargin = 10.0;
    // 카드 목록의 좌우 공백 각각의 margin
    CGFloat horizontalMargin = 2;
    // 카드와 카드 사이의 공백
    CGFloat cardViewSpacing = 4.0;
    // 카드뷰 목록 노출 시작 x축 위치 자동 설정
    CGFloat cardViewXPosition = horizontalMargin;
    // ****************************** //
    // 카드 자체에 대한 세팅
    // 카드 높이 길이 (상하 길이) 설정
    CGFloat cardViewHeight = 60.0;
    // 카드 좌우 길이 phone size 참조하여 자동 조정
    CGFloat cardViewWidth = [UIScreen mainScreen].bounds.size.width - horizontalMargin * 2;
    // 카드뷰 안에 내용 들어가는 공간까지의 margin
    CGFloat basicMarginInCard = 10.0;
    CGFloat defaultFontSize = 16.0;
    // ****************************** //
    
    // 최상단에 최근 업데이트 시간 띄우기위한 공간 설정
    UIView *topInfoTab = [[UIView alloc] initWithFrame:CGRectMake(cardViewXPosition, cardViewTopStartMargin - (cardViewSpacing + cardViewHeight), cardViewWidth, cardViewHeight)];
    // 한국 시간
    UILabel *liveKSTLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard, cardViewWidth / 2 - 20, 20)];
    // 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
    liveKSTLabel.text = [[CRTSystem alloc] init].NowDateTimeKST;
    liveKSTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
    // 표준 시간
    UILabel *liveGMTLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, cardViewHeight - 25, cardViewWidth - 20, 20)];
    // 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
    liveGMTLabel.text = [[CRTSystem alloc] init].NowDateTimeGMT;
    liveGMTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
    
    // cardView를 self.scrollView에 추가합니다.
    [topInfoTab addSubview:liveKSTLabel];
    [topInfoTab addSubview:liveGMTLabel];
    [self.scrollView addSubview:topInfoTab];
    
    // 카드뷰 목록 쭉 만들기
    for (int i=0; i<favoriteListFullInfo.count; i++) {
        UIView *cardView = [[UIView alloc] initWithFrame:CGRectMake(cardViewXPosition, cardViewTopStartMargin + i * (cardViewSpacing + cardViewHeight), cardViewWidth, cardViewHeight)];
        
        // 카드뷰 모서리를 둥글게 설정합니다. 조건 1
        cardView.layer.cornerRadius = 8.0;
        // cardView의 경계를 기준으로 내용물이 보이는 영역을 제한합니다. masksToBounds를 YES로 설정하면, cardView의 경계 밖에 있는 모든 내용물은 자르고 숨깁니다(클립 됩니다). 즉 뷰의 경계 값을 초과한 부분을 자르기 위해 masksToBounds를 YES로 설정합니다. 반면 masksToBounds가 NO인 경우(기본값)에는 뷰의 경계 밖에 있는 내용물이 그대로 보이게 됩니다.
        cardView.layer.masksToBounds = YES;
        
        // UILabel의 텍스트 색상 및 배경색 설정
        // 카드뷰 배경색을 설정합니다.
        if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
            // 다크모드인 경우
            cardView.backgroundColor = [UIColor darkGrayColor];
            [self.view addSubview:cardView];
        } else {
            // 라이트모드인 경우
            cardView.backgroundColor = [UIColor lightGrayColor];
            [self.view addSubview:cardView];
        }
        
        // UILabel 객체를 생성합니다. 이 레이블은 암호화폐의 이름을 표시할 것입니다.
        // 따라서 CGRect를 사용하여 레이블의 위치와 크기를 설정하며, 왼쪽 위 모서리에서 시작합니다.
        UILabel *cryptoNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard, cardViewWidth / 2 - 20, 20)];
        // 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
        cryptoNameLabel.text = favoriteListFullInfo[i][4];
        cryptoNameLabel.font = [UIFont fontWithName:@"Pretendard-Bold" size:defaultFontSize];
//        systemFontOfSize:defaultFontSize
        // 생성한 cryptoNameLabel을 cardView의 서브뷰로 추가합니다. 이렇게 함으로써 레이블이 카드 뷰에 표시됩니다.
        [cardView addSubview:cryptoNameLabel];
        
        
        // 암호화폐 가격 레이블을 생성하고 카드뷰에 추가합니다. 조건 3
        UILabel *cryptoPriceLabel = [[UILabel alloc] initWithFrame:CGRectMake(cardViewWidth / 3, basicMarginInCard, cardViewWidth / 2 - basicMarginInCard, 20)];
        cryptoPriceLabel.text = favoriteListFullInfo[i][priceIndexOfFavoriteGoods];
        cryptoPriceLabel.textAlignment = NSTextAlignmentRight;
        cryptoPriceLabel.font = [UIFont fontWithName:@"Pretendard-ExtraBold" size:defaultFontSize];
        [cardView addSubview:cryptoPriceLabel];
        
        // 거래소 이름 레이블을 생성하고 카드뷰에 추가합니다. 조건 5
        UILabel *exchangeNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, cardViewHeight - 25, cardViewWidth - 20, 20)];
        exchangeNameLabel.text = favoriteListFullInfo[i][0];
        exchangeNameLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
        [cardView addSubview:exchangeNameLabel];
        
        // cardView를 self.scrollView에 추가합니다.
        [self.scrollView addSubview:cardView];
    }
    // 상하 스크롤 최대치 자동 설정
    CGFloat contentHeight = favoriteListFullInfo.count * (cardViewHeight + cardViewSpacing);
    self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, contentHeight);
    // ****************************** [End] 뷰 그리기 ****************************** //
}
@end

 

 

 

 

 

5. 결과 예시

 

 - 왼쪽은 수정 전, 오른쪽은 수정 후입니다.

 

 

 

 

 

 

6. 본 포스팅에서 활용된 NSDate 등 관련 자료 보러가기

 

https://growingsaja.tistory.com/883

 

[Objective-C] 입문하기 - 14 : 날짜 데이터 활용 및 타이머 구현 실습

1. 시작 전에 프로젝트 코드 기본 세팅하고 오기 https://growingsaja.tistory.com/869 [Objective-C] 프로젝트 기본 세팅 소스코드 예시 1. AppDelegate 수정 with 설명 // vim AppDelegate.h #import // MARK: - [클래스 설명] /*

growingsaja.tistory.com

 

 

 

+ Recent posts