web-dev-qa-db-ja.com

Alamofireでのエラー処理

AngularJSコントローラーにHTTPコードがあります:

$http.post('/api/users/authenticate', {email: $scope.email, password: $scope.password})
    .success(function (data, status, headers, config) {
        authService.login($scope.email);
        $state.go('home');
    })
    .error(function (data, status, headers, config) {
        $scope.errorMessages = data;
        $scope.password = "";
    });

成功した場合、サーバーはユーザーのJSON表現で応答します。エラーの場合、サーバーはdataパラメーターを介してアクセスできるUser not foundなどの単純な文字列で応答します。

Alamofireで同じようなことをする方法を理解するのに苦労しています。私が今持っているものは次のとおりです。

@IBAction func LoginPressed(sender: AnyObject) {
    let params: Dictionary<String,AnyObject> = ["email": emailField.text, "password": passwordField.text]

    Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params)
        .responseJSON {(request, response, data, error) in
            if error == nil {
                dispatch_async(dispatch_get_main_queue(), {
                    let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController;

                    self.presentViewController(welcome, animated: true, completion: nil);
                })
            }
            else{
                dispatch_async(dispatch_get_main_queue(), {
                    // I want to set the error label to the simple message which I know the server will return
                    self.errorLabel.text = "something went wrong"
                });
            }
    }
}

エラー以外のケースを正しく処理しているかどうかもわからず、その上での入力も歓迎します。

15

あなたは正しい軌道に乗っていますが、現在の実装でいくつかの重要な問題に遭遇するでしょう。私はあなたを助けたいと思ういくつかの低レベルのAlamofireがあなたをつまずかせるでしょう。はるかに効果的なコードサンプルの代替バージョンを次に示します。

_@IBAction func loginPressed(sender: AnyObject) {
    let params: [String: AnyObject] = ["email": emailField.text, "password": passwordField.text]

    let request = Alamofire.request(.POST, "http://localhost:3000/api/users/authenticate", parameters: params)
    request.validate()
    request.response { [weak self] request, response, data, error in
        if let strongSelf = self {
            let data = data as? NSData

            if data == nil {
                println("Why didn't I get any data back?")
                strongSelf.errorLabel.text = "something went wrong"
                return
            } else if let error = error {
                let resultText = NSString(data: data!, encoding: NSUTF8StringEncoding)
                println(resultText)
                strongSelf.errorLabel.text = "something went wrong"
                return
            }

            var serializationError: NSError?

            if let json: AnyObject = NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments, error: &serializationError) {
                println("JSON: \(json)")
                let welcome = self.storyboard?.instantiateViewControllerWithIdentifier("login") as UINavigationController
                self.presentViewController(welcome, animated: true, completion: nil)
            } else {
                println("Failed to serialize json: \(serializationError)")
            }
        }
    }
}
_

検証

まず、リクエストのvalidate関数は以下を検証します:

  • HTTPStatusCode-200 ... 299でなければなりません
  • _Content-Type_-応答のこのヘッダーは、元の要求のAcceptヘッダーと一致する必要があります

Alamofireの検証の詳細については、 [〜#〜] readme [〜#〜] を参照してください。

弱める/強める

クロージャを弱い自己と強い自己にし、リテンションサイクルを作成しないようにします。

メインキューへのディスパッチ

メインキューへのディスパッチコールバックは必要ありません。 Alamofireは、responseおよびresponseJSONシリアライザーの完了ハンドラーがメインキューで既に呼び出されていることを保証します。実際には、必要に応じてシリアライザーを実行するための独自のディスパッチキューを提供できますが、現在のところソリューションも私のものもそうではないため、メインキューへのディスパッチ呼び出しはまったく不要です。

応答シリアライザー

特定のケースでは、responseJSONシリアライザーを実際に使用する必要はありません。そうした場合、検証に合格しなければ、データを取り戻すことはできません。理由は、JSONシリアル化からの応答がAnyObjectとして返されるものだからです。シリアル化が失敗した場合、AnyObjectはnilになり、データを読み取ることができなくなります。

代わりに、responseシリアライザーを使用し、NSJSONSerializationを使用してデータを手動で解析してください。それが失敗した場合、適切なole NSString(data:encoding:)メソッドに依存してデータを印刷できます。

うまくいけば、かなり複雑な方法でつまずくのを防ぐことができます。

28
cnoon

そのため、Alamofireはすべてのリクエストを正常に処理します。これは、APIサーバーのhttpヘッダーが返されることに本当に由来します。

Alamofire.Request.validate()を使用できます

Httpヘッダーなどを検証できます。例を確認してください。

https://github.com/Alamofire/Alamofire#validation

エラーメッセージはdataオブジェクトにあると想定しています。

データの値にアクセスするには、次のようなことができます

あなたのAPIレスポンスの外観については本当にわかりませんが、この例では

{
     "message": "Could not authenticate"
}
let message: String? = data?.valueForKey("message") as String
1
slik