위 두 게시글에서 이어지는 작업이다.
JSON을 사용하여 News API정보를 JSON으로 변환하여 Foundation데이터로 정보를 추출하여 TableView에 뉴스 title내용을 출력시키는 작업이다.
아래 첨부한 전체코드를 살펴보면 JSON데이터를 Foundation데이터로 변환하여 값을 다룰때 다운캐스팅을 굉장히 많아하는것을 볼 수 있다. 이는 JSON을 다룰 때 흔히 사용되는건지 잘 모르겠지만,,, 코드를 읽는데 많이 복잡했따. 다운캐스팅한걸 또하고 또하니 머리속에 정리가 되질않아 많이 형편없지만 그림으로 그려보았다. 그래서 그리면서 이해하는데 도움이 된것같아 다행이다.. 나중엔 더 예쁘게 그려볼게요..
# 구현 순서
1. HTTP 통신을 시도한다. -> URLSession
2. URL정보내 JSON데이터를 Foundation 데이터로 변환한다. -> JSONSerialization
3. 변환된 데이터를 TableView에 데이터 매칭을 시킨다. -> tableView메서드내 다운캐스팅으로 값에 접근
3-1. 데이터를 가져왔으니 뿌려줘야함 -> DispatchQueue.main.sync { TableViewProperty.reloadData() }
# 전체코드
# URL
enum NewsApi {
static let url = "https://newsapi.org/v2/top-headlines?country=kr&apiKey=cc0f1ef9a14347e38975fecc11158ce5"
}
# TableViewMain
class TableViewMain: UITableViewCell {
@IBOutlet weak var label: UILabel!
}
# ViewController
// ViewController.swift
// NewsAPITableView
// Created by LIMGAUI on 2022/04/10
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var TableViewMain: UITableView!
// TableView에 테이터 매칭을 하기위해서 변수에 할당을 해줘야함
// tableView내에 중복코드가 발생하기떄문에 변수에 담아서 관리해주는게 좋음
var newsData: [[String: Any]]?
override func viewDidLoad() {
super.viewDidLoad()
setTableViewMainOwnerToSelf()
getNews()
}
}
// MARK: method
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let news = newsData {
return news.count
} else {
return .zero
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 1. TableView Cell개체를 반환하고 테이블에 추가한다.
let cell = TableViewMain.dequeueReusableCell(withIdentifier: "TableViewMain", for: indexPath) as! TableViewMain
let indexPathRow = indexPath.row
// 2. getNews메서드에서 추출한 Foudation news데이터로 접근한다.
if let news = newsData {
let rowData = news[indexPathRow]
if let row = rowData as? [String: Any] {
if let title = row["title"] as? String {
cell.label.text = title
}
}
}
return cell
}
func setTableViewMainOwnerToSelf() {
TableViewMain.delegate = self
TableViewMain.dataSource = self
}
func getNews() {
// 1. URL정보를 가져온다
guard let url = URL(string: NewsApi.url) else { return }
// 2. URL정보 가져오기 성공시 dataTask메서드를 실행한다.
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let newsData = data {
// 3-1. JSONSerialization.jsonObject메서드를 사용할때 변환을 실패할 수 있기때문에 do catch문내에서 작업해준다.
do {
// 3. JSON Parsing 작업을 시도한다. JSON -> Foundation데이터로 변환
guard let json = try JSONSerialization.jsonObject(with: newsData, options: []) as? [String: Any] else { return }
// 4. Parsing을 완료한 데이터로 읽어와야하는 값을 Dictionary Key로 접근하여 정보를 읽어온다.
guard let articles = json["articles"] as? [[String: Any]] else { return }
// 5. 정보를 외부 전역변수에 할당
self.newsData = articles
// 6. TableView정보의 값을 변경했으니 reloadData메서드를 TableView의 행과 섹션을 다시 로드합니다.(업데이트 작업)
// tableViewMain에 통보를 해줘야한다.
// 그러면 TableViewMain은 화면에 그리기 시작한다.
// 이때 중요한 개념이 하나나오는데 네트워크의 기본 원칙이 존재한다.
// 모바일은 네트워크를 통신하게되면 일하는 쓰레드 즉,일꾼이 존재한다.
// 그 일꾼들은 background: network에서 일하는데 현재 그려야하는 위치가 UI: Main에 해야하는것이다.
// 그래서 Main에 그려라라는 메서드인 DispatchQueue.main.async {}
// 비동기로 바로 작업을 해주라는 코드를 작성해주어야한다.
// 6-1. 위와같은 설명에 이유때문에 DispatchQueue내부에 넣어준다.
DispatchQueue.main.sync {
self.TableViewMain.reloadData()
}
} catch {}
}
}
// 7. 작업이 일시 중단된 경우 작업을 다시 시작한다.
task.resume()
}
}
중요한 내용인데 reloadData()메서드를 실행시킬때 모바일로 네트워크 통신을 할경우에는 background인 즉 내부에서 일꾼들이 일을 하다보니 내부에서 보여지는 작업이랑 UI에서 표시되는거랑은 상반된다고 한다. 예를들면 오리가 호수에서 발을 동동구르면 밖에서는 오리발이 보이지않는 것과 같은 현상 처럼 말이다. 그래서 UI에 노출을 시켜줄 수 있어야하는데 이때 사용하는게 DispatchQueue.main.sync 이다. 그래서 이 메서드 내에서 사용하게되면 사용자 UI에 데이터를 뿌려주는 역할이기때문에 정상적으로 업데이트되는걸 볼 수 있다.
만일 DispatchQueue.main.sync 를 사용하지않고 실행하게되면 하단의 사진처럼 보라색에러를 만나볼 수있다.
에러 메세지를 보면 must be used main thread only라고 말하고있다. main 즉, UI를 말하는것이다. background가 networt이고 main은 UI를 가르킨다고 볼 수 있다.
# 실행화면
- Reference
- https://newsapi.org/s/south-korea-news-api
- https://www.youtube.com/watch?v=5ejngRFNy_k
'iOS' 카테고리의 다른 글
[예약] TableView LifeCycle 공부예정 (0) | 2022.04.11 |
---|---|
[iOS] JSON개념공부 및 사용해보기(feat. Codable, Decoder, Encoder) (0) | 2022.04.10 |
[iOS] TableView만드는 두번째 방법(feat. 스토리보드+identifier지정) (0) | 2022.04.10 |
[iOS] TableView만드는 첫번째 방법(feat. 임의의 Cell 지정) (0) | 2022.04.10 |
[iOS] TableView란? 공식문서를 읽어보자 (0) | 2022.04.10 |