(기말 80%)
5월 3일 기준 pretty print 적용



네트워크에서 무언가를 가져오는 경우

주소를 저장할 함수 getData
init(string:) | Apple Developer Documentation
Creates a URL instance from the provided string.
developer.apple.com
init?(string: String) 에서 ? 는 실패 가능한 초기화 구문(Failable Initializer) 이라는 뜻이야.
즉, 객체 생성이 성공할 수도 있고 실패할 수도 있다는 의미야.
예를 들어:
struct Person {
let age: Int
init?(age: Int) {
if age < 0 {
return nil
}
self.age = age
}
}
사용:
let p1 = Person(age: 20) // 성공
let p2 = Person(age: -1) // nil
여기서 p2는 객체 생성이 실패해서 nil이 돼.
init 와 init? 차이 정리:
| init() | 반드시 생성 성공 |
| init?() | 생성 실패 가능 (nil 반환 가능) |
네가 본:
init?(string: String)
은 보통 문자열을 어떤 타입으로 변환할 때 많이 사용돼.
예:
let num = Int("123") // 성공 → Optional(123)
let num2 = Int("abc") // 실패 → nil
왜냐면 "abc" 는 숫자로 변환할 수 없으니까 객체 생성이 실패하는 거야.
그래서 Int의 생성자는 내부적으로 이런 느낌:
init?(string: String)
처럼 실패 가능하게 만들어져 있어.
핵심:
- ? = 실패 가능
- 실패하면 nil
- 그래서 결과 타입이 Optional 이 됨 (Int?, Person?)
-> 옵셔널형으로 만들어진다.
1단계


URL(string:) -> 실패 가능한 초기화 구문(Failable Initializer) -> 객체가 옵셔널으로 나옴사용하려면 옵셔널을 풀어야함

if let

guard let ->더 추천

url 인스턴스를 넣을때 주소가 없을 수도 있음으로 nil이 출력되어야헤서 옵셔널형으로 나옴
1. if let 2. guard let중 더 가독성 좋은 guard let을 선호한다
2단계
init(configuration: URLSessionConfiguration)
init(configuration:) | Apple Developer Documentation
Creates a session with the specified session configuration.
developer.apple.com


3단계(*중요*)


datatask 함수안에 클로저가 들어감(후행 클로저 스타일)



후행클로저 스타일로 변경하기

Data?, URLResponse?, Error?
3개 자료형 -> 옵셔널형



4단계


