web-dev-qa-db-ja.com

AlamoFire GET APIリクエストが期待どおりに機能しない

AlamoFireの使用方法を習得しようとしていますが、問題があります。

これまでの私の方法は次のとおりです:

func siteInfo()->String?{
    var info:NSDictionary!
    var str:String!
    Alamofire.request(.GET, MY_API_END_POINT).responseJSON {(request, response, JSON, error) in
        info = JSON as NSDictionary
        str = info["access_key"] as String
        //return str
    }
    return str
}

これは問題であるnilを返します。私が読んだもの here から、これはリクエストがしばらくかかることがあり、そのためクロージャーが戻るまで実行されないためです。戻り値をクロージャに移動するという提案された解決策は私にとっては機能せず、コンパイラは叫ぶだけです(->Stringの後に(request,response,JSON,error)を追加すると、「「String」はvoidのサブタイプではありません」。提供される他のソリューションについても同様です。

何か案は?この問題に関係なく、AlamoFireを使用するいくつかのソースコードも役立ちます。

ありがとう!

19
boidkan

これを処理する1つの方法は、クロージャー(通常はcompletionHandlerと呼びます)をsiteInfo関数に渡し、それを_Alamofire.request_のクロージャー内で呼び出すことです。

_func siteInfo(completionHandler: (String?, NSError?) -> ()) -> () {
    Alamofire.request(.GET, MY_API_END_POINT).responseJSON {
        (request, response, JSON, error) in

        let info = JSON as? NSDictionary // info will be nil if it's not an NSDictionary
        let str = info?["access_key"] as? String // str will be nil if info is nil or the value for "access_key" is not a String

        completionHandler(str, error)
    }
}
_

次に、次のように呼び出します(エラー処理を忘れないでください):

_siteInfo { (str, error) in
    if str != nil {
        // Use str value
    } else {
        // Handle error / nil value
    }
}
_

あなたが尋ねたコメントで:

では、クロージャーの内部でのみ行うことができ、クロージャーの外部のオブジェクトには影響を与えられない場合、取得リクエストから収集した情報をどのように保存しますか?また、リクエストが完了したことを追跡する方法は?

Getリクエストの結果は、クロージャーの内側からクラスのインスタンス変数に保存できます。クロージャがそれを妨げることは何もありません。そこから何をするかは、そのデータをどのように処理するかによって異なります。

例はどうですか?

リクエストを取得するアクセスキーフォームを取得しているように見えるため、他の関数で行われる将来のリクエストには、それが必要になる場合があります。

その場合、次のようなことができます。

注:非同期プログラミングは大きなトピックです。ここではカバーしきれません。これは、非同期リクエストから取得したデータを処理する方法の一例にすぎません。

_public class Site {
    private var _accessKey: String?

    private func getAccessKey(completionHandler: (String?, NSError?) -> ()) -> () {

        // If we already have an access key, call the completion handler with it immediately
        if let accessKey = self._accessKey {
            completionHandler(accessKey, nil)
        } else { // Otherwise request one
            Alamofire.request(.GET, MY_API_END_POINT).responseJSON {
                (request, response, JSON, error) in

                let info = JSON as? NSDictionary // info will be nil if it's not an NSDictionary
                let accessKey = info?["access_key"] as? String // accessKey will be nil if info is nil or the value for "access_key" is not a String

                self._accessKey = accessKey
                completionHandler(accessKey, error)
            }
        }
    }

    public func somethingNeedingAccessKey() {
        getAccessKey { (accessKey, error) in
            if accessKey != nil {
                // Use accessKey however you'd like here
                println(accessKey)
            } else {
                // Handle error / nil accessKey here
            }
        }
    }
}
_

この設定では、最初にsomethingNeedingAccessKey()を呼び出すと、アクセスキーを取得するリクエストがトリガーされます。その後のsomethingNeedingAccessKey()の呼び出しでは、_self._accessKey_にすでに格納されている値が使用されます。 somethingNeedingAccessKeyに渡されるクロージャー内でgetAccessKeyの残りの作業を行う場合、accessKeyが常に有効であることを確認できます。 accessKeyを必要とする別の関数が必要な場合は、somethingNeedingAccessKeyと同じ方法で記述してください。

_public func somethingElse() {
    getAccessKey { (accessKey, error) in
        if accessKey != nil {
            // Do something else with accessKey
        } else {
            // Handle nil accessKey / error here
        }
    }
}
_
31
Mike S