LoginSignup
1
1

「Swift5」オブジェクト指向でAPI通信を実装してみると、意外と簡単だった件

Last updated at Posted at 2022-08-08

はじめに

今回は実際にOpenWeatherMapのAPIを使ってサンプルアプリをオブジェクト指向で実装していきます。

開発環境

Xcode 13.4.1
Swift5

この記事の対象者

・SwiftでAPI通信を実装したい方
・API通信の実装方法は理解したが、オブジェクト指向での実装方法を知りたい方
・サンプルアプリを使ってみたい方
・Alamofire等のライブラリを使わず実装したい方

クラスの説明

・DataManager :APIから取得したデータを格納するためのstruct等を記述するクラス
・MainViewController :UI操作をするメインのクラス
・DataController :URLセッション等のメソッドを記述するクラス

実装手順

①Open Weather Mapのサイトに登録してキーを取得

②APIから取得したデータを格納するためのstructをDataManagerに記述

③DataControllerでURLセッション等を記述

④MainViewControllerでDataControllerのURLセッションを呼び出す

解説

①Open Weather Mapのサイトに登録してキーを取得

Open Weather Mapとは

基本的には無料で利用できる天気予報APIです。
20200914_auto_001.jpg
有料版と無料版での機能を比較すると、リクエスト回数の制限や取得できる天気予報の日数に違いがありますが無料版で全然大丈夫です。

APIキー取得方法

会員登録

Open Weather MapでSign in(会員登録)→ 『Create an Account』→ 『Purpose』利用目的を記入
→『Company』は記入不要  → Saveボタン → メール認証 → 登録完了

APIキーを取得

ユーザー名をタップ → API keysタブ → Keyの下に表示されているのがあなたのAPIキーになります。

②APIから取得したデータを格納するためのstructをDataManagerに記述

1、まずDataManagerクラスを作成する
中身は空でいい。なぜならただstructをまとめて記述してるだけだから。
2、DataManagerクラスの外にDecodableを継承したstructを記述
どのファイルからでもアクセスしやすくするため

import UIKit
import Foundation
class DataManager: NSObject {
    
}
//mainの情報
struct main_info : Decodable{
    //平均気温
    let temp: Double
    //湿度
    let humidity: Double
}
//weatherの情報
struct weather_info : Decodable{
    //天気の状態
    let description: String
}
struct ReceiveData {
    var statusCode: Int
    var data: Data?
    var result:Bool
}

③MainViewControllerでDataControllerのURLセッションを呼び出す

1、NSObjectを継承したDataControllerクラスを作成

import Foundation
let connectURL = "https://api.openweathermap.org/data/2.5/weather?"
class DataController: NSObject {


}

2、APIリクエストの準備をするメソッドを作成
class func get_tempメソッド: 引数にプロパティの値を指定できるようにする
URLQueryItem: URLのプロパティとその値を追加
request.httpMethod: API通信を記述(GET,POST,PUT)
詳しくは(超簡単)SwiftでAPIを叩いてサーバーから情報を取得する方法を参照
return session(request: request): 戻り値でsessionメソッドを呼び出す

// MARK: 指定した都道府県の天気情報を取得(リクエスト)
    class func get_temp(lat: String, lon: String, appid: String) -> ReceiveData {
        var urlComponents = URLComponents(string: connectURL)!
        urlComponents.queryItems = [
            //URLのプロパティとその値を追加
            URLQueryItem(name: "lat", value: lat),
            URLQueryItem(name: "lon", value: lon),
            URLQueryItem(name: "appid", value: appid),
            URLQueryItem(name: "lang", value: "ja"),
            URLQueryItem(name: "units", value: "metric")
        ]
        var request = URLRequest(url: urlComponents.url!)
        request.httpMethod = "POST"
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpBody = urlComponents.percentEncodedQuery?.data(using: .utf8)
        
        return session(request: request)
    }

3、非同期でデータを受信(レスポンス)

//MARK: 非同期でデータを受信(レスポンス)
    class func session(request: URLRequest) -> ReceiveData {
        
        // セマフォの準備
        let semaphore = DispatchSemaphore(value: 0)
        //ここでクエリ結果を受け取る
        var receiveData: ReceiveData = ReceiveData(statusCode: 0, data: nil, result: false)
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in  //非同期で通信を行う
            if ((error) != nil) {
                // 受信エラー
                print("受信エラー:\(String(describing: error?.localizedDescription))")
                semaphore.signal()
            }
            else {
                guard let data = data else { return }
                if let response = response as? HTTPURLResponse {
                    receiveData.statusCode = response.statusCode
                }
                
                if receiveData.statusCode != 200 {
                    // 受信エラー
                    print("受信エラー")
                    semaphore.signal()
                }
                else {
                    receiveData.data = data
                    semaphore.signal()
                }
            }
        }
        task.resume()
        
        semaphore.wait()
        //statusCodeを出力
        print(receiveData.statusCode)
        //requestのURLを出力
        print(request)
        //取得した生のデータを出力
        let str: String? = String(data: receiveData.data!, encoding: .utf8)
        print(str)
        
        
        return receiveData
    }

全体のコードを載せておきます

import Foundation
//OpenWeatherMapにアクセスするためのURL
let connectURL = "https://api.openweathermap.org/data/2.5/weather?"

class DataController: NSObject {
    //MARK: 非同期でデータを受信(レスポンス)
    class func session(request: URLRequest) -> ReceiveData {
        
        // セマフォの準備
        let semaphore = DispatchSemaphore(value: 0)
        //ここでクエリ結果を受け取る
        var receiveData: ReceiveData = ReceiveData(statusCode: 0, data: nil, result: false)
        let task = URLSession.shared.dataTask(with: request) { (data, response, error) in  //非同期で通信を行う
            if ((error) != nil) {
                // 受信エラー
                print("受信エラー:\(String(describing: error?.localizedDescription))")
                semaphore.signal()
            }
            else {
                guard let data = data else { return }
                if let response = response as? HTTPURLResponse {
                    receiveData.statusCode = response.statusCode
                }
                
                if receiveData.statusCode != 200 {
                    // 受信エラー
                    print("受信エラー")
                    semaphore.signal()
                }
                else {
                    receiveData.data = data
                    semaphore.signal()
                }
            }
        }
        task.resume()
        
        semaphore.wait()
        //statusCodeを出力
        print(receiveData.statusCode)
        //requestのURLを出力
        print(request)
        //取得した生のデータを出力
        let str: String? = String(data: receiveData.data!, encoding: .utf8)
        print(str)
        
        
        return receiveData
    }
    
    // MARK: 指定した都道府県の天気情報を取得(リクエスト)
    class func get_temp(lat: String, lon: String, appid: String) -> ReceiveData {
        var urlComponents = URLComponents(string: connectURL)!
        urlComponents.queryItems = [
            //URLQueryItemでURLのプロパティを追加
            URLQueryItem(name: "lat", value: lat),
            URLQueryItem(name: "lon", value: lon),
            URLQueryItem(name: "appid", value: appid),
            URLQueryItem(name: "lang", value: "ja"),
            URLQueryItem(name: "units", value: "metric")
        ]
        var request = URLRequest(url: urlComponents.url!)
        request.httpMethod = "POST"
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpBody = urlComponents.percentEncodedQuery?.data(using: .utf8)
        
        return session(request: request)
    }
}



おわりに

ここまで記事を読んでいただきありがとうございます。
今回の内容は非常に基礎だと思いますが、意外と記述の仕方に迷ったので共有しておきます。
またもっと簡単に実装した場合は(超簡単)SwiftでAPIを叩いてサーバーから情報を取得する方法を閲覧してください。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1