네트워크 서버 통신 코드
서버에서 원하는 데이터를 받아와 사용하는 기본 개념:
1. 서버에 데이터 요청(request)
2. JSON 형태로 받은 서버 데이터를 분석(Parsing)
3. Parse된 서버 데이터를 Struct / Class로 변환(Decoding)
JSON이란?)
- JavaScript Object Notation의 약자
- 데이터 용량이 커질수밖에 없는 마크업 태그를 사용하는 기존 XML 방식을 극복하기 위해 만들어진 경량의 데이터 교환 형식.
- 프로그래밍 언어와 플랫폼에 의존적이지 않고 독립적
- key : value 로 쌍을 이루는 Dictionary 형식. key는 무조건 String(문자열)만 가능
- JSON 형태로 받은 데이터는 그대로 사용할 수 없고, 파싱을 통해 프로그램이나 시스템에서 처리하기 쉬운 형태로 변환해야 함.
app.quicktype.io 사이트를 통해 JSON 데이터를 swift 구조체/ 클래스 등의 필요한 형식으로 parsing & decoding 가능.
헷갈렸던 부분) JSON parsing은 JSON 데이터를 읽고 분석하여 일반적으로 문자열이나 데이터 구조로 변환하는 과정을 의미하며, JSON decoding은 JSON 데이터를 프로그래밍 언어의 특정 데이터 타입으로 변환하는 과정을 의미. decoding 과정에서는 해당 프로그래밍 언어의 데이터 타입으로 매핑된 JSON 데이터 중 필요한 정보를 추출하여 해당 데이터 타입의 객체에 저장까지 하므로 JSON decoding이 일반적으로 JSON parsing 이후에 이루어지는 단계라고 보면 됨. 즉, JSON parsing이 먼저 이루어지고, 그 다음에 파싱된 데이터를 프로그래밍 언어의 데이터 타입으로 변환하는 디코딩 단계가 이어지는 것.
// 네트워크 통신을 코드로 하면 아래처럼..실제로는 주로 통신 라이브러리 사용해서 만듦
//서버에서 받은 JSON 데이터 parsing 한 것 예시
struct MusicData: Codable {
let dailyTopTenList : [DailyTopTenList]
struct DailyTopTenList : Codable {
let rank: String
let musicTitle: String
let uploadDate: String
}
struct Music {
// 서버에서 주는 데이터를 parsing한 후 사용하고자 하는 데이터를 채택/변환하여 struct나 class 생성
}
struct MusicDataManager {
//아래 일련의 코드를 통해 서버와 통신해서 데이터 받아오게 됨.
let musicURL = "//openAPI url 등 서버 주소 기입"
let myKey = "//openAPI에서 발급받은 개인 키 기입"
func fetchMusic(date: String, completion: @escaping ([Music]?) -> Void) {
let urlString = "\(musicURL)&key=\(myKey)&targetDt=\(date)"
performRequest(with: urlString) { musics in
completion(musics)
}
}
func performRequest(with urlString: String, completion: @escaping ([Music]?) -> Void) {
guard let url = URL(string: urlString) else { return }
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!)
completion(nil)
return
}
guard let response = response as?HTTPURLREsponse,(200...<299)~= response.statusCode else {
print("Error:HTTP request failed")
return
}
guard let safeData = data else {
completion(nil)
return
}
// 클로저에서 객체의 메서드를 이용하려면 self를 붙여줘야하는 것 유의
if let musics = self.parseJSON(safeData) {
completion(musics)
} else {
completion(nil)
}
}
task.resume()
}
func parseJSON(_ musicData: Data) -> [Music]? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MusicData.self, from: musicData)
let dailyLists = decodedData.dailyTopTenList
let myMusiclists = dailyLists.map {
Music(rank: $0.rank, musicTitle: $0.musicTitle, uploadDate: $0.uploadDate)
}
return myMusiclists
} catch {
//print(error.localizedDescription)
// (파싱 실패 에러)
print("파싱 실패")
return nil
}
}
}
//만들어둔 musicDataManager 뷰컨트롤러에서 활용 예시
var downloadedMusics = [Music]()
let musicManager = MusicDataManager()
musicManager.fetchMusic(date: "20210201") { (musics) in
if let musics = musics {
downloadedMusics = musics
dump(downloadedMusics)
} else {
print("음악데이터가 없거나 다운로드에 실패했습니다.")
}
}