2017-07-31 31 views
0

我在制定問題標題時遇到了一些問題,如果您有更好的選擇,請進行編輯。基於GCD的登錄超時有時會在下次登錄嘗試時觸發

我有一個登錄過程,這是我加的超時:

private func startTimeout() { 
    self.timeoutActive = true 
    DispatchQueue.main.asyncAfter(deadline: .now() + 20) { 
     [weak self] in 
     guard let weakSelf = self else { 
      return 
     } 

     if weakSelf.timeoutActive && !weakSelf.loggedIn { 
      weakSelf.onError("Login timed out") 
     } 
    } 
} 

我已經設計了登錄過程,這樣,如果我們出於任何原因需要再次登錄(例如註銷後,或後登錄過程確定存在缺失或錯誤的憑證),我們最終進入執行登錄的類的相同實例。

現在,據我所知,我們永遠無法阻止執行預定的塊,只能通過使用某些標誌來阻止它,這是我用timeoutActive標誌完成的。這像一個魅力。

但是,如果第二次登錄的時間精確到使新的登錄過程開始之後執行先前的調度塊,則會遇到問題(當新的登錄過程啓動時,timeoutActive標誌再次設置爲true )。新登錄收到一個不正確的超時。

我一直在想不同的方式來解決它,並嘗試了一些,但沒有得到任何他們的工作。

我有一個想法,使用performSelectorAfterDelay而不是GCD,它可以取消,但在Swift(3)中不可用。

我也玩過一個想法,就是擁有一些獨特的塊ID和一個被阻塞的塊ID列表 - 但這看起來似乎有點矯枉過正。

我也有一個關於將塊中的當前調度時間(.now())與原始截止時間(.now()+ 20)進行比較並查看它是否匹配的想法,但我不知道如何確切這個截止日期是,而且感覺不穩定。

我留下的唯一想法是在登錄過程本身周圍創建一些類似任務的任務,包括超時,併爲不同的登錄創建該任務的新實例。似乎有點工作,我寧願如果我找到一個更簡單的方法。

有沒有人遇到過這種情況,並有解決方案?

+0

'performSelectorAfterDelay'在Swift3中可用,它的名字就像其他執行選擇器方法一樣更改爲'perform(...)'。你也可以創建,然後'asyncAfter(...)'DispatchWorkItem''可以取消。 – dan

+0

Xcode僅向我展示了3個執行(...)方法,其中「after」參數不可用。我的錯。 DispatchWorkItem對我來說是新的,我正在嘗試它。謝謝:) – Joakim

+0

謝謝@dan它的工作完美。我發佈這個作爲答案,因爲你沒有,但如果你發佈的答案,而不是我會刪除我的。 – Joakim

回答

0

所以這是我從有關問題的丹的評論提出:

private var timeoutBlock: DispatchWorkItem? = nil 

private func startTimeout() { 
    self.timeoutBlock = DispatchWorkItem(block: { [weak self] in 
     guard let weakSelf = self else { 
      return 
     } 

     if !weakSelf.loggedIn { 
      weakSelf.onError("Login timed out") 
     } 
    }) 

    DispatchQueue.main.asyncAfter(wallDeadline: .now() + 20, execute: self.timeoutBlock!) 
} 

和離開的ViewController或完成過程中,當使用self.timeoutBlock?.cancel()。這按預期工作!