👨‍🎓
Today I Learned
  • Today-I-Learend
  • 🍎WWDC
    • Developer Tools
      • Testing in Xcode
    • UIKit
      • UIDiffableDataSource
        • [WWDC 19] Advances in UI Data Sources
      • [WWDC2019] Advances in CollectionView Layout
  • 자료구조
    • Heap 자료구조
  • Clean code
    • 네이밍
    • 주석과 포맷팅
    • 함수
    • 클래스
    • 에러 핸들링
    • 가독성 높이기
    • 객체지향
  • Network
    • RestAPI
  • Swift
    • DateType
    • ARC
    • Availablity
    • KeyPath
    • Network
    • Never타입
    • Result
    • Selector
    • 검증함수
    • 메타타입
    • 동시성 프로그래밍
    • 메모리 안전
    • 에러처리
    • 접근제어 (Access Control)
    • 제네릭
    • 주요 프로토콜
  • 알고리즘
    • 그래프
    • 기초 알고리즘
    • 누적합(Prefix)
    • 복잡도
    • 비트마스킹
  • 운영체제
    • 운영체제의 개요
    • 프로세스와 스레드
    • CPU 스케줄링
    • 프로세스 동기화
    • 교착상태
    • 07. 메모리
    • 08.가상 메모리
    • 입출력 장치
    • 파일 시스템
  • UIKit
    • UITableView xib으로 만들어보기
  • 🖊️정보 기록
    • 코코아팟 배포하는 방법
  • iOS Project
    • 채팅 앱 만들기
      • Trouble shooting
      • 1. 디자인
      • 2. AutoLayout
    • 날씨 조회 어플리케이션
      • Figma를 이용한 UI 설계
      • TableView 연결하기
      • Networking
    • MVC -> MVVM으로 구조 변경해보기
      • MVC
      • MVVM
    • OAuth Project
      • 로컬 호스트를 이용한 로그인 페이지 제작
      • Github의 OAuth App 설정
    • Rest API 프로젝트
      • UI설계 (with Figma)
      • Network Model
      • MVVM 구조 전환
  • 🕶️UIKit
    • Compositional Layout
Powered by GitBook
On this page
  • Open Weather site
  • API 키 숨기는 방법
  • 네트워킹 코드 작성
  • Model 정의하기
  • Network Error 정의
  • NetworkManager 작성
  • Trouble Shooting
  • URL Error
  • APIKey GIt ignore 적용 안 됨
  1. iOS Project
  2. 날씨 조회 어플리케이션

Networking

Open Weather API를 이용해서 데이터를 받아옵니다.

PreviousTableView 연결하기NextMVC -> MVVM으로 구조 변경해보기

Last updated 2 years ago

Open Weather site

API 키 숨기는 방법

  1. Plist 파일 생성

  1. git ignore 설정

  1. key 딕셔너리 생성

  1. Bundle extension 작성

import Foundation

extension Bundle {
    var apiKey: String {
        guard let file = self.path(forResource: "APIKey", ofType: "plist") else { return "" }
        
        guard let resource = NSDictionary(contentsOfFile: file) else { return "" }
        
        guard let key = resource["APIKey"] as? String else {
            fatalError("API KEY ERROR")
        }
        return key
    }
}

네트워킹 코드 작성

Model 정의하기

내가 필요한 데이터는 오늘 (현재 온도, 날씨 아이콘) / 주간 (날짜, 최고 최저 온도, 날씨 아이콘)

struct NetworkData: Codable {
    let cod: String
    let message, cnt: Int
    let list: [List]
    let city: City
}

// MARK: - City
struct City: Codable {
    let id: Int
    let name: String
    let coord: Coord
    let country: String
}

// MARK: - Coord
struct Coord: Codable {
    let lat, lon: Int
}

// MARK: - List
struct List: Codable {
    let dt: Int
    let temperature: Temperature
    let weather: [Weather]
    let dtText: String
    
    enum CodingKeys: String, CodingKey {
        case dt
        case temperature = "main"
        case weather
        case dtText = "dt_txt"
    }
}

