본문 바로가기

iOS

iOS_3grade - 10주차

 

영진위 데이터 - 5/11 일자

{
  "boxOfficeResult": {
    "boxofficeType": "일별 박스오피스",
    "showRange": "20260511~20260511",
    "dailyBoxOfficeList": [
      {
        "rnum": "1",
        "rank": "1",
        "rankInten": "1",
        "rankOldAndNew": "OLD",
        "movieCd": "20259791",
        "movieNm": "악마는 프라다를 입는다 2",
        "openDt": "2026-04-29",
        "salesAmt": "250692610",
        "salesShare": "34.1",
        "salesInten": "-459085710",
        "salesChange": "-64.7",
        "salesAcc": "12401287580",
        "audiCnt": "24856",
        "audiInten": "-43481",
        "audiChange": "-63.6",
        "audiAcc": "1246484",
        "scrnCnt": "1079",
        "showCnt": "3498"
      },
      {
        "rnum": "2",
        "rank": "2",
        "rankInten": "1",
        "rankOldAndNew": "OLD",
        "movieCd": "20254121",
        "movieNm": "살목지",
        "openDt": "2026-04-08",
        "salesAmt": "149637230",
        "salesShare": "20.4",
        "salesInten": "-431817520",
        "salesChange": "-74.3",
        "salesAcc": "31117243350",
        "audiCnt": "14561",
        "audiInten": "-41643",
        "audiChange": "-74.1",
        "audiAcc": "3037366",
        "scrnCnt": "878",
        "showCnt": "2641"
      },
      {
        "rnum": "3",
        "rank": "3",
        "rankInten": "-2",
        "rankOldAndNew": "OLD",
        "movieCd": "20259773",
        "movieNm": "슈퍼 마리오 갤럭시",
        "openDt": "2026-04-29",
        "salesAmt": "72856350",
        "salesShare": "9.9",
        "salesInten": "-727066010",
        "salesChange": "-90.9",
        "salesAcc": "12797524100",
        "audiCnt": "7191",
        "audiInten": "-75291",
        "audiChange": "-91.3",
        "audiAcc": "1325908",
        "scrnCnt": "733",
        "showCnt": "1685"
      },
      {
        "rnum": "4",
        "rank": "4",
        "rankInten": "0",
        "rankOldAndNew": "OLD",
        "movieCd": "20261782",
        "movieNm": "프로젝트 헤일메리",
        "openDt": "2026-03-18",
        "salesAmt": "86328020",
        "salesShare": "11.8",
        "salesInten": "-171644790",
        "salesChange": "-66.5",
        "salesAcc": "31662396640",
        "audiCnt": "7049",
        "audiInten": "-13720",
        "audiChange": "-66.1",
        "audiAcc": "2790015",
        "scrnCnt": "546",
        "showCnt": "934"
      },
      {
        "rnum": "5",
        "rank": "5",
        "rankInten": "0",
        "rankOldAndNew": "OLD",
        "movieCd": "20240532",
        "movieNm": "짱구",
        "openDt": "2026-04-22",
        "salesAmt": "43781220",
        "salesShare": "6.0",
        "salesInten": "-82122880",
        "salesChange": "-65.2",
        "salesAcc": "3713649280",
        "audiCnt": "4447",
        "audiInten": "-7784",
        "audiChange": "-63.6",
        "audiAcc": "381052",
        "scrnCnt": "429",
        "showCnt": "785"
      },
      {
        "rnum": "6",
        "rank": "6",
        "rankInten": "0",
        "rankOldAndNew": "OLD",
        "movieCd": "20242837",
        "movieNm": "왕과 사는 남자",
        "openDt": "2026-02-04",
        "salesAmt": "31877200",
        "salesShare": "4.3",
        "salesInten": "-51521200",
        "salesChange": "-61.8",
        "salesAcc": "162533352330",
        "audiCnt": "3446",
        "audiInten": "-4840",
        "audiChange": "-58.4",
        "audiAcc": "16836970",
        "scrnCnt": "372",
        "showCnt": "555"
      },
      {
        "rnum": "7",
        "rank": "7",
        "rankInten": "0",
        "rankOldAndNew": "OLD",
        "movieCd": "20262685",
        "movieNm": "란 12.3",
        "openDt": "2026-04-22",
        "salesAmt": "15206950",
        "salesShare": "2.1",
        "salesInten": "-26729200",
        "salesChange": "-63.7",
        "salesAcc": "2317632710",
        "audiCnt": "1590",
        "audiInten": "-2620",
        "audiChange": "-62.2",
        "audiAcc": "231977",
        "scrnCnt": "271",
        "showCnt": "360"
      },
      {
        "rnum": "8",
        "rank": "8",
        "rankInten": "5",
        "rankOldAndNew": "OLD",
        "movieCd": "20259626",
        "movieNm": "마이클",
        "openDt": "2026-05-13",
        "salesAmt": "16200000",
        "salesShare": "2.2",
        "salesInten": "3348000",
        "salesChange": "26.1",
        "salesAcc": "188388000",
        "audiCnt": "1506",
        "audiInten": "750",
        "audiChange": "99.2",
        "audiAcc": "18375",
        "scrnCnt": "4",
        "showCnt": "4"
      },
      {
        "rnum": "9",
        "rank": "9",
        "rankInten": "-1",
        "rankOldAndNew": "OLD",
        "movieCd": "20262947",
        "movieNm": "모탈 컴뱃 2",
        "openDt": "2026-05-06",
        "salesAmt": "12540250",
        "salesShare": "1.7",
        "salesInten": "-14937700",
        "salesChange": "-54.4",
        "salesAcc": "148652290",
        "audiCnt": "1168",
        "audiInten": "-1172",
        "audiChange": "-50.1",
        "audiAcc": "13217",
        "scrnCnt": "314",
        "showCnt": "410"
      },
      {
        "rnum": "10",
        "rank": "10",
        "rankInten": "-1",
        "rankOldAndNew": "OLD",
        "movieCd": "20247648",
        "movieNm": "내 이름은",
        "openDt": "2026-04-15",
        "salesAmt": "8243200",
        "salesShare": "1.1",
        "salesInten": "-5113550",
        "salesChange": "-38.3",
        "salesAcc": "1836367180",
        "audiCnt": "896",
        "audiInten": "-644",
        "audiChange": "-41.8",
        "audiAcc": "205640",
        "scrnCnt": "99",
        "showCnt": "128"
      }
    ]
  }
}

