Swift로 미세먼지 앱 만들기

2021. 4. 10. 17:19iOS 개발일지

학교 과제로 미세먼지를 보여주는 프로그램을 만들라기에 자신감 있게 iOS를 선택했습니다!

할 줄 아는게 iOS밖에 없어서...

과제도 이왕 만드는김에 제대로 만들어보자라고 생각해서 앱의 장점인 현재 위치를 받아와 주변 측정소의 미세먼지 값을 쓰기로 했어요.

 

 

앱 미리보기

 

 

미세먼지 값을 받아오려면 네트워크 통신이 필수적이었고, 현재 위치를 알아내야 했습니다.

 

그래서 서버와의 통신 전, 서버의 요청값에 보내줄 현재위치를 알아 내기 위해서 CoreLocation을 사용했어요.

 

 

info.plist에 먼저 위치정보 접근 허용을 받을때 이유를 설명해주기 위한 문자열을 추가한다.

 

// lazy로 선언하여 메모리 관리
    lazy var locationManager = CLLocationManager().then {
        // 10미터 이내의 정확도로 설정을 하여 배터리 관리 최적화
        $0.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
        // 거리 위치 변화를 감지하지 않음
        $0.distanceFilter = kCLHeadingFilterNone
        // 권한을 요청
        $0.requestWhenInUseAuthorization()
    }

그리고 locationMagager 인스턴스를 생성하고 몇가지 조건을 추가 해주었습니다.

 

    // 정보를 담을 struct 설정
    struct userLocation {
        var latitude: Double!
        var longitude: Double!
    }
    
    // 현재 좌표값 가져오기
   var info = userLocation()
   let coord = locationManager.location?.coordinate
   info.latitude = coord?.latitude
   info.longitude = coord?.longitude

그 후, 정보를 담을 struct를 만들고, 현재 좌표값을 받아 구조체에 넣어주었습니다.

 

그 후 문제가 생겼는데, 제가 사용할 API에서 넘겨줘야할 좌표값이 다르더라구요!

아래는 사용한 API주소인데, iOS에서 받아오는 좌표값은 WGS84 좌표값이었고, 근처 측정소를 찾기 위해선 TM좌표로 변환해야했습니다.

측정소 정보 : www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15073877

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

미세먼지 값 정보 : www.data.go.kr/tcs/dss/selectApiDataDetailView.do?publicDataPk=15073861

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

 

그래서 WGS84좌표값들을 변환해주기 위해 카카오 API를 사용했습니다.

이거 말고도 로컬로 변경할 수 있는 Extension이 있던데 이건 나중에 따로 공부해봐야 할 것 같네요...

developers.kakao.com/docs/latest/ko/local/dev-guide#trans-coord

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

// TM좌표로 변환
    func TM(url: String, longitude: Double, latitude: Double, handler: @escaping(userLocation) -> Void) {
        var result = userLocation()
        let headers:HTTPHeaders = ["Authorization" : kakaoKey]
        let parameters: Parameters = ["x" : longitude, "y" : latitude, "output_coord" : "TM"]
        let alamo = AF.request(url, method: .get,parameters: parameters, encoding: URLEncoding.queryString ,headers: headers)
        alamo.responseJSON() { response in
            switch response.result {
            case .success(let value):
                let json = JSON(value)
                let documents = json["documents"].arrayValue
                result.longitude = documents[0]["x"].double
                result.latitude = documents[0]["y"].double
                handler(result)
            case .failure(_):
                let alert = UIAlertController(title: nil, message: "네트워크를 다시 확인해주세요", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "확인", style: .default, handler: nil))
                self.present(alert, animated: true, completion: nil)
                return
            }
        }
    }

먼저 카카오 API를 통해 반환된 좌표값을 콜백 함수를 통해 빼내고, 근처 측정소를 받아오는 API에 값을 다시 넘겨주었습니다.

// 근처 측정소 받아오기
    func getNearbyMsrstn(url: String, tmX: Double, tmY: Double, handler: @escaping(String) -> Void) {
        let parameters: Parameters = [
            "serviceKey" : airKoreaKey,
            "tmX" : tmX,
            "tmY" : tmY,
            "returnType" : "json"
        ]
        
        let alamo = AF.request(url, method: .get,parameters: parameters, encoding: URLEncoding.default)
        alamo.responseJSON() { response in
            switch response.result {
            case .success(let value):
                let json = JSON(value)
                let stationName = json["response"]["body"]["items"][0]["stationName"].string!
                locationInfo.shared.stationName = stationName
                handler(stationName)
            case .failure(_):
                let alert = UIAlertController(title: nil, message: "네트워크를 다시 확인해주세요", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "확인", style: .default, handler: nil))
                self.present(alert, animated: true, completion: nil)
                return
            }
        }
    }

그 후 측정소의 이름을 활용해 제가 필요한 정보(미세먼지 값)을 받아오는 API를 한번 더 요청해 주었어요.

// 미세먼지 값 받아오기
    func getfinedust(url: String, stationName: String, handler: @escaping(String, String) -> Void) {
        let parameters: Parameters = [
            "serviceKey" : airKoreaKey,
            "stationName" : stationName,
            "dataTerm" : "DAILY",
            "informCode" : "PM10",
            "returnType" : "json"
        ]
        
        let alamo = AF.request(url, method: .get,parameters: parameters, encoding: URLEncoding.default)
        alamo.responseJSON() { response in
            switch response.result {
            case .success(let value):
                let json = JSON(value)
                let pm10Value = json["response"]["body"]["items"][0]["pm10Value"].string!
                let dataTime = json["response"]["body"]["items"][0]["dataTime"].string!
                locationInfo.shared.pmValue = pm10Value
                locationInfo.shared.dataTime = dataTime
                handler(pm10Value, dataTime)
            case .failure(_):
                let alert = UIAlertController(title: nil, message: "네트워크를 다시 확인해주세요", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "확인", style: .default, handler: nil))
                self.present(alert, animated: true, completion: nil)
                return
            }
        }
    }

 

이번에 로딩화면을 활용해보고 싶어서 이러한 처리를 로딩화면에서 하게 만들어주었는데, 그렇게 좋지는 못한 것 같네요.

로딩화면에서 정보를 다 처리한 후에 싱글톤 패턴을 이용하여 값을 저장하고, 그 값을 메인 화면에 값을 넘겨 주었습니다.

import Foundation


class locationInfo {
    static let shared = locationInfo()
    
    var nowLocationName: String?
    var longitude: Double?
    var latitude: Double?
    var pmValue: String?
    var dataTime: String?
    var stationName: String?

    private init() { }
}

확실히 비효율적인 로직이 많아보이는데, 더 공부해야할 게 많아보이네요.

그래도 싱글톤 패턴이라던지 Escaping Closure, CoreLocation등 처음 써본것들이 많아서 신기했고, Alamofire를 활용하는 법을 조금 더 배운거 같아 의미있는 프로젝트였던 것 같습니다.

 

'iOS 개발일지' 카테고리의 다른 글

Xcode Archive 멈춤현상 해결  (0) 2022.04.19