프로젝트를 하다 데이터를 불러와야 할 일이 생겨서 어떻게 할까 하다 json 형식으로 저장하고, 파싱하여 사용해 보기로 했다.
일단 한솥 메뉴를 가져와야 했는데,
저렇게 html 코드를 가져가서 지피티한테 붙여주면 json 형식으로 반환해준다. 지피티 진짜 최고잖아... 옛날엔 이거 파이썬으로 크롤링 해보고 그랬다.
무튼 그 결과물 :
다음과 같은 형식의 json 파일을 프로젝트 안에 로컬로 저장했고, 이제 Codable
프로토콜을 활용해 파싱해보도록 하자.
우선 MenuItem
struct를 만들고, Codable
프로토콜을 채택한다.
이 Codable
프로토콜은 Encodable
프로토콜과 Decodable
프로토콜이 결합된 것으로, 채택하면 구조체나 클래스 객체의 인코딩, 디코딩이 가능해진다.
struct MenuItem: Codable {
var name: String
var price: String
var image: String
var category: String
}
다음으로 로컬에 있는 Json 파일을 일단 객체로 로드해야 한다.
따라서 파일 이름을 가져와 Data
형식의 객체를 반환하는 함수를 생성해줌
func loadJsonData(filename: String) -> Data? {
guard let fileUrl = Bundle.main.url(forResource: filename, withExtension: "json") else {
return nil
}
return try? Data(contentsOf: fileUrl)
}
Bundle.main.url(forResource:withExtension:)
: 번들(애플리케이션 패키지) 내에 있는 지정된 리소스 파일의 URL을 반환한다. 여기서는 filename
이라는 이름과 json
확장자를 가진 파일을 찾음Data(contentsOf: fileUrl)
를 통해 데이터를 로드한다. 참고로 try? 는 Data(contentsOf: fileUrl)
가 오류를 던지면 nil을 반환한다.2번에서 Data로 반환된 객체를 swift 안에서 처리할 수 있도록 디코딩 해야 한다. Data객체를 받아 위에서 만든 [MenuItem
] 배열을 반환하는 함수.
func decodeMenuItems(from data: Data) -> [MenuItem]? {
let decoder = JSONDecoder()
do {
let menuData = try decoder.decode([String: [MenuItem]].self, from: data)
return menuData["Menu"]
} catch {
print("JSON 데이터를 디코딩하는 데 실패했습니다: \(error)")
return nil
}
}
decoder.decode(_:from:)
메서드는 주어진 데이터를 지정된 타입으로 디코딩한다. 여기서는 [String: [MenuItem]]
타입으로 디코딩 - 이는 JSON 데이터가 String 키와 MenuItem 객체 배열로 구성된 딕셔너리 형식임을 의미한다.위에서 만든 메서드들을 활용하여 menuItems
을 전역변수로 만들어 보자.
let menuItems: [MenuItem]? = {
if let data = loadJsonData(filename: "Menu") {
return decodeMenuItems(from: data)
}
return nil
}()
이제 menuItems
를 통해 프로젝트 파일 전체에서 디코딩된 json 데이터에 접근할 수 있다!