2016-07-26 3 views
0

AuthenticatorクラスのsendEmailForPasswordRecoveryメソッドはasynchronousコールを実装しており、パスワード回復のためにfirebaseユーザーに電子メールを送信します。即時の非同期呼び出し動作とメインキューを理解しようとしました

func sendEmailForPasswordRecovery(email: String, completion: CallBackWithError) { 
     FIRAuth.auth()?.sendPasswordResetWithEmail(email, completion: { (error: NSError?) in 
      completion(error) 
     }) 
    } 

私は完了ブロックは、単純にこの関数を呼び出すUIViewController

Authenticator().sendEmailForPasswordRecovery(email, completion: { (error: NSError?) in 
     print("operation completed. error: \(error)") 
     self.completion?() 
}) 

からこのfunctionを呼び出しています。それは単ににpopUpビュー、およびフェードアウトを隠しblurEffectはその親ビューからそれを削除します。

しかし、Authenticator().sendEmailForPasswordRecoveryが実行されると、コンソールでエラーが発生していないことがわかります。しかしpopUpビューは40〜50秒後に消えてしまいます。しかし、私がdispatch_async内に完了をラップすると、私はすぐに私の結果を得る。

Authenticator().sendEmailForPasswordRecovery(email, completion: { (error: NSError?) in 
    // self.completion?() <----- this was causing delay 

    dispatch_async(dispatch_get_main_queue(), { 
      self.completion?() <------ Now it updates immidiately 
    }) 
}) 

Firebase sendPasswordResetWithEmail署名有する:

public func sendPasswordResetWithEmail(email: String, completion: FIRSendPasswordResetCallback?) 

を、それが必要に応じ

@param完了を言います。 要求が終了したときに呼び出されるブロック。今後メインスレッドで非同期に を呼び出します。ポップアップが一定の最初の場所での遅延とはどのようdispatch_assyncはimmidiately仕事をしてくれた後に消えたなぜ私が理解しない何

です。ビューをアニメーション化する

+1

簡単な提案 - iOS開発の同時性を扱うシステムであるGrand Central Dispatch(GCD)について読むことをお勧めします。 –

+0

いつ完了変数を設定しますか?最初のケースで正しく設定されていることを確認していますか? removeForgotPasswordScreenにブレークポイントを追加して、いつ実際に呼び出されたか、そしてどのスレッドかを確認します。 – fishinear

+0

@MattLeFleurご提案ありがとうございます。それは非常に有用でした。 – Ccr

答えて

1

、あなたがメインキューを使用する必要があり、かつsendPasswordResetWithEmailはメインキューにあなたのブロックを呼び出していない、そしてそれは強調:は、将来的には、メインスレッドで非同期的に呼び出されます。

dispatch_asyncは、dispatch_asyncとして、スレッドのキューにブロックを実行エンキューしますが、このスレッドは、メインスレッドであることが保証されていないか、または低い優先順位を有する(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT、0)){}、だから私は推測するsendPasswordResetWithEmailは、そのメソッドは、あなたのコードがすぐに実行されることを保証することはできませんDISPATCH_QUEUE_PRIORITY_DEFAULTまたは他の低優先順位を使用して実装する、実際には実行時間が正確に確認されていません。以下はテストですが、ラベルのアニメーションは数秒後に実行されることがあり、実行されないこともあります。

注意:ハンドルまたはUIをメインスレッドに設定する必要があります。これはテスト用です。

class ViewController: UIViewController { 
let label = UILabel() 

override func viewDidLoad() { 
    super.viewDidLoad() 
    self.view.backgroundColor = UIColor.whiteColor() 
    self.label.frame = CGRectMake(0, 0, 100, 21) 
    self.label.text = "Label" 
    self.label.center = self.view.center 
    self.view.addSubview(self.label) 

    let button = UIButton(type: .System) 
    button.setTitle("Button", forState: .Normal) 
    button.frame = CGRectMake(CGRectGetMinX(self.label.frame), CGRectGetMaxY(self.label.frame) + 20, 50, 20) 
    button.addTarget(self, action: NSSelectorFromString("handleButtonPressed:"), forControlEvents: .TouchUpInside) 
    self.view.addSubview(button) 
} 

func handleButtonPressed(sender: UIButton) { 
    // the block will execute not in main queue 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
     NSThread.sleepForTimeInterval(1) 
     // because the queue is not main queue, the animation not execute immediatelly, even not execute. 
     UIView.animateWithDuration(3, animations: { 
      var origin = self.label.frame.origin 
      origin.y += 100 
      self.label.frame.origin = origin 
      }, completion: { (complete) in 
       self.label.hidden = true 
     }) 
    } 
} 
} 

メインキューに変更すると、アニメーションがあなたの希望の時間として実行されます。

func handleButtonPressed(sender: UIButton) { 
    // in main queue 
    dispatch_async(dispatch_get_main_queue()) { 
     NSThread.sleepForTimeInterval(1) 

     UIView.animateWithDuration(3, animations: { 
      var origin = self.label.frame.origin 
      origin.y += 100 
      self.label.frame.origin = origin 
      }, completion: { (complete) in 
       self.label.hidden = true 
     }) 
    } 
} 

したがって、メインキュー(メインスレッド)のUIに適用されるすべてのコードを実行する必要があります。

回答がお役に立てば幸いです。これはGCD's guideです。注意深く完全に説明しています。

関連する問題