본문 바로가기

카테고리 없음

iOS 프로그래밍 실무 9주차

https://www.kobis.or.kr/kobisopenapi/homepg/apiservice/searchServiceInfo.do

 

영화진흥위원회 오픈API

제공서비스 영화관입장권통합전산망이 제공하는 오픈API서비스 모음입니다. 사용 가능한 서비스를 확인하고 서비스별 인터페이스 정보를 조회합니다.

www.kobis.or.kr

 

영화진흥위원회 json(20260503기준)

 

네이버 영화 순위와 비교
키들의 의미

https://codebeautify.org/jsonviewer

 

Best JSON Viewer and JSON Beautifier Online

Online JSON Viewer, JSON Beautifier and Formatter to beautify and tree view of JSON data - It works as JSON Pretty Print to pretty print JSON data.

codebeautify.org

 

 

 

json데이터의 데이터 모델을 swift구조->

주어진 JSON 구조를 보면 중첩 객체 형태이기 때문에 Swift에서는 Codable을 활용해서 아래처럼 구조체를 만들면 됩니다.

 
import Foundation

// 최상위
struct BoxOfficeResponse: Codable {
    let boxOfficeResult: BoxOfficeResult
}

// boxOfficeResult
struct BoxOfficeResult: Codable {
    let boxofficeType: String
    let showRange: String
    let dailyBoxOfficeList: [DailyBoxOffice]
}

// dailyBoxOfficeList 배열 내부 객체
struct DailyBoxOffice: Codable {
    let rnum: String
    let rank: String
    let rankInten: String
    let rankOldAndNew: String
    let movieCd: String
    let movieNm: String
    let openDt: String
    let salesAmt: String
    let salesShare: String
    let salesInten: String
    let salesChange: String
    let salesAcc: String
    let audiCnt: String
    let audiInten: String
    let audiChange: String
    let audiAcc: String
    let scrnCnt: String
    let showCnt: String
}
 

👍 추가 팁 (실무 스타일)

현재 모든 값이 "String"으로 되어 있지만, 실제로는 숫자인 데이터가 많습니다.
API가 문자열로 주기 때문에 일단 String으로 받는 게 안전하지만, 필요하면 이렇게 바꿀 수도 있습니다:

 
let rank: Int
let salesAmt: Int
let audiCnt: Int
 

단, 이 경우 디코딩 시 타입 mismatch 에러가 날 수 있어서
Custom Decoder를 쓰거나 String → Int 변환을 따로 해주는 게 좋습니다.


🔥 JSON 디코딩 예시

 
let decoder = JSONDecoder()

if let data = jsonData {
    do {
        let result = try decoder.decode(BoxOfficeResponse.self, from: data)
        print(result.boxOfficeResult.dailyBoxOfficeList[0].movieNm)
    } catch {
        print("디코딩 에러:", error)
    }
}
 

 

<다양한 언어의 예시>

✅ 1. Java (POJO + Jackson/Gson 공통 스타일)

import java.util.List;

public class BoxOfficeResponse {
    public BoxOfficeResult boxOfficeResult;
}

class BoxOfficeResult {
    public String boxofficeType;
    public String showRange;
    public List<DailyBoxOffice> dailyBoxOfficeList;
}

class DailyBoxOffice {
    public String rnum;
    public String rank;
    public String rankInten;
    public String rankOldAndNew;
    public String movieCd;
    public String movieNm;
    public String openDt;
    public String salesAmt;
    public String salesShare;
    public String salesInten;
    public String salesChange;
    public String salesAcc;
    public String audiCnt;
    public String audiInten;
    public String audiChange;
    public String audiAcc;
    public String scrnCnt;
    public String showCnt;
}
 

👉 라이브러리

  • Jackson: ObjectMapper
  • Gson: new Gson().fromJson(...)

✅ 2. Kotlin (data class)

 
data class BoxOfficeResponse(
    val boxOfficeResult: BoxOfficeResult
)

data class BoxOfficeResult(
    val boxofficeType: String,
    val showRange: String,
    val dailyBoxOfficeList: List<DailyBoxOffice>
)

data class DailyBoxOffice(
    val rnum: String,
    val rank: String,
    val rankInten: String,
    val rankOldAndNew: String,
    val movieCd: String,
    val movieNm: String,
    val openDt: String,
    val salesAmt: String,
    val salesShare: String,
    val salesInten: String,
    val salesChange: String,
    val salesAcc: String,
    val audiCnt: String,
    val audiInten: String,
    val audiChange: String,
    val audiAcc: String,
    val scrnCnt: String,
    val showCnt: String
)
 

👉 보통 함께 쓰는 라이브러리

  • kotlinx.serialization
  • Moshi
  • Gson

✅ 3. Python (dataclass)

 
from dataclasses import dataclass
from typing import List

@dataclass
class DailyBoxOffice:
    rnum: str
    rank: str
    rankInten: str
    rankOldAndNew: str
    movieCd: str
    movieNm: str
    openDt: str
    salesAmt: str
    salesShare: str
    salesInten: str
    salesChange: str
    salesAcc: str
    audiCnt: str
    audiInten: str
    audiChange: str
    audiAcc: str
    scrnCnt: str
    showCnt: str

@dataclass
class BoxOfficeResult:
    boxofficeType: str
    showRange: str
    dailyBoxOfficeList: List[DailyBoxOffice]

@dataclass
class BoxOfficeResponse:
    boxOfficeResult: BoxOfficeResult
 

👉 JSON → 객체 변환 예시

 
import json

