킥보드 프로젝트 2일차
Kakao Map API V2를 사용하려 했으나,
Docs대로 구현 하던 중 메서드가 먹히지 않아 searchBar에 대한 부분만 해보려 한다.
우선 검색을 했을때 해당 주소의 지역의 값을 가져오게 하려고 한다.
searchBar 기능 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension ViewController: UISearchBarDelegate {
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.text = ""
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.endEditing(true)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
print(searchBar.text)
}
}
우선은 기본 틀만 잡아둔다.
KakaoMap REST API 호출
Docs에 알려주는대로 구현하면 될것 같다.
우선 헤더와 파라미터를 다르게 사용하기에 Alamofire을 사용해야 할 것으로 보인다.
1
2
3
4
5
6
7
8
9
10
func fetchRequest(textString: String) {
let url = "https://dapi.kakao.com/v2/local/search/address.json"
let header: HTTPHeaders = ["Authorization" : "KakaoAK {API KEY}"]
let parameter = ["query" : textString]
AF.request(url, method: .get, parameters: parameter, headers: header).responseDecodable(of: MapModel.self) { response in
print(response)
}
}
Decoding Error가 떠서 확인했는데 알고보니 Authorization 관련 Error였다.
엄한부분 파고들었던게 잘못이었다.
우선 모델링은 좌표값만 가져오려고 하기에 다음과 같이 구성을 하였다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct MapModel: Decodable {
let documents: [Document]
}
struct Document: Decodable {
let addressName: String
let x: String
let y: String
enum CodingKeys: String, CodingKey {
case addressName = "address_name"
case x
case y
}
}
이제 코드를 더 작성해서 넘기도록 하겠다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func fetchRequest(textString: String, completion: @escaping (Result<MapModel, Error>) -> Void) {
let url = "https://dapi.kakao.com/v2/local/search/address.json"
let header: HTTPHeaders = ["Authorization" : "KakaoAK API Key"]
let parameter = ["query" : textString]
AF.request(url, method: .get, parameters: parameter, headers: header).responseDecodable(of: MapModel.self) { response in
switch response.result {
case .success(let data):
completion(.success(data))
case .failure(let error):
completion(.failure(error))
}
}
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if let text = searchBar.text {
mapManager.fetchRequest(textString: text) { result in
switch result {
case .success(let data):
print(data)
case .failure(let error):
print(error)
}
}
}
}
출력은 잘된다.
다만 코엑스 이렇게 검색하는게 아니라, 진짜 찐 주소를 입력해야 가져오는 아주 큰 단점이 존재한다.
호출된 좌표값으로 지역 이동.
documents의 배열에 어차피 첫번쨰로 가기에 일단은 인덱스를 0으로 해두었다. 해당 부분은 추가로 수정 예정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
if let text = searchBar.text {
mapManager.fetchRequest(textString: text) { result in
switch result {
case .success(let data):
if let lat = Double(data.documents[0].y), let lon = Double(data.documents[0].x) {
DispatchQueue.main.async {
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: lat, longitude: lon), span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapView.setRegion(region, animated: true)
}
}
case .failure(let error):
print(error)
}
}
}
}
완료.
괜히 카카오 지도 쓰려다가 고생은 했지만, 손해본건 아니어서 좋은 경험이었다.
갑자기 AlamoFire를 쓰지않고도 구현해보는 연습이 필요해서 추가로 글을 작성한다
FetchRequest 재구현 (Without AlamoFire)
AF를 쓰지않고도 할 수 있을것 같아서 찾아보다가 사이트를 한번 봤는데, 생각보다 별거 없어서 구현해보려한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
func fetchRequestWithSession(textString: String, completion: @escaping (Result<MapModel, Error>) -> Void) {
let urlString = "https://dapi.kakao.com/v2/local/search/address.json"
let header: HTTPHeaders = ["Authorization" : "KakaoAK API Key"]
if let url = URL(string: urlString) {
var urlComponent = URLComponents(string: urlString)
urlComponent?.queryItems = [URLQueryItem(name: "query", value: textString)]
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.headers = header
let urlSession = URLSession(configuration: .default)
let task = urlSession.dataTask(with: url) { (data, response, error) in
if let e = error {
completion(.failure(e))
}
if let safeData = data {
let decodedData = self.decodingJson(data: safeData)
completion(.success(decodedData!))
}
}
task.resume()
}
}
func decodingJson (data: Data) -> MapModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MapModel.self, from: data)
let documents = decodedData.documents
let address = documents[0].addressName
let x = documents[0].x
let y = documents[0].y
var list: MapModel = MapModel(documents: [Document(addressName: address, x: x, y: y)])
return list
} catch {
print(error)
return nil
}
}
디코딩에러 아무래도, 또 Auth 에러로 보인다.
즉 설정한 헤더가 제대로 먹지 않았다고 생각이 든다.
문제점 확인
let task = urlSession.dataTask(with: url)
이부분이 문제였다.
with 부분에 url이 아닌 request로 들어가야 했던 문제였다.
헤더는 ` request.setValue(“KakaoAK API_Key”, forHTTPHeaderField: “Authorization”)` 이부분이 맞았다.
이제는 파라미터에 관한 에러가 뜬다.
혹시나 해서 request에서 query를 넣는 메소드가 있어서 해보았다.
request.url?.append(queryItems: [URLQueryItem(name: "query", value: "전북 삼성동 100")])
실행해보니 출력이 된다.
이제 이해했다.
그런데 왜 urlcomponent에서는 안되는지 좀 생각을 해봐야겠다.
뭐가 놓친게 있는듯하다.
urlcomponent의 url로 넘기니 해결이 되었다.
component 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
class NetworkManager {
func makeStringKoreanEncoded(_ string: String) -> String {
return string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? string
}
func fetchRequestWithSession(completion: @escaping (Result<MapModel, Error>) -> Void) {
let urlString = "https://dapi.kakao.com/v2/local/search/address.json"
if let url = URL(string: urlString) {
var urlComponent = URLComponents(string: urlString)
urlComponent?.queryItems = [URLQueryItem(name: "query", value: "전북 삼성동 100")]
let urlforrequest = urlComponent?.url
var request = URLRequest(url: urlforrequest!)
request.httpMethod = "GET"
request.setValue("KakaoAK API_KEY", forHTTPHeaderField: "Authorization")
let urlSession = URLSession(configuration: .default)
let task = urlSession.dataTask(with: request) { (data, response, error) in
if let e = error {
completion(.failure(e))
}
if let safeData = data {
if let decodedData = String(data: safeData, encoding: .utf8) {
print(decodedData)
let decod = self.decodingJson(data: safeData)
completion(.success(decod!))
} else {
print("decoding fail")
}
}
}
task.resume()
}
}
func decodingJson (data: Data) -> MapModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MapModel.self, from: data)
let documents = decodedData.documents
let address = documents[0].addressName
let x = documents[0].x
let y = documents[0].y
let list: MapModel = MapModel(documents: [Document(addressName: address, x: x, y: y)])
return list
} catch {
print(error)
return nil
}
}
}
component 미사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import Foundation
class NetworkManager {
func makeStringKoreanEncoded(_ string: String) -> String {
return string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? string
}
func fetchRequestWithSession(completion: @escaping (Result<MapModel, Error>) -> Void) {
let urlString = "https://dapi.kakao.com/v2/local/search/address.json"
if let url = URL(string: urlString) {
var request = URLRequest(url: urlforrequest!)
request.httpMethod = "GET"
request.url?.append(queryItems: [URLQueryItem(name: "query", value: "전북 삼성동 100")])
request.setValue("KakaoAK API_KEY", forHTTPHeaderField: "Authorization")
let urlSession = URLSession(configuration: .default)
let task = urlSession.dataTask(with: request) { (data, response, error) in
if let e = error {
completion(.failure(e))
}
if let safeData = data {
if let decodedData = String(data: safeData, encoding: .utf8) {
print(decodedData)
let decod = self.decodingJson(data: safeData)
completion(.success(decod!))
} else {
print("decoding fail")
}
}
}
task.resume()
}
}
func decodingJson (data: Data) -> MapModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(MapModel.self, from: data)
let documents = decodedData.documents
let address = documents[0].addressName
let x = documents[0].x
let y = documents[0].y
let list: MapModel = MapModel(documents: [Document(addressName: address, x: x, y: y)])
return list
} catch {
print(error)
return nil
}
}
}
끝.