영진위 api json
{
"boxOfficeResult": {
"boxofficeType": "일별 박스오피스",
"showRange": "20240501~20240501",
"dailyBoxOfficeList": [
{
"rnum": "1",
"rank": "1",
"rankInten": "0",
"rankOldAndNew": "OLD",
"movieCd": "20228797",
"movieNm": "범죄도시4",
"openDt": "2024-04-24",
"salesAmt": "7173755964",
"salesShare": "84.8",
"salesInten": "3490937394",
"salesChange": "94.8",
"salesAcc": "54743912218",
"audiCnt": "784809",
"audiInten": "394859",
"audiChange": "101.3",
"audiAcc": "5790321",
"scrnCnt": "2702",
"showCnt": "14172"
},
{
"rnum": "2",
"rank": "2",
"rankInten": "0",
"rankOldAndNew": "OLD",
"movieCd": "20236614",
"movieNm": "쿵푸팬더4",
"openDt": "2024-04-10",
"salesAmt": "336923219",
"salesShare": "4.0",
"salesInten": "243213158",
"salesChange": "259.5",
"salesAcc": "13462011584",
"audiCnt": "38600",
"audiInten": "28087",
"audiChange": "267.2",
"audiAcc": "1443199",
"scrnCnt": "600",
"showCnt": "919"
},
{
"rnum": "3",
"rank": "3",
"rankInten": "0",
"rankOldAndNew": "NEW",
"movieCd": "20235613",
"movieNm": "스턴트맨",
"openDt": "2024-05-01",
"salesAmt": "357447723",
"salesShare": "4.2",
"salesInten": "357447723",
"salesChange": "100",
"salesAcc": "660244723",
"audiCnt": "35374",
"audiInten": "35374",
"audiChange": "100",
"audiAcc": "68479",
"scrnCnt": "801",
"showCnt": "2244"
},
{
"rnum": "4",
"rank": "4",
"rankInten": "0",
"rankOldAndNew": "NEW",
"movieCd": "20249313",
"movieNm": "포켓몬스터: 성도지방 이야기, 최종장",
"openDt": "2024-05-01",
"salesAmt": "278724769",
"salesShare": "3.3",
"salesInten": "278724769",
"salesChange": "100",
"salesAcc": "280484769",
"audiCnt": "32927",
"audiInten": "32927",
"audiChange": "100",
"audiAcc": "33087",
"scrnCnt": "658",
"showCnt": "1446"
},
{
"rnum": "5",
"rank": "5",
"rankInten": "0",
"rankOldAndNew": "OLD",
"movieCd": "20231677",
"movieNm": "남은 인생 10년",
"openDt": "2023-05-24",
"salesAmt": "51708205",
"salesShare": "0.6",
"salesInten": "7596913",
"salesChange": "17.2",
"salesAcc": "4382668970",
"audiCnt": "5326",
"audiInten": "812",
"audiChange": "18",
"audiAcc": "430512",
"scrnCnt": "108",
"showCnt": "142"
},
{
"rnum": "6",
"rank": "6",
"rankInten": "-3",
"rankOldAndNew": "OLD",
"movieCd": "20234675",
"movieNm": "파묘",
"openDt": "2024-02-22",
"salesAmt": "39390826",
"salesShare": "0.5",
"salesInten": "-29943572",
"salesChange": "-43.2",
"salesAcc": "114670144872",
"audiCnt": "4251",
"audiInten": "-3157",
"audiChange": "-42.6",
"audiAcc": "11864316",
"scrnCnt": "141",
"showCnt": "183"
},
{
"rnum": "7",
"rank": "7",
"rankInten": "0",
"rankOldAndNew": "NEW",
"movieCd": "20249133",
"movieNm": "극장판 실바니안 패밀리: 프레야의 선물",
"openDt": "2024-05-01",
"salesAmt": "29828450",
"salesShare": "0.4",
"salesInten": "29828450",
"salesChange": "100",
"salesAcc": "34224450",
"audiCnt": "3948",
"audiInten": "3948",
"audiChange": "100",
"audiAcc": "4576",
"scrnCnt": "188",
"showCnt": "280"
},
{
"rnum": "8",
"rank": "8",
"rankInten": "0",
"rankOldAndNew": "NEW",
"movieCd": "20249353",
"movieNm": "꼬마참새 리차드: 신비한 보석 탐험대",
"openDt": "2024-05-01",
"salesAmt": "29553100",
"salesShare": "0.3",
"salesInten": "29553100",
"salesChange": "100",
"salesAcc": "43045400",
"audiCnt": "3851",
"audiInten": "3851",
"audiChange": "100",
"audiAcc": "5305",
"scrnCnt": "154",
"showCnt": "205"
},
{
"rnum": "9",
"rank": "9",
"rankInten": "-5",
"rankOldAndNew": "OLD",
"movieCd": "20249318",
"movieNm": "챌린저스",
"openDt": "2024-04-24",
"salesAmt": "35507320",
"salesShare": "0.4",
"salesInten": "-21340719",
"salesChange": "-37.5",
"salesAcc": "369939305",
"audiCnt": "3612",
"audiInten": "-2457",
"audiChange": "-40.5",
"audiAcc": "39067",
"scrnCnt": "129",
"showCnt": "152"
},
{
"rnum": "10",
"rank": "10",
"rankInten": "-4",
"rankOldAndNew": "OLD",
"movieCd": "20248466",
"movieNm": "고스트버스터즈: 오싹한 뉴욕",
"openDt": "2024-04-17",
"salesAmt": "16081700",
"salesShare": "0.2",
"salesInten": "7039244",
"salesChange": "77.8",
"salesAcc": "416480161",
"audiCnt": "2021",
"audiInten": "866",
"audiChange": "75",
"audiAcc": "44852",
"scrnCnt": "50",
"showCnt": "51"
}
]
}
}
Tree, Code 형식으로 보기 (Code Beautify)
Tree
Code
JSON 데이터 모델 만들기
// This file was generated from JSON Schema using quicktype, do not modify it directly.
// To parse the JSON, add this file to your project and do:
//
// let welcome = try? JSONDecoder().decode(Welcome.self, from: jsonData)
import Foundation
// MARK: - Welcome
struct Welcome: Codable {
let boxOfficeResult: BoxOfficeResult
}
// MARK: - BoxOfficeResult
struct BoxOfficeResult: Codable {
let boxofficeType, showRange: String
let dailyBoxOfficeList: [DailyBoxOfficeList]
}
// MARK: - DailyBoxOfficeList
struct DailyBoxOfficeList: Codable {
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 CodingKeys: String, CodingKey {
case rnum, rank, rankInten, rankOldAndNew
case movieCD = "movieCd"
case movieNm, openDt, salesAmt, salesShare, salesInten, salesChange, salesAcc, audiCnt, audiInten, audiChange, audiAcc, scrnCnt, showCnt
}
}
enum RankOldAndNew: String, Codable {
case new = "NEW"
case old = "OLD"
}
// To parse the JSON, install Klaxon and do:
//
// val welcome = Welcome.fromJson(jsonString)
package quicktype
import com.beust.klaxon.*
private fun <T> Klaxon.convert(k: kotlin.reflect.KClass<*>, fromJson: (JsonValue) -> T, toJson: (T) -> String, isUnion: Boolean = false) =
this.converter(object: Converter {
@Suppress("UNCHECKED_CAST")
override fun toJson(value: Any) = toJson(value as T)
override fun fromJson(jv: JsonValue) = fromJson(jv) as Any
override fun canConvert(cls: Class<*>) = cls == k.java || (isUnion && cls.superclass == k.java)
})
private val klaxon = Klaxon()
.convert(RankOldAndNew::class, { RankOldAndNew.fromValue(it.string!!) }, { "\"${it.value}\"" })
data class Welcome (
val boxOfficeResult: BoxOfficeResult
) {
public fun toJson() = klaxon.toJsonString(this)
companion object {
public fun fromJson(json: String) = klaxon.parse<Welcome>(json)
}
}
data class BoxOfficeResult (
val boxofficeType: String,
val showRange: String,
val dailyBoxOfficeList: List<DailyBoxOfficeList>
)
data class DailyBoxOfficeList (
val rnum: String,
val rank: String,
val rankInten: String,
val rankOldAndNew: RankOldAndNew,
@Json(name = "movieCd")
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
)
enum class RankOldAndNew(val value: String) {
New("NEW"),
Old("OLD");
companion object {
public fun fromValue(value: String): RankOldAndNew = when (value) {
"NEW" -> New
"OLD" -> Old
else -> throw IllegalArgumentException()
}
}
}
RESTful API
RESTful API를 사용하면 URI만 봐도 어떤 사이트인지 알 수 있다.
JSON
Open API 활용 사례
Open API를 이용한 앱 개발 단계
- 원하는 정보를 제공하는 웹 서비스와 사용할 Open API 선정
- Open API 사용을 위한 신청과 인증키 발급
- 네트워크를 통해 데이터 요청
- 받은 데이터를 파싱하여 앱에서 사용
MovieCMU
Constraints
dequeueReusableCell
출처
- Smile Han의 iOS 프로그래밍 실무, 한성현(출판 예정), PPT로 제공
- Do it! 스위프트로 아이폰 앱 만들기 입문(개정 7판)(이지스퍼블리싱,송호정, 이범근, 2023.1)
- 핵심만 골라 배우는 SwiftUI 기반의 iOS 프로그래밍(제이펍, 닐 스미스, 2023.12)
- https://www.techotopia.com/index.php/IOS_iPhone_iPad_eBooks
- 스위프트 프로그래밍(Swift 5) 3판(한빛미디어, 야곰, 2019.10)
- 꼼꼼한 재은 씨의 스위프트 기본편 (루비페이퍼, 이재은, 2018.05)
- 꼼꼼한 재은 씨의 스위프트 실전편 (Swift) (루비페이퍼, 이재은, 2018.08)
- 꼼꼼한 재은 씨의 Swift 문법편 (루비페이퍼, 이재은, 2017.12)