【Swift】非同期処理のAPIの結果を待って処理

こんにちは。
前回の記事でOpenCVのAPIを用意したので、それを使った簡単なiOSアプリを作ります。

GCP + Apache + mod-wsgi + Django 独自ドメインで公開

2020.05.22

アプリを作る際に悩むのがネイティブ(Xcode-Swift)かハイブリッド(Phonegap,fultter..)か。。Swiftは触った事がなくて、学習コストが高いので、JavascriptかPythonが使えたらいいのですがPhonegap設定で躓く躓く。。fultterも未経験でSwift同様で学習コストが高いので、もう腹をくくってネイティブ(Xcode-Swift)で行ってみます。フォトライブラリーを起動して写真を選択して、その写真をAPI向けにアップロードして結果を受け取り、処理する。だけのシンプルアプリだから、大丈夫でしょう。

 
まぁ、世の中そんなに甘くないよね。
 

mami
Swiftクセが強い(笑)

なので、今回は以下2点に絞ってお話します。

・APIにPOSTして結果をJSONで受取る
・非同期処理のAPIの結果を待って処理する

APIにPOSTして結果をJSONで受取る

API呼び出してJSONで受取るFuncを作ります。

func processAsyncFaceDetect(image: UIImage?){

    var face: FaceDect?
    let url = URL(string: "http://[api url]")
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)
    
    let boundary = UUID().uuidString

    var request = URLRequest(url: url!)
    request.httpMethod = "POST"
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

    var uploadData = Data()
    uploadData.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
    uploadData.append("Content-Disposition: form-data; name=\"image\"; filename=\"\(filename)\"\r\n".data(using: .utf8)!)
    uploadData.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
    uploadData.append((uploadimage?.jpegData(compressionQuality: 1.0)!)!)
    uploadData.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)

    session.uploadTask(with: request,from: image) { data, response, error in
        DispatchQueue.global().async {
            if(error != nil){
                print("\(error!.localizedDescription)")
            }    
            face = try! JSONDecoder.init().decode(FaceDect.self, from: data!)
        }
    }.resume()
}

struct FaceDect: Decodable {
    var success: Bool
    var num_faces: Int?
    let faces: [[Int]]?
}

非同期処理のAPIの結果を待って処理する

APIの結果を使いたいので、結果を待って次の処理をするようにします。
ちなみにこちらのサイトを殆どコピーさせて頂きました。ありがとうございます。

APIの結果が入ったらそれを通知するようにします。以下色付き行(1,29行目)の部分を変更します。

func processAsyncFaceDetect(image: UIImage? ,_ after:@escaping (FaceDect) -> ()){

    var face: FaceDect?
    
    let url = URL(string: "http://[api url]")
    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)
    
    let boundary = UUID().uuidString

    var request = URLRequest(url: url!)
    request.httpMethod = "POST"
    request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")

    var uploadData = Data()
    uploadData.append("\r\n--\(boundary)\r\n".data(using: .utf8)!)
    uploadData.append("Content-Disposition: form-data; name=\"image\"; filename=\"\(filename)\"\r\n".data(using: .utf8)!)
    uploadData.append("Content-Type: image/jpeg\r\n\r\n".data(using: .utf8)!)
    uploadData.append((uploadimage?.jpegData(compressionQuality: 1.0)!)!)
    uploadData.append("\r\n--\(boundary)--\r\n".data(using: .utf8)!)

    session.uploadTask(with: request,from: uploadData) { data, response, error in
        DispatchQueue.global().async {
            if(error != nil){
                print("\(error!.localizedDescription)")
            }
    
            face = try! JSONDecoder.init().decode(FaceDect.self, from: data!)
            after(face !)
        }
    }.resume()
}

struct FaceDect: Decodable {
    var success: Bool
    var num_faces: Int?
    let faces: [[Int]]?
}

上記の非同期処理Funcを作成したら、それを同期処理にするFuncを作成します。

func processSyncFaceDetect(image: UIImage?) -> FaceDect? {
    var result: FaceDect?
    let semaphore = DispatchSemaphore(value: 0)
    processAsyncFaceDetect(image: image) { (facerect: FaceDect) in
        result = facerect
        semaphore.signal()
    }
    semaphore.wait()
    return result
}

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)