
Xcode 새 프로젝트를 가져와서 열려고 하면 해당 프로젝트를 신뢰할 것인지 묻는 창이 뜬다. 신뢰하고 열기를 눌러주자.

혹시 연 프로젝트에서 실행 가능한 디바이스가 뜨지 않으면

Minimum Deployments의 iOS 버전을 낮추면 된다.

네트워크로 데이터를 가져오려면 위와 같은 과정을 거친다.
1단계. URL 만들기


failable initializer를 거쳐서 나온 인스턴스는 옵셔널로 감싸져 있다.
URL의 내용이 잘못될 가능성이 있기 때문에 옵셔널로 반환되는 것이다.

그래서 guard 문으로 감싸서 언래핑하도록 했다.
2단계. URLSession 만들기


URLSession을 이용해서 세션을 만든다. .default를 이용해서 기본 설정을 이용한다.
3단계. task 만들기


dataTask() 메서드를 이용해서 데이터를 받아오는 과정을 정의했다. 후행 클로저를 이용하였다.
data, response, error는 모두 옵셔널 타입이므로 적절한 처리를 하고 사용해야 한다.
4단계. resume()

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()
}

dataTask()의 반환값을 task에 저장하고 resume()을 사용해서 실행한다.

실행해보면 무언가가 받아진 것을 알 수 있다.
이제 이 스트림 바이트를 JSON 형태로 파싱하여 처리하면 된다.

UTF-8 방식으로 String 인스턴스를 만들어서 해당 내용을 출력하니 이제 원하던 형태가 보이기 시작했다.
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
}

이번에는 JSON을 파싱해서 구조체에 맞춰 파싱해보았다.

예외 처리를 해야 하는데 아무것도 하지 않아서 에러가 발생했다.
예외처리
1. try 추가
try decoder.decode(MovieData.self, from: jsonData)
2. do {} 로 감싼다.
do {
try decoder.decode(MovieData.self, from: jsonData)
}
3. catch {} 추가
do {
try decoder.decode(MovieData.self, from: jsonData)
} catch {
print(error)
}
메서드 전체 코드
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)
// let dataString = String(data: jsonData, encoding: .utf8)
// print(dataString!)
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MovieData.self, from: jsonData)
} catch {
print(error)
}
}
task.resume()
}
출력 결과

구조체를 이용해서 JSON의 데이터 중 필요한 부분만 추려서 가져온 것을 확인할 수 있다.

이런 식으로 원하는 부분만 가져올 수도 있다.

클로저 안에서 프로퍼티를 사용하려면 self.를 붙여주어야 한다.



영화 제목을 출력하려고 했는데 화면에 표시되지 않는다. 테이블의 내용을 바꿨으면 다시 갱신해줘야 하는데 그냥 화면에 출력했기 때문이다.
reload

reloadData()를 이용해서 다시 로드하는 메서드를 추가한다.

다시 실행해보니 이번에는 어떤 오류가 떴다.
reloadData()는 메인 스레드에서 실행되어야 한다고 한다.

DispatchQueue.main.async를 이용해서 메인 스레드에서 실행될 수 있도록 한다.

이제 잘 출력된다..!
어제 날짜 가져오기

최종 코드
import UIKit
// 영화 이름 배열 초기화
let name = ["범죄도시4","쿵푸팬더4", "스턴트맨", "포켓몬스터", "남은 인생 10년", "파묘", "극장판 실바니안 패밀리", "꼬마참새 리차드", "챌린져스", "고스트버스터즈"]
// JSON 데이터를 매핑할 Codable 구조체들을 정의
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
}
// ViewController 클래스 정의
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// 스토리보드에서 연결한 테이블 뷰 아웃렛
@IBOutlet weak var table: UITableView!
// 영화 데이터를 저장할 변수 선언
var movieData : MovieData?
// API 요청을 위한 URL 문자열 초기화
var movieURL = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=생략&targetDt="
// 뷰가 로딩될 때 호출되는 메서드
override func viewDidLoad() {
super.viewDidLoad()
// 테이블 뷰의 데이터 소스와 대리자(delegate)를 현재 뷰 컨트롤러로 설정
table.dataSource = self
table.delegate = self
// 어제 날짜 문자열을 만들어 API URL에 추가
movieURL += makeYesterDayString()
// 영화 데이터를 가져오는 함수 호출
getData()
}
// 어제 날짜를 'yyyyMMdd' 형식의 문자열로 반환하는 함수
func makeYesterDayString() -> String {
// 현재 날짜에서 하루를 빼서 어제 날짜를 계산
guard let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date()) else {
return ""
}
// 날짜 형식을 설정하기 위한 DateFormatter 인스턴스 생성
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd"
// 어제 날짜를 지정한 형식의 문자열로 변환
return dateFormatter.string(from: yesterday)
}
// API에서 영화 데이터를 가져오는 함수
func getData() {
// URL 문자열로부터 URL 인스턴스 생성
guard let url = URL(string: movieURL) else { return }
// 기본 구성의 URLSession 인스턴스 생성
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 }
// JSONDecoder 인스턴스를 사용해 JSON 데이터를 MovieData 타입으로 디코딩
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MovieData.self, from: jsonData)
// 디코딩된 데이터를 movieData 변수에 저장
self.movieData = decodedData
// 메인 스레드에서 테이블 뷰를 다시 로드하도록 지시
DispatchQueue.main.async {
self.table.reloadData()
}
} catch {
// 디코딩 실패시 에러 출력
print(error)
}
}
// 태스크 시작
task.resume()
}
// 테이블 뷰의 섹션당 행의 개수를 결정하는 함수
func tableView(_ tableView
리팩토링된 코드
import UIKit
// 영화 정보를 담을 구조체
struct Movie: Codable {
let name: String
// 추가적인 영화 정보 필드가 있다면 여기에 포함시킵니다.
}
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var movies: [Movie] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
fetchMovieData()
}
// 어제 날짜를 'yyyyMMdd' 형식의 문자열로 반환
func makeYesterdayString() -> String {
let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: Date())!
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyyMMdd"
return dateFormatter.string(from: yesterday)
}
// 영화 데이터를 가져오는 함수
func fetchMovieData() {
let yesterdayString = makeYesterdayString()
guard let url = URL(string: "https://api.example.com/movies?date=\(yesterdayString)") else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
do {
let decodedData = try JSONDecoder().decode([Movie].self, from: data)
DispatchQueue.main.async {
self.movies = decodedData
self.tableView.reloadData()
}
} catch {
print("Decoding error: \(error)")
}
}.resume()
}
}
// UITableViewDataSource 및 UITableViewDelegate 확장
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movies.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "MovieCell", for: indexPath)
cell.textLabel?.text = movies[indexPath.row].name
return cell
}
}

'공부 > Swift' 카테고리의 다른 글
| [iOS][12주차] 영화 상세 화면 만들기 (0) | 2024.05.23 |
|---|---|
| [iOS][11주차] 앱 만들기 진행 (0) | 2024.05.16 |
| [iOS][8, 9주차] 영화진흥위원회 오픈API 사용하기 (0) | 2024.05.02 |
| [iOS][7주차] 지난 과정 & 문법 복습 (2) | 2024.04.18 |
| [iOS][6주차] TableView & 간단한 앱 만들기 2 / 다운캐스팅, 옵셔널 (0) | 2024.04.11 |