data = json.loads(json_string)
result = BoxOfficeResponse(**data)
 

(※ 실제로는 nested 구조라 pydantic이나 dacite 쓰는 게 더 안정적)

 

REST를 만족한다
uri(더 큰 개념)-> 이름만 있음, url->위치정보
웹에서 컴퓨터들끼리 정보를 주고받는 방법(주소+행동)
시험 중요

주소와 동작은 분리 http메서드에 넣음 

 

 

 

xml(최근은 잘 사용s)과 json

json데이터 형식은 {},[]로 처리(시험문제)-> json객체는 name/vlaue로 {}와 ,로 ???? 여러개를 나열할때는 []배열처럼 표시

 

 

json데이터를 타고 타고 들어가서 내가 원하는 정보를 파씽(원하는 데이터)

open api https://github.com/dl0312/open-apis-korea

 

GitHub - dl0312/open-apis-korea: 🇰🇷 한국어 사용자를 위한 서비스에 사용하기 위한 오픈 API 모음

🇰🇷 한국어 사용자를 위한 서비스에 사용하기 위한 오픈 API 모음. Contribute to dl0312/open-apis-korea development by creating an account on GitHub.

github.com

https://data.seoul.go.kr/datasetRanking/popular.do

 

열린데이터광장 메인

데이터분류,데이터검색,데이터활용

data.seoul.go.kr

https://www.data.go.kr/tcs/eds/ctm/selectContestDataList.do

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

<실습>

table뷰로 화면을 덮음(constraints 제약조건을 줌)

마진 유무에 따라 label에 차이가 생긴다

dequeueReusableCell 리턴값이 uitableviewcell이다(중요***기말시험)

->

as! MyTableViewCell //다운캐스팅

name이라는 배열을 만들고 name[indexPath.row]를 사용하여 name의 내용을 출력

 

*중요* 이 코드의 내용 주석 설명

//
//  ViewController.swift
//  Moviekhw
//
//  Created by 컴소뉴맥 on 2026/05/04.
//

import UIKit // iOS UI를 만들기 위한 기본 프레임워크

// 전역 배열 (영화 제목 리스트)
// 테이블뷰에서 각 셀에 표시될 데이터
let name = [
    "1: 슈퍼 마리오 갤럭시",
    "2: 악마는 프라다를 입는다 2",
    "3: 살목지",
    "4: 프로젝트 헤일메리",
    "5: 짱구",
    "6: 왕과 사는 남자",
    "7: 란 12.3",
    "8: 내 이름은",
    "9: 사랑의 하츄핑 특별판",
    "10: 극장판 반짝반짝 달님이- 싱어롱 파티"
]

// UIViewController를 상속받고,
// UITableViewDelegate + UITableViewDataSource 프로토콜을 채택
// → 테이블뷰의 동작과 데이터 제공을 직접 구현하겠다는 의미
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
   
    // 스토리보드에서 연결된 UITableView 아울렛
    @IBOutlet weak var table: UITableView!
    
    // 🔹 섹션 하나당 몇 개의 행(row)이 있는지 반환
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 10
        // 현재는 고정값 10
        // 👉 더 좋은 방법: name.count 사용
    }
    
    // 🔹 각 행(row)에 들어갈 셀을 생성 및 설정
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        // 재사용 가능한 셀을 가져옴 (성능 최적화)
        // "myCell"은 스토리보드에서 설정한 Identifier
        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
        // as! → 강제 다운캐스팅 (MyTableViewCell 타입으로 변환)
        
        // 현재 행(indexPath.row)에 해당하는 영화 이름을 셀에 넣기
        cell.movieName.text = name[indexPath.row]
        
        // 현재 셀의 위치 출력 (디버깅용)
        print(indexPath.description)
        
        return cell
    }
    
    // 🔹 테이블뷰의 섹션 개수 설정
    func numberOfSections(in tableView: UITableView) -> Int {
        return 5
        // ⚠️ 현재 문제점:
        // 섹션은 5개인데, 데이터는 10개만 있음
        // → 모든 섹션에 동일한 데이터가 반복됨
    }
    
    // 🔹 뷰가 로드될 때 실행
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 테이블뷰의 delegate 설정 (이벤트 처리)
        table.delegate = self
        
        // 테이블뷰의 dataSource 설정 (데이터 공급)
        table.dataSource = self
    }
}
 

⚠️ 중요한 문제 포인트 (시험에 잘 나옴)

1. ❌ 하드코딩된 row 개수

 
return 10
 

👉 이렇게 쓰면 데이터 바뀌면 오류 가능

✔️ 더 좋은 코드:

 
return name.count
 

2. ❌ 섹션 5개인데 데이터 구조 없음

 
return 5
 

👉 지금 구조는

  • 섹션 5개
  • 각 섹션마다 동일한 10개 데이터 반복됨

✔️ 해결 방법 (둘 중 하나 선택)

방법 1 (간단)

 
return 1
 

방법 2 (진짜 구조화)

 
let data = [
    ["영화1", "영화2"],
    ["영화3", "영화4"]
]
 

3. ❗ 강제 캐스팅 위험

 
as! MyTableViewCell
 

👉 잘못 연결되면 앱 바로 크래시

✔️ 안전한 방법:

 
guard let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as? MyTableViewCell else {
    return UITableViewCell()
}
 

🔥 한 줄 핵심 정리

  • DataSource → 데이터 개수 + 셀 내용 담당
  • Delegate → 클릭, 높이 등 이벤트 담당
  • indexPath.row → 몇 번째 행
  • indexPath.section → 몇 번째 섹션