이번 주차에 보고 넘어갈것들
- 수집한 데이터 정리
- 수집한 데이터중 원하는 데이터만 가져오기
- 원하는 데이터를 화면에 출력하기
- 스택 뷰 관련
- 화면 제작
- 전 주차에서 추가 설명없이 이어서 하기에 전주차를 보고 오시는게 좋습니다.
- 이번 주차역시 사진이 많아 데이터로 볼경우 스압주의!
1. 파싱용 구조체 제작 이후 뽑을 데이터만 넣기

1-1. 파일 불러오기

1-2. JsonData를 MovieData로 디코딩 했지만 에러


1-3. 에러 핸들링


1-4. 에러 핸들링 후 1등 영화 이름과 관람객 수 뽑아보기




1-4. 프로퍼티에 decoderData 저장


클로저는 독립적인 코드 블록이다보니, 클로저 내에서 프로퍼티 접근시에는 self를 붙여야 오류가 안뜹니다.


1-5-1. 실행했는데 화면이 왜이러지?


몇번 대충 스크롤질 하다보면 다시 원래대로 나옵니다.
1-5-2. 문제 파악후 수정



1-6-1. 수정했더니 생전 처음보는 오류와 함께 크래시

좀전에도 말했듯 클로저는 독립적인 코드의 집합입니다.
하지만 독립 적인 코드 블록, 즉 메인 프로그램에 영향을 줄수 있는 코드를 메인 쓰레드가 아닌,
클로저 내에서 (메인 쓰레드 바깥에서) 처리해 생기는 문제입니다.
UITableView.reloadData() must be used from main thread only.
번역 : UITableView.reloadData()는 반드시 메인 쓰레드 내에서만 실행(사용)되어야 합니다.
AI도 말하는게 조금 달라서 그렇지 대략적인 설명은 같습니다.


크래시가 나면 첫번째 처럼 보라색 경고가 뜬뒤, 조금 있다가 두번째 사진으로 자동으로 넘어갑니다.


1-6-2. UI관련은 메인 쓰레드에서만

관련 오류 해결후 이번엔 관람객 수만 뽑아낸 결과


1-7. 날짜가 자동으로 갱신되게 만들기

가끔 다 수정하고도 간혹 왼쪽 사진처럼 뜰때가 있는데, 무시하고 스크롤하면 됩니다.


2. 뷰 만들고 수정하기

2-1. 스택 뷰

2-2. 스택 뷰의 4가지 제약조건

2-3. 스택 뷰 설정값

2-4. 제약조건이 걸린 디자인을 수정시에는 제약조건을 반드시 삭제


2-5. 제약조건 보다 더 좋은 스택뷰로 대신하기

2-6. 스택 뷰 활용





2-7. 텍스트 수정


스택뷰로 강력하게 잡혀져 있기 때문에 화면을 돌리더라도, 비율이 자동적으로 맞춰져서 수정되어 표시됩니다.

3. 하위 클래스 수정하기


3-1. 이름에 맞게 수정

간혹, movieData에 왜 ?를 붙일까 할수도 있지만, 연결이 잘안되었거나,
데이터를 못가져왔거나 등의 문제를 막아주기 위해서 존재합니다.
(못가져오더라도 일단은 실행하고, 추후 못불러왔다는 내용의 추가를 하면 되기 때문)


3-2. 등수 표시와 세세한 표시
(마지막 전체 본문 코드에 기록되어 있습니다.)

3-3. 글 넣기


3-4. 제목이 너무 길어서 ...로 표시될때

2가 아닌 0인 경우 줄이 끝없이 (제한없이) 늘어나서 통일감이 깨지기에 비추천합니다.


- - - 모든것이 작성된 전체 본문 코드 - - -
import UIKit
let name = ["1등","2등","3등","4등","5등"]
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {
@IBOutlet weak var table: UITableView!
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
}
var movieData : MovieData?
var movieURL = "자신의 키를 넣으세요"
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() {
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 }
let dataString = String(data: JSONdata, encoding: .utf8)
let decoder = JSONDecoder()
do {
let decodedData =
try decoder.decode(MovieData.self, from: JSONdata)
self.movieData = decodedData
DispatchQueue.main.async { self.table.reloadData() }
} catch { print(error) }
}
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
guard let mRank = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].rank else {return UITableViewCell()}
guard let mName = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].movieNm else {return UITableViewCell()}
cell.movieName.text = "[\(mRank)위] \(mName)"
if let aCnt = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiCnt {
let numF = NumberFormatter()
numF.numberStyle = .decimal
let aCount = Int(aCnt)!
let result = numF.string(for: aCount)!+"명"
cell.audiCount.text = "어제: \(result)"
}
if let aAcc = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiAcc {
let numF = NumberFormatter()
numF.numberStyle = .decimal
let aAcc1 = Int(aAcc)!
let result = numF.string(for: aAcc1)!+"명"
cell.audiAccumulate.text = "누적: \(result)"
}
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "🍿박스오피스(영화진흥위원회제공:"+makeYesterdayString()+")🍿"
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return "made by SSI"
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{ print(indexPath.description) }
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
}'실무 (iOS)' 카테고리의 다른 글
| iOS 프로그래밍 실무 12주차 [Open API 앱개발 완성하기] (0) | 2025.05.25 |
|---|---|
| iOS 프로그래밍실무 10주차 [ Open API 기반 앱 개발 1] (1) | 2025.05.10 |
| iOS 프로그래밍 실무 9주차 (Restful , JSON , Open API 앱 개발) (4) | 2025.05.03 |
| iOS 프로그래밍 실무 (7주차) [ 클래스 , 구조체 , 열거형 ] (0) | 2025.04.19 |
| iOS프로그래밍 실무 (6주차) [옵셔널 체이닝 , Error handling , generic , array] (0) | 2025.04.10 |
댓글