해당 주소가 없다면 nil 이 나와야하기 때문에 옵셔널형임.

 

JSON 파싱을 쉽게 하기 위함 - https://app.quicktype.io/

- 영진위에서 받아온 JSON 데이터를 구조체로 만듦

import Foundation

// MARK: - Welcome
struct Welcome {
    let boxOfficeResult: BoxOfficeResult
}

// MARK: - BoxOfficeResult
struct BoxOfficeResult {
    let boxofficeType, showRange: String
    let dailyBoxOfficeList: [DailyBoxOfficeList]
}

// MARK: - DailyBoxOfficeList
struct DailyBoxOfficeList {
    let rnum, rank, rankInten: String
    let rankOldAndNew: RankOldAndNew
    let movieCD, movieNm, openDt, salesAmt: String
    let salesShare, salesInten, salesChange, salesAcc: String
    let audiCnt, audiInten, audiChange, audiAcc: String
    let scrnCnt, showCnt: String
}

enum RankOldAndNew: String {
    case old
}

 

 - 2등인 영화의 제목 출력

 - 1등인 영화의 누적 관객 수

 - reloadData를 사용할 때도 self를 명시해야됨

 - 명시를 했음에도 오류 발생 : main Thread에서 사용해야되는데 클로저 안에서 사용 중임

//
//  ViewController.swift
//  movie_yjy
//
//  Created by 소프트웨어컴퓨터 on 2026/04/28.
//

import UIKit

let name = ["살목지","란 12.3","짱구","프로젝트 헤일메리","왕과 사는 남자","내 이름은","리 코로닌의 미이라",
            "기동전사 건담: 섬광의 하사웨이 키르케의 마녀", " 르누아르","마녀배달부 키키"]

struct MovieData : Codable {
    let boxOfficeResult : BoxOfficeResult
}
struct BoxOfficeResult : Codable {
    let dailyBoxOfficeList : [DailyBoxOfficeList]
}
struct DailyBoxOfficeList : Codable {
    let movieNm : String
    let audiCnt : String
    let audiAcc : String
    let rank : String
}

class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
    @IBOutlet weak var table: UITableView!
    var movieData : MovieData? // 프로퍼티는 반드시 초기값이 있어야함. -> 옵셔널로 지정하여 초기값을 nil로
//    let movieURL = 정해진 날짜가 아닌
    // 앱 실행시마다 날짜가 어제의 날짜로 설정되도록
    var movieURL = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=&targetDt="
    
    override func viewDidLoad() {
        super.viewDidLoad()
        table.delegate = self
        table.dataSource = self
        
        movieURL += makeYesterdayString()
        getData()
    }
    func makeYesterdayString() -> String{
        let y = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
        let dateF = DateFormatter()
        dateF.dateFormat = "yyyyMMdd"
        let day = dateF.string(from: y)
        return day
    }
    
    func getData(){
        //if let url = URL(string: movieURL){}
        guard let url = URL(string: movieURL) else { return } //네트워크 1단계 : url (주소) 만들기
        let session = URLSession(configuration: .default) // 2단계 : URLSession 만들기
        //3단계
        let task = session.dataTask(with: url) { data, response, error in
            if error != nil {return} // 에러가 있으면 종료
            guard let JSONdata = data else {return}
            print(JSONdata)
            let dataString = String(data:JSONdata, encoding: .utf8)
            //print(dataString!)
            let decoder = JSONDecoder()
            do{
                let decodedData = try decoder.decode(MovieData.self, from: JSONdata)
                //MovieData라는 자료형을 매개변수로 쓰려면 .self를 적어야함
                print(decodedData.boxOfficeResult.dailyBoxOfficeList[1].movieNm)
                print(decodedData.boxOfficeResult.dailyBoxOfficeList[0].audiAcc)
                self.movieData = decodedData
                DispatchQueue.main.async {
                    self.table.reloadData()
                }
            }catch{
                print(error)
            }
            //print(response!)
        }
        task.resume()
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
    }
    
//    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
//        as! MyTableViewCell
//        cell.movieName.text = "\(indexPath.row+1)등 " + name[indexPath.row]
//        //print(indexPath,separator: " ",terminator: " ") //화면에 보이는 셀을 모두 만듦
//        return cell
//    }
    func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        //print(indexPath.description) //어떤 섹션을 눌렀는지 확인 가능
    }
    func tableView(_ tableView : UITableView, cellForRowAt indexPath : IndexPath) ->
    UITableViewCell{
        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
        cell.movieName.text = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].movieNm
        return cell
    }
    
}

 

 

- 마무리 프로젝트 모습

 

'iOS' 카테고리의 다른 글

iOS_3grade - 13주차  (0) 2026.06.02
iOS_3grade - 11주차  (0) 2026.05.19
iOS_grade3 - 9주차  (0) 2026.04.28
iOS_3grade - 7주차  (0) 2026.04.14
iOS_3grade - 6주차  (1) 2026.04.07