일하고 있는 팀에서 새로 진행중인 프로젝트때문에 swift를 만지게 되었다.
웹뷰를 기반으로 하여 native코드로 몇가지 처리를 해준다고만 들었는데
가지수가 꽤 많은 것 같다.
역시 사람말은 믿으면 안된다.
여튼 프로젝트를 진행하면서 기존 안드로이드 앱의 구현을 위해 작동되고 있는 API를 활용하고 있다.
메인 페이지의 Data 와 유저의 상태에 따른 token값 변경으로 다른 동영상 데이터를 띄워줘야하는 그런 작업을 진행중이다.
그리하여 커스터마이즈된 데이터는 json형태로 받게 된다.
안타깝게도 기존의 회사에서 급했는지 jQuery,php조합으로 웹뷰가 구성이 되어있었고.. 따라서 native언어에서 json을 받아서 웹뷰가 구성되어있는 Html로 넘겨주는 것이 로직의 중복코드를 피할 수 있는 유일한 길이 되었다.
그래서 몇가지를 검색하고 삽질하였던 것을 기록하여본다 허허허..
private func parse(jsonData: Data){
do{
//decode
let mdata = try JSONDecoder().decode(getDataMeta.self, from: jsonData)
//encode
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let newMdata = try? encoder.encode(jsonData)
if let newMdata = newMdata, let MString = String(data: newMdata, encoding: .utf8){
print("newMdata", MString)
}
//serialize
let jsonResponse = try JSONSerialization.jsonObject(with: jsonData, options: [])
self.jsonDataFrom = mdata
// print("JSONDecoder", mdata)
print("JSONSerialization", mdata)
} catch{
print("decodeError: \(error)")
}
}
API로 부터 받는 데이터를 파싱하기 위해서 parse라는 함수를 별개로 만들어서 처리하려고 했다.
이것저것 구글링을 해보며 Encoding과 Decoding을 해보고 공식문서를 통해 차이점을 읽어보고 실행을 하려 하였으나 안타까운 사태가 많이 발생했다.
맞다 삽질의 시작이었다.
애초에 json파일을 출력할때 특별한 값을 설정해주지 않으면 "1004byte"와 같이 byte값이 전달된다
이를 설정을 통해 문자열로 변경하면 아래와 같은 난해한 문자가 생긴다 :)
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let newMdata = try? encoder.encode(jsonData)
if let newMdata = newMdata, let MString = String(data: newMdata, encoding: .utf8){
print("newMdata", MString)
}
encoder라는 변수에 JSONEncoder()를 담고 outputForamtting을 설정해 이쁘게 나타내보려 했으나 실패했고 .utf8설정을 통해 변경해주었다.
"eyJwcm9maWxlIjp7ImlkIjpudWxsLCJuYW1lIjpudWxsLCJwcm92aWRlciI6bnVsbCwidG9rZW4iOm51bGwsImVtYWlsIjpudWxsLCJnZW5kZXIiOiJtYWxlIiwidGh1bWIiOiJhc3NldHNcL2ltYWdlc1wvcHJvZmlsZV9zbWFsZS5wbmciLCJuZXdzIjoiMCJ9LCJjb250ZW50cyI6eyJkYWJpc3UiOnsiazEiOnsiZGF0YSI6W3siaWQiOiI2MzU0IiwidGl0bGUiOiIxXHViMmU4XHVhY2M0IiwidXJsIjoiZGFiaXN1X2sxXzEuaHRtbCIsInRodW1iIjoiYXNzZXRzXC9pbWFnZXNcL2RhYmlzdVwvazEtMS5wbmciLCJsb2NrIjowfSx7ImlkIjoi
..."
아래와 같이 나오는데 자세히 보면 nil타입이 정의되어 버리고 제대로된 JSON형태가 나오지 않게 된다. (컬리브레이스는 어디로..)
JSONDecoder getDataMeta(profile: downtest.profileMetadata(id: nil, name: nil, provider: nil, token: nil, email: nil, gender: "male", thumb: "assets/images/profile_smale.png", news: "0"), contents: downtest.contentsUpperMeta(abc: Optional(downtest.kDataType(k1: Optional(downtest.imageType(data: [downtest.idType(id: "6354", title: "abc", url: "abc.html", thumb: "assets/images/abc/k1-1.png", lock: 0), downtest.idType(id: "6355", title: "2단계", url: "abc.html", thumb: "assets/images/abc/k1-2.png", lock: 1),
...)
이 상태로 Javascript로 넘기게 된다면 parsingerror를 맞이할 수 있다.
이는 swift내부에서 사용할 수 있기 위해 decode가 되어버린 상태이기 때문이라 보면 된다.
unexpected token .... 이라는 지겹고도 지겨운 에러를..
코드에서 보이듯이 Struct에 대한 처리를 하나하나 다 해주지 않았기 때문에 적합한 형태가 나오지 않는다.
그리고 Serialize기능 자체가 예전에 주로 사용되었고 최근에는 이의 불편함을 해소하기 위해서 JSONEncoder와 같은 기능이 나왔으니 굳이 사용하지 말자.
여러 예제를 보니 보통할일이 아니다..(회문 돌고 struct설정해주고 뭐 ..)
JSONSerialization getDataMeta(profile: downtest.profileMetadata(id: nil, name: nil, provider: nil, token: nil, email: nil, gender: "male", thumb: "assets/images/profile_smale.png", news: "0"), contents: downtest.contentsUpperMeta(abc: Optional(downtest.kDataType(k1: Optional(downtest.imageType(data: [downtest.idType(id: "6354", title: "1단계", url: "avc.html", thumb: "assets/images/avc/k1-1.png", lock: 0), downtest.idType(id: "6355", title: "2단계", url: "abc.html", thumb: "assets/images/abc/k1-2.png", lock: 1), downtest.idType(id: "6357", title: "3단계", url: "abc.html", thumb: "assets/images/abc/k1-3.png", lock: 1),
//loadData with token for getting Json
public func loadData(token:String){
guard let url = URL(string:"http://abc.def.com/api/getdata?token=\(token)") else{return}
let task = URLSession.shared.dataTask(with: url){(data, response, error) in
guard let dataResponse = data,
error == nil else{
print(error?.localizedDescription ?? "Response Error")
return
}
do{
self.StringJson = try String(contentsOf: url)
self.parse(jsonData: dataResponse)
print(self.StringJson)
} catch{
print(error)
}
}
task.resume()
}
삽질과 삽질을 통해 발견한 방법이다.
self.StringJson = try String(contentsOf: url)
애초에 url로부터 들어오는 데이터의 contents.. 즉, 그냥 들어오는 contents를 곧바로 String타입으로 변경시켜서 html로 넘겨주면 되는 일이었다.
따로 JSON.parse()라던지의 절차도 필요없다..