// MARK: - MainClass
struct Temperature: Codable {
    let temp, tempMin, tempMax: Double
    let tempKf: Double

    enum CodingKeys: String, CodingKey {
        case temp
        case tempMin = "temp_min"
        case tempMax = "temp_max"
        case tempKf = "temp_kf"
    }
    
    var celsius: Double {
        temp - 273.15
    }
    
    var maxCelsius: Double {
        tempMax  - 273.15
    }
    
    var minCelsius: Double {
        tempMin - 273.15
    }
    
    var furmula: Double {
        temp * 9 / 5 - 459.67
    }
    
    var minFurmula: Double {
        tempMin * 9 / 5 - 459.67
    }
    
    var maxFurmula: Double {
        tempMax * 9 / 5 - 459.67
    }
}

// MARK: - Weather
struct Weather: Codable {
    let id: Int
    let parameter: Parameter
    let description: String
    let icon: String
    
    enum CodingKeys: String, CodingKey {
        case id
        case parameter = "main"
        case description
        case icon
        
    }
}

enum Description: String, Codable {
    case brokenClouds = "broken clouds"
    case clearSky = "clear sky"
    case fewClouds = "few clouds"
    case lightRain = "light rain"
    case overcastClouds = "overcast clouds"
    case scatteredClouds = "scattered clouds"
}

enum Parameter: String, Codable {
    case clear = "Clear"
    case clouds = "Clouds"
    case rain = "Rain"
}

Network Error 정의

enum NetworkError: Error {
    case networkError
    case dataError
    case parseError
}

NetworkManager 작성

  • 해당 클래스는 상속이 일어나지 않으므로, final로 작성한다.

  • 클래스 외부에서 fetch request만 작성할 수 있도록 함수를 분리하여 pirvate으로 관리한다.

  • Singleton으로 설계하여 객체가 여러개 생성되는 것을 방지한다.

final class NetworkManager {
    
    static let shared = NetworkManager()
    
    typealias NetworkCompletion = (Result<[List], NetworkError>) -> Void
    
    func fetchData(completion: @escaping NetworkCompletion) {
        performRequest(with: "https://api.openweathermap.org/data/2.5/forecast?lat=37&lon=126&lang=kr&appid=\(Bundle.main.apiKey)") { result in
            completion(result)
        }
    }
    
    private func performRequest(with urlString: String, completion: @escaping NetworkCompletion) {
        
        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 {
                completion(.failure(.networkError))
                return
            }
            
            guard let safeData = data else {
                completion(.failure(.dataError))
                return
            }
            
            if let datas = self.parseJSON(safeData) {
                completion(.success(datas))
            } else {
                completion(.failure(.parseError))
            }
        }
        
        task.resume()
    }
    
    private func parseJSON(_ data: Data) -> [List]? {
        do {
            let data = try JSONDecoder().decode(NetworkData.self, from: data)
            return data.list
        } catch {
            return nil
        }
    }
}

Trouble Shooting

URL Error

finished with error [-1002] Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL"

NSErrorFailingURLStringKey
  • 이건 내가 앞에 https://를 붙여주지 않아서 나타난 에러였다.

  • 안전한 도메인인지 확인할 수 없을 때, iOS에서 자체적으로 네트워킹을 제한해서 발생한 문제이다.

    • 만약 해당 도메인을 사용해야한다면, 해당 도메인을 신뢰한다는 설정을 해줘야한다.

    • 검색 키워드: 예외 도메인 ATS(App Transport Security)에 대해 공부해보자.

APIKey GIt ignore 적용 안 됨

  • git status를 통해 확인해봤는데, 분명 git ignore에 있는 파일이 존재함

git update-index --skip-worktree WeatherApp/APIKey.plist 
  • 다시 포함시키고 싶을 때

git update-index --no-skip-worktree WeatherApp/APIKey.plist

를 확인하여 필요한 데이터를 기반으로 모델을 작성한다.

API 문서
출처: 나른한 코딩
https://openweathermap.org
WeatherApp/APIKey.plist는 포함되면 안 된다