func getData(){
guard let url = URL(string: movieURL) else { return } //네트워킹 1단계 - 주소 만들기
let session = URLSession(configuration: .default)//네트워킹 2단계 - 택배회사 정하기
let task = session.dataTask(with: url) { data, response, error in
if error != nil{
print(error!)
return
}//네트워킹 3단계 - 배송 요청서 작성
//dataTask -> 이 주소로 가서 데이터를 가져와라
guard let JSONdata = data else{ return }
print(JSONdata)
}
task.resume()//내트워킹 4단계 - 택배출발
}
->
이 코드는 Swift에서 URLSession을 사용해서 인터넷에서 데이터를 가져오는 네트워킹 코드야.
주석도 잘 달아놨는데, 각 단계가 실제로 무엇을 하는지 흐름까지 자세히 설명해볼게.
전체 흐름
이 함수의 목적:
func getData()
👉 movieURL 주소로 이동해서
👉 서버 데이터를 받아오는 것
예를 들면:
- 영화 API
- 날씨 API
- 로그인 서버
- JSON 데이터
같은 걸 가져올 때 사용해.
코드 전체
func getData(){
guard let url = URL(string: movieURL) else { return }
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { data, response, error in
if error != nil{
print(error!)
return
}
guard let JSONdata = data else{ return }
print(JSONdata)
}
task.resume()
}
1단계 — URL 만들기
guard let url = URL(string: movieURL) else { return }
역할
문자열 주소를 실제 URL 객체로 변환
예:
let movieURL = "https://example.com/movie"
↓
URL(string: movieURL)
↓
URL 객체 생성
왜 guard let 사용?
URL(string:) 은 실패 가능 생성자야.
즉:
URL(string: "잘못된 주소")
이런 경우 실패할 수 있음.
그래서 반환형이:
URL?
(Optional)
이라서 안전하게 언래핑해야 해.
guard let 의미
guard let url = ... else { return }
의 뜻:
- URL 생성 성공 → 계속 진행
- 실패 → 함수 종료
2단계 — URLSession 만들기
let session = URLSession(configuration: .default)
역할
인터넷 통신 담당 객체 생성
쉽게 말하면:
“통신 회사 선택”
URLSession 이란?
애플이 제공하는 네트워크 관리자 객체
할 수 있는 것:
- 데이터 다운로드
- 파일 업로드
- API 호출
- 이미지 다운로드
등등
configuration: .default
기본 설정 사용
즉:
- 일반 캐시 사용
- 쿠키 사용
- 기본 네트워크 정책 사용
가장 흔하게 사용되는 설정
3단계 — dataTask 생성
let task = session.dataTask(with: url) { data, response, error in
역할
실제 요청(Request) 만들기
쉽게 말하면:
“이 주소 가서 데이터 가져와”
dataTask란?
비동기 네트워크 작업
서버에 요청 보내고 결과를 받아옴.
클로저 부분 설명
{ data, response, error in
서버 응답이 오면 실행되는 코드
서버가 응답하면 자동 호출됨.
매개변수 3개
| data | 실제 받은 데이터 |
| response | 서버 응답 정보 |
| error | 오류 정보 |
error 처리
if error != nil{
print(error!)
return
}
의미
네트워크 실패했는지 확인
예:
- 인터넷 끊김
- 주소 오류
- 서버 다운
왜 return?
에러 발생 시 더 진행하면 안 되니까 함수 종료
더 안전한 코드
보통 이렇게 많이 씀:
if let error = error {
print(error)
return
}
강제 언래핑(!) 피할 수 있어서 더 안전함.
data 언래핑
guard let JSONdata = data else { return }
의미
서버가 실제 데이터를 보냈는지 확인
data 타입은:
Data?
Optional 이라 언래핑 필요
Data란?
바이트(binary) 데이터
예:
- JSON
- 이미지
- 영상
- 텍스트
모든 인터넷 데이터는 결국 Data 형태로 옴.
print(JSONdata)
print(JSONdata)
현재는 원시 데이터 출력
결과 예시:
876 bytes
같은 식으로 나옴.
실제 앱에서는 보통 이렇게 변환
JSON 문자열 보기:
let str = String(data: JSONdata, encoding: .utf8)
print(str)
또는
JSONDecoder()
로 모델 객체 변환
4단계 — task 시작
task.resume()
매우 중요
이거 안 쓰면 네트워크 시작 안 됨.
왜?
dataTask() 는 작업만 생성함.
아직 시작 안 한 상태.
즉:
let task = ...
는
“택배 예약만 함”
상태
resume()
task.resume()
해야 실제 요청 시작
즉:
“택배 출발”
전체 흐름 그림
1. URL 생성
↓
2. URLSession 생성
↓
3. dataTask 생성
↓
4. 서버 요청
↓
5. 서버 응답
↓
6. data / error 처리
중요한 개념 — 비동기(Async)
이 코드 핵심 중 하나
session.dataTask
는 비동기 작업임.
즉:
getData()
print("끝")
하면
출력 순서가:
끝
(나중에 서버 응답)
일 수 있음.
왜냐면 인터넷 응답은 시간이 걸리니까.
실제 앱에서 자주 추가하는 것
JSON 디코딩
let decoder = JSONDecoder()
let result = try decoder.decode(Movie.self, from: JSONdata)
메인스레드 UI 업데이트
네트워크는 백그라운드에서 실행됨.
그래서 UI 수정 시:
DispatchQueue.main.async {
self.label.text = "완료"
}
필요함.
한 줄 요약
이 코드는:
URL 생성
→ 네트워크 세션 생성
→ 서버에 요청
→ 응답 받기
→ 데이터 출력
하는 Swift 기본 네트워킹 코드야.

let dataString = String(data: JSONdata, encoding: .utf8)
print(dataString!)을 통해 영화진흥위원회 데이터를 인코딩하여 datastring에 저장
Instantly parse JSON in any language | quicktype
app.quicktype.io
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 {
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
}
AI활용 -> 파싱을 쉽게 하기 위한 MovieData형 구조체를 Swift로 만들어 줘
import Foundation
// 최상위
struct MovieData: Decodable {
let boxOfficeResult: BoxOfficeResult
}
// boxOfficeResult
struct BoxOfficeResult: Decodable {
let boxofficeType: String
let showRange: String
let dailyBoxOfficeList: [DailyBoxOffice]
}
// 영화 정보
struct DailyBoxOffice: Decodable {
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
}
그리고 이렇게 디코딩하면 돼:
do {
let decoder = JSONDecoder()
let result = try decoder.decode(MovieData.self, from: JSONdata)
print(result.boxOfficeResult.dailyBoxOfficeList[0].movieNm)
} catch {
print(error)
}
구조 이해 그림
MovieData
└── boxOfficeResult
└── dailyBoxOfficeList
├── 영화1
├── 영화2
└── 영화3
실제 접근 예시
영화 제목 출력
let movies = result.boxOfficeResult.dailyBoxOfficeList
for movie in movies {
print(movie.movieNm)
}
출력 결과
슈퍼 마리오 갤럭시
악마는 프라다를 입는다 2
살목지
...
왜 Decodable 사용?
Decodable
은:
JSON → Swift 객체
자동 변환 가능하게 해주는 프로토콜이야.
Codable로 써도 됨
실무에서는 보통:
struct MovieData: Codable
많이 사용해.
왜냐면:
| Decodable | JSON → 객체 |
| Encodable | 객체 → JSON |
| Codable | 둘 다 |
참고 (시험/실무 팁)
현재 모든 값이 "문자열" 형태라서 전부 String 으로 만든 거야.
예:
"rank":"1"
숫자처럼 보여도 실제 JSON은 문자열임.
그래서:
let rank: String
으로 해야 디코딩 오류 안 남.

구조체는 상속 x codable은 프로토콜

Codable 은 Swift 객체를
JSON 같은 데이터 형식으로 변환(인코딩) 하거나
JSON 데이터를 Swift 객체로 변환(디코딩) 하기 위해 사용해.
쉽게 말하면:
Swift 객체 ↔ JSON
자동 변환 기능이라고 보면 돼.
서버에서 받은 JSON:
{
"movieNm":"슈퍼 마리오 갤럭시"
}
이걸 Swift 구조체로 바꾸고 싶음:
struct Movie {
let movieNm: String
}
이때 Codable 이 필요해.
Codable 없으면?
Swift는:
JSON 데이터를
어떤 구조체에 넣어야 하는지 모름
그래서 자동 변환 불가능.
Codable 추가
struct Movie: Codable {
let movieNm: String
}
하면 Swift가 자동으로:
JSON ↔ 구조체
변환 코드를 만들어줌.
Codable의 진짜 정체
사실:
Codable
은 합쳐진 이름이야.
Codable = Encodable + Decodable
각각 의미
| Decodable | JSON → 객체 |
| Encodable | 객체 → JSON |
| Codable | 둘 다 가능 |
네 코드에서는 주로 Decodable 기능 사용
let result = try decoder.decode(MovieData.self, from: JSONdata)
여기서 하는 일:
JSONdata
↓
MovieData 구조체 변환
이거야.
내부적으로 Swift가 하는 일
이 JSON:
{
"movieNm":"슈퍼 마리오 갤럭시"
}
을 보고
struct Movie: Codable {
let movieNm: String
}
의
movieNm
이랑 이름 매칭해서 자동 저장함.
Codable 없으면 오류
struct Movie {
let movieNm: String
}
이 상태에서:
decoder.decode(Movie.self, from: data)
하면 오류 발생.
왜냐면:
Movie는 Decodable이 아님
이라고 뜸.
실무에서 Codable 엄청 중요함
앱 개발 대부분이 서버 통신이라서:
- 영화 API
- 로그인 API
- 쇼핑몰 데이터
- 채팅 데이터
전부 JSON 사용함.
그래서 Codable 은 iOS에서 거의 필수 개념이야.
시험 스타일 핵심 정리
Codable
- JSON 데이터를 Swift 객체로 변환 가능
- Swift 객체를 JSON으로 변환 가능
- Encodable + Decodable
- 서버 통신에서 자주 사용
흐름 그림
서버 JSON 데이터
↓
JSONDecoder
↓
Codable 구조체
↓
Swift 객체 사용
예시 전체 흐름
struct Movie: Codable {
let movieNm: String
}
let decoder = JSONDecoder()
let movie = try decoder.decode(Movie.self, from: data)
결과:
print(movie.movieNm)
출력:
슈퍼 마리오 갤럭시


예외처리 필요한 매소드


do catch try 사용

1등의 데이터 출력 이름,누적관객수,해당 날짜 관객수,순위


클로저안에 쓰기 위해 self 사용(현재 객체(ViewController 등) 자신의 속성)




//
// ViewController.swift
// Moviekhw
//
import UIKit
// 테스트용 영화 이름 배열
// 현재는 실제 API 데이터를 사용하므로 사용하지 않음
let name = [
"1: 슈퍼 마리오 갤럭시",
"2: 악마는 프라다를 입는다 2",
"3: 살목지",
"4: 프로젝트 헤일메리",
"5: 짱구",
"6: 왕과 사는 남자",
"7: 란 12.3",
"8: 내 이름은",
"9: 사랑의 하츄핑 특별판",
"10: 극장판 반짝반짝 달님이- 싱어롱 파티"
]
// MARK: - JSON 전체 구조
// 가장 바깥 JSON 구조
// JSON:
// {
// "boxOfficeResult": { ... }
// }
struct MovieData : Codable {
let boxOfficeResult : BoxOfficeResult
}
// boxOfficeResult 내부 구조
// JSON:
// "boxOfficeResult": {
// "dailyBoxOfficeList": [ ... ]
// }
struct BoxOfficeResult : Codable {
let dailyBoxOfficeList : [DailyBoxOfficeList]
}
// 실제 영화 데이터 하나의 구조
// JSON 배열 안의 각각 영화 정보
struct DailyBoxOfficeList : Codable {
// 영화 제목
let movieNm : String
// 하루 관객 수
let audiCnt : String
// 누적 관객 수
let audiAcc : String
// 현재 순위
let rank : String
}
// MARK: - ViewController
class ViewController: UIViewController,
UITableViewDelegate,
UITableViewDataSource {
// 스토리보드의 TableView 연결
@IBOutlet weak var table: UITableView!
// 서버에서 받아온 영화 데이터를 저장할 변수
// 처음에는 데이터가 없으므로 Optional(?)
var movieData : MovieData?
// 영화진흥위원회(KOBIS) API 주소
// targetDt = 조회 날짜
let movieURL =
"https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=d32b85027905503dcfff4af4097262af&targetDt=20260510"
// MARK: - 테이블뷰 행 개수
// 테이블에 몇 개의 셀(row)을 만들지 결정
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
// 현재는 10개 고정
// 실제로는:
// return movieData?.boxOfficeResult.dailyBoxOfficeList.count ?? 0
// 처럼 많이 사용함
return 10
}
// MARK: - 셀 내용 구성
// 각 셀에 어떤 데이터를 넣을지 결정
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
// 재사용 가능한 셀 가져오기
// dequeueReusableCell:
// 셀을 새로 계속 만드는 것이 아니라
// 기존 셀을 재사용해서 성능 향상
let cell = tableView.dequeueReusableCell(
withIdentifier: "myCell",
for: indexPath
) as! MyTableViewCell
// 다운캐스팅(as!)
// UITableViewCell -> MyTableViewCell 변환
// 서버에서 받아온 영화 제목 표시
// movieData? :
// Optional 안전 접근
// indexPath.row :
// 현재 몇 번째 셀인지
cell.movieName.text =
movieData?.boxOfficeResult
.dailyBoxOfficeList[indexPath.row]
.movieNm
// 테스트용 배열 사용 코드
// cell.movieName.text = name[indexPath.row]
// 셀 반환
return cell
}
// MARK: - 섹션 개수
func numberOfSections(in tableView: UITableView) -> Int {
// 섹션 1개
return 1
}
// MARK: - 화면 로드 시 실행
override func viewDidLoad() {
super.viewDidLoad()
// 테이블뷰의 delegate 연결
// delegate:
// 셀 선택, 높이 등 이벤트 처리
table.delegate = self
// dataSource:
// 셀 데이터 공급
table.dataSource = self
// 서버 데이터 요청 시작
getData()
}
// MARK: - 네트워크 함수
func getData(){
// =========================
// 1단계 - URL 생성
// =========================
// 문자열 주소 -> URL 객체 변환
guard let url = URL(string: movieURL)
else { return }
// =========================
// 2단계 - URLSession 생성
// =========================
// 인터넷 통신 객체
let session =
URLSession(configuration: .default)
// =========================
// 3단계 - 데이터 요청
// =========================
let task = session.dataTask(with: url) {
data, response, error in
// error:
// 네트워크 실패 정보
// =========================
// 에러 확인
// =========================
if error != nil{
// 에러 출력
print(error!)
// 함수 종료
return
}
// =========================
// 데이터 안전 추출
// =========================
// data는 Optional(Data?)
guard let JSONdata = data
else { return }
// 서버에서 받은 원본 데이터 크기 출력
// print(JSONdata)
// =========================
// Data -> String 변환
// =========================
// JSON 내용을 문자열로 확인 가능
let dataString =
String(data: JSONdata,
encoding: .utf8)
// 실제 JSON 확인
// print(dataString!)
// =========================
// JSONDecoder 생성
// =========================
let decoder = JSONDecoder()
// =========================
// JSON 파싱
// =========================
do{
// JSON -> MovieData 구조체 변환
let decosedData =
try decoder.decode(
MovieData.self,
from: JSONdata
)
// 첫 번째 영화 정보 출력
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.movieNm
)
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.audiAcc
)
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.audiCnt
)
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.rank
)
// 현재 ViewController의
// movieData 속성에 저장
self.movieData = decosedData
// =========================
// 메인 스레드에서 UI 업데이트
// =========================
// 네트워크는 백그라운드 스레드
// UI 수정은 반드시 메인 스레드
DispatchQueue.main.async(){
// 테이블뷰 새로고침
// 다시
// numberOfRowsInSection
// cellForRowAt
// 호출됨
self.table.reloadData()
}
}catch{
// 디코딩 실패 시 에러 출력
print(error)
}
}
// =========================
// 4단계 - 네트워크 시작
// =========================
// resume() 안 하면 실행 안 됨
task.resume()
}
}
주요 코드

