web-dev-qa-db-ja.com

Swift URLセッションとURLリクエストが機能しない

この投稿 と非常によく似た問題が発生していますが、答えが完全にわかりません。完了ハンドラを作成しましたが、期待どおりに動作していないようです。

func updateTeam(teamID: Int) {
    startConnection {NSArray, Int in
        //Do things with NSArray
    }
}

func startConnection(completion: (NSArray, Int) -> Void) {
    let url = URL(string: "http://www.example.com/path")
    var request : URLRequest = URLRequest(url: url!)
    request.httpMethod = "POST"
    let postString = "a=\(Int(teamInput.text!)!)"
    request.httpBody = postString.data(using: .utf8)

    let dataTask = URLSession.shared.dataTask(with: request) {
        data,response,error in
        print("anything")
        do {
            if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
                self.teamResult = jsonResult
                print(jsonResult)
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }

    }
    dataTask.resume()

    completion(NSArray(object: teamResult), Int(teamInput.text!)!)
}

結果のデータを使用しようとする前に、dataTaskステートメント内の何も実行されていないようです、または少なくとも完了していません。この完了ハンドラーの何が問題になっていますか?

前もって感謝します!

8
D. Cohen

コードが正しく構造化されていません。

URLSessionは、非同期で実行されるタスクを作成します。タスクを設定し、完了ブロックを渡すか、デリゲートを設定します。

Task.resume()呼び出しは、ネットワークのダウンロードが完了するずっと前に、すぐに戻ります。

タスクが完了すると、システムは完了ハンドラ(またはデリゲートスタイルを使用している場合はデリゲート)を呼び出します。

URLSessionsの完了ハンドラーとデリゲート呼び出しはバックグラウンドスレッドで行われることに注意してください。タスクの完了に応答してUIKit呼び出しを行う場合は、メインスレッドで行う必要があります。

@keithbhunterがコメントで述べているように、タスクの完了ハンドラー内に完了ハンドラーへの呼び出しを配置する必要があります。メインスレッドの呼び出しで完了ハンドラーの呼び出し全体をラップするのがおそらく最も安全です。

func startConnection(completion: (NSArray, Int) -> Void) {
    let url = URL(string: "http://www.example.com/path")
    var request : URLRequest = URLRequest(url: url!)
    request.httpMethod = "POST"
    let postString = "a=\(Int(teamInput.text!)!)"
    request.httpBody = postString.data(using: .utf8)

    let dataTask = URLSession.shared.dataTask(with: request) {
        data,response,error in
        print("anything")
        do {
            if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
                self.teamResult = jsonResult
                print(jsonResult)
                //Use GCD to invoke the completion handler on the main thread
                DispatchQueue.main.async() {
                  completion(NSArray(object: teamResult), Int(teamInput.text!)!)
                }
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }
    }
    dataTask.resume()
}

TeamInput.textの強制アンラップは非常に壊れやすく、teamInput.textがnilの場合、またはIntに変換できない場合はクラッシュすることに注意してください。データとteamInput.textから返されるint値の両方のオプションを取るように完了ハンドラーを作成する方がはるかに良いでしょう。

func startConnection(completion: (NSArray?, Int?) -> Void) {

オプションで渡して呼び出す:

let value: Int? = teamInput.text != nil ? Int(teamInput.text!) : nil
completion(NSArray(object: teamResult), value)
10
Duncan C

閉鎖時のエラーも処理する必要があると思います。

func updateTeam(teamID: Int) {
    startConnection {array, teamId, error in
        // Do things with NSArray or handle error
    }
}

func startConnection(completion: @escaping (NSArray?, Int, Error?) -> Void) {
    let url = URL(string: "http://www.example.com/path")
    var request : URLRequest = URLRequest(url: url!)
    request.httpMethod = "POST"
    let postString = "a=\(Int(teamInput.text!)!)"
    request.httpBody = postString.data(using: .utf8)

    let dataTask = URLSession.shared.dataTask(with: request) {
        data,response,error in
        print("anything")
        do {
            if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary {
                self.teamResult = jsonResult
                print(jsonResult)
                DispatchQueue.main.async() {
                    completion(NSArray(object: self.teamResult), Int(teamInput.text!)!, nil)
                }
        } catch let error as NSError {
            print(error.localizedDescription)
            DispatchQueue.main.async() {  
                completion(nil, Int(teamInput.text!)!, error)
            }
        }

    }
    dataTask.resume()
}
3
abdullahselek

これを試して:

let urlString = "www.yoururl.com"
let url = URL(string: string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)

これは私に何度も役立ちました

0
henrik-dmg