2

私はかなり新しくPromiseKit、プロミスラップされたデリゲートシステム(UIALertView + PromiseKitなど)の予期しない動作の解決策を見つけようと数日間試みてきましたPMKLocationManager

アプリのセットアップ プロセスのかなり典型的なシナリオでは、アプリの読み込み時にユーザーが実行しなければならない一連の操作を連鎖させようとしています。この例のために、ケースを 2 つのステップのみに制限しましょう。ユーザーを Restful システムにログインさせた後、alertView を提示し、ユーザーの操作を待機します。

以下は私のコードです。

  1. LoginToService は、MCUser をPromiseKit. これは期待どおりに機能し、ユーザーがログインすると元に戻るか、エラーで失敗します。

  2. ログイン成功の 'then' 句では、alert.promise() を介して約束されたバージョンを返すことで、alertView を提示します。

    PromiseKit の実装に従って、ユーザーがボタンをクリックしてそれを閉じると、アラートの約束が満たされる必要があります。デリゲート システム ラッパー: これは、alert.promise().then を使用して Promises のチェーンを開始したときに観察された動作に問題なく動作します -

        // Doesn't work: alert.promise returns immediately 
    let user = MCUser.sharedInstance()
    user.logInToService(.RestServiceOne, delegate: self).then { _ -> AnyPromise in
        MCLogInfo("LogInToService: Promise fulfilled")
        let alert = UIAlertView(title: "Title", message: "Msg", delegate: nil, cancelButtonTitle: "Cancel", otherButtonTitles: "Hello")
        return alert.promise()
        }.then { (obj:AnyObject) -> Void in
            print("Clicked")
        }.finally {
            print("Finally")
        }.catch_ { error in
     print("Error")
    }
    

私が観察したことは、ユーザーがクリックするのを待たずにチェーンがすぐに継続し、「クリックされました」および「最終的に」メッセージがコンソールに出力され、画面上のアラートがアクションを待っていることです。Promise チェーンの先頭にない場合、使用することを意図していないデリゲート システム ラッパーが明らかに不足していますか?

ヒントを事前にありがとう

4

1 に答える 1

1

期待どおりに動作するはずです。返された promise が正しく完了していないかどうかを確認できます。

ただし、私が不満に思っているのは、それalert.promise()が a Promise<Int>- を返す必要があることですが、クロージャは a を返すように明示的に型指定されていAnyPromiseます。したがって、コードはコンパイルされません。

私は自分でテスト プロジェクトをセットアップしましたが、実際、コンパイラは文句を言います。PromiseKit v3.x を使用しました。あなたのバージョンは古い可能性がfinallyありcatchます(非推奨です)。

クロージャーの戻り値の型を に修正するPromise<Int>と、コードがコンパイルされます。しかし、重要な事実は、動作がコードで説明および経験したとおりであり、本来の動作ではないということです。そのため、バグがあるようです。

編集:

OK、「オーバーロード解決」と「型推論」に問題があることが判明しました。OP でコードを指定すると、Swift コンパイラはthenメソッドの予期しないオーバーロードに解決されます。

期待される:
func then<U>(on q: dispatch_queue_t = dispatch_get_main_queue(), _ body: (T) throws -> Promise<U>) -> Promise<U>

実際:
func then<U>(on q: dispatch_queue_t = dispatch_get_main_queue(), _ body: (T) throws -> U) -> Promise<U>

これは、後続の finallyandcatchメソッドが原因です。

このシナリオでこれを解決するには、クロージャーの型を正しく完全に指定するか、型を指定せずにコンパイラーに判断させる必要があります。これは、Swift で PromiseKit v3.x を使用して期待どおりに動作します。

import UIKit
import PromiseKit

// helper
func fooAsync() -> Promise<String> {
    return Promise { fulfill, reject in
        let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(1.0 * Double(NSEC_PER_SEC)))
        dispatch_after(delay, dispatch_get_global_queue(0,0)) {
            fulfill("OK")
        }
    }
}        


class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()            
        fooAsync()
        .then { str in
            print("String: \(str)")
            let alert = UIAlertView(title: "Title", message: "Msg", delegate: nil, cancelButtonTitle: "Cancel", otherButtonTitles: "Hello")
            let promise: Promise<Int> = alert.promise()
            return promise
        }.then { (n: Int) -> Void in   // notice: closure type specified!
            print("Clicked")
        }.ensure {
            print("Finally")
        }.report { error in
            print("Error")
        }

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

別の PromiseKit ライブラリを使用しているため、上記のコードでは解決しない場合があります。最新の Swift バージョンを使用することをお勧めします。

それにもかかわらず、PromiseKit にはいくつかの微妙な落とし穴があるようです。問題を解決できることを願っています。

于 2016-05-04T10:08:22.993 に答える