//
// ViewController.swift
// Moviekhw
//
import UIKit
// ======================================================
// MARK: - JSON 구조체
// ======================================================
// 서버에서 받아오는 JSON 구조와
// 동일한 형태로 구조체를 생성해야 함
// 가장 바깥 JSON 구조
//
// {
// "boxOfficeResult" : { ... }
// }
struct MovieData : Codable {
// boxOfficeResult 저장
let boxOfficeResult : BoxOfficeResult
}
// boxOfficeResult 내부 구조
//
// "boxOfficeResult": {
// "dailyBoxOfficeList": [ ... ]
// }
struct BoxOfficeResult : Codable {
// 영화 배열 저장
let dailyBoxOfficeList : [DailyBoxOfficeList]
}
// 영화 1개의 정보 구조
//
// [
// {
// "movieNm":"슈퍼마리오",
// "audiCnt":"1000"
// }
// ]
struct DailyBoxOfficeList : Codable {
// 영화 제목
let movieNm : String
// 하루 관객 수
let audiCnt : String
// 누적 관객 수
let audiAcc : String
// 현재 순위
let rank : String
}
// ======================================================
// MARK: - ViewController
// ======================================================
class ViewController: UIViewController,
UITableViewDelegate,
UITableViewDataSource {
// ==================================================
// IBOutlet
// ==================================================
// 스토리보드의 테이블뷰 연결
@IBOutlet weak var table: UITableView!
// ==================================================
// 영화 데이터 저장 변수
// ==================================================
// 서버에서 받아온 데이터를 저장
// Optional(?)인 이유:
// 앱 시작 직후에는 아직 데이터가 없음
var movieData : MovieData?
// ==================================================
// API 주소
// ==================================================
// 영화진흥위원회(KOBIS) API
// targetDt=
// 뒤에 날짜를 붙여서 사용
var movieURL =
"https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=d32b85027905503dcfff4af4097262af&targetDt="
// ==================================================
// 테이블뷰 행 개수
// ==================================================
// 몇 개의 셀(row)을 만들지 결정
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int)
-> Int {
// 현재는 10개 고정
// 실제 앱에서는:
//
// return movieData?
// .boxOfficeResult
// .dailyBoxOfficeList.count ?? 0
//
// 많이 사용
return 10
}
// ==================================================
// 셀 내용 설정
// ==================================================
// 각 셀에 어떤 데이터를 넣을지 결정
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath)
-> UITableViewCell {
// 재사용 가능한 셀 가져오기
// withIdentifier:
// 스토리보드의 identifier 이름
let cell =
tableView.dequeueReusableCell(
withIdentifier: "myCell",
for: indexPath
) as! MyTableViewCell
// as!
// 다운캐스팅
// UITableViewCell
// ↓
// MyTableViewCell
// 현재 행(row)의 영화 제목 표시
// indexPath.row
// 현재 몇 번째 셀인지
cell.movieName.text =
movieData?
.boxOfficeResult
.dailyBoxOfficeList[indexPath.row]
.movieNm
// 완성된 셀 반환
return cell
}
// ==================================================
// 섹션 개수
// ==================================================
func numberOfSections(in tableView: UITableView)
-> Int {
// 섹션 1개
return 1
}
// ==================================================
// 화면 로드 시 실행
// ==================================================
override func viewDidLoad() {
super.viewDidLoad()
// delegate 연결
// 셀 선택 이벤트 등 처리
table.delegate = self
// dataSource 연결
// 테이블 데이터 공급
table.dataSource = self
// 어제 날짜 문자열 생성
// 예:
// 20260510
movieURL += makeYesterdayString()
// 최종 URL 예시
//
// https://.....&targetDt=20260510
// 서버 데이터 요청
getData()
}
// ==================================================
// 어제 날짜 문자열 생성 함수
// ==================================================
func makeYesterdayString() -> String {
// 현재 날짜에서 하루(-1일) 빼기
let y =
Calendar.current.date(
byAdding: .day,
value : -1,
to : Date()
)!
// DateFormatter 객체
// 날짜 형식 변환 담당
let dateF = DateFormatter()
// 원하는 날짜 형식
// yyyy = 년도
// MM = 월
// dd = 일
dateF.dateFormat = "yyyyMMdd"
// Date -> String 변환
let day = dateF.string(from: y)
// 문자열 반환
return day
}
// ==================================================
// 네트워크 함수
// ==================================================
func getData(){
// ==============================================
// 1단계 - URL 생성
// ==============================================
// 문자열 -> URL 객체 변환
guard let url =
URL(string: movieURL)
else { return }
// ==============================================
// 2단계 - URLSession 생성
// ==============================================
// 인터넷 통신 객체
let session =
URLSession(configuration: .default)
// ==============================================
// 3단계 - 데이터 요청
// ==============================================
let task =
session.dataTask(with: url) {
data, response, error in
// data
// 서버에서 받은 데이터
// response
// 서버 응답 정보
// error
// 오류 정보
// ==========================================
// 에러 체크
// ==========================================
if error != nil{
// 오류 출력
print(error!)
// 함수 종료
return
}
// ==========================================
// 데이터 안전 추출
// ==========================================
// data는 Optional(Data?)
guard let JSONdata = data
else { return }
// Data -> String 변환
// JSON 확인 가능
let dataString =
String(
data: JSONdata,
encoding: .utf8
)
// JSON 문자열 출력
// print(dataString!)
// ==========================================
// JSONDecoder 생성
// ==========================================
let decoder = JSONDecoder()
// ==========================================
// JSON 파싱
// ==========================================
do{
// JSON 데이터를
// MovieData 구조체로 변환
let decosedData =
try decoder.decode(
MovieData.self,
from: JSONdata
)
// 첫 번째 영화 제목 출력
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.movieNm
)
// 누적 관객 수 출력
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.audiAcc
)
// 하루 관객 수 출력
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.audiCnt
)
// 순위 출력
print(
decosedData
.boxOfficeResult
.dailyBoxOfficeList[0]
.rank
)
// 현재 ViewController의
// movieData 속성에 저장
self.movieData = decosedData
// ==========================================
// 메인 스레드 UI 업데이트
// ==========================================
// 네트워크는 백그라운드 스레드
// UI 수정은 반드시 메인 스레드
DispatchQueue.main.async(){
// 테이블뷰 새로고침
// 다시
// numberOfRowsInSection
// cellForRowAt
// 호출됨
self.table.reloadData()
}
}catch{
// JSON 파싱 실패
print(error)
}
}
// ==============================================
// 4단계 - 네트워크 시작
// ==============================================
// resume() 안 하면 실행 안 됨
task.resume()
}
}