Skip to content

重入保護判斷式寫反,轉場中的 ChangePage 不會被擋下 #20

Description

@rafuMacaca

問題
builtInClickProtection 開啟時,原意是「頁面轉場中又呼叫 ChangePage 要被擋下或排隊」。但實際上預設情況下完全沒有保護:轉場還沒結束時再呼叫一次 FullPageChanger().Show(),會直接再開一條 ChangePageBase 協程跟前一條同時跑,兩條協程互相覆寫 currentLiveElementsInViewPage / currentLiveElementsInViewState,導致前一頁 ViewState 上的元件從 live 清單消失、殘留在場上脫離管理。

根因
判斷式條件寫反了。ViewControllerBase.cs:

// 第 159 行(FullPage)
if (builtInClickProtection == true && ignoreClickProtection != false)
// 第 78 行(Overlay)、第 119 行 也是同樣寫法

ignoreClickProtection != false 等於 ignoreClickProtection == true,意思變成「只有當呼叫端要求忽略保護時,才套用保護」,邏輯顛倒。

builtInClickProtection 預設 true
PageChanger 的 ignoreClickProtection 預設 false
所以 true && (false != false) = false,整段保護(含 AutoWaitPreviousPageFinish 排隊邏輯)在預設路徑被跳過,直接走到第 173 行立刻起新協程。

重現
在某 ViewElement 的 OnStartShow()(此時前一頁 ChangePageBase 還沒結束、IsPageTransition == true)裡呼叫 ViewController.FullPageChanger().SetPage(另一頁).Show()。
觀察:兩條 ChangePageBase 同時執行;若兩頁的 ViewState 不同,前一頁 ViewState 的元件會殘留在畫面上、不再被收場。

預期
轉場進行中(IsPageTransition == true)且未指定忽略保護時,ChangePage 應該被擋下(回傳 null),或在 AutoWaitPreviousPageFinish == true 時排到前一個轉場結束後再執行。

建議修法
把三處條件改為「未要求忽略保護時才套用保護」:

if (builtInClickProtection == true && ignoreClickProtection == false)

附帶發現
WaitPrevious()(ViewControllerBase.cs 第 387 行)呼叫 ChangePage 時參數位置錯位:

yield return ChangePage(viewPageName, OnStart, OnChanged, OnComplete, ignoreTimeScale);
ChangePage 第 5 個參數是 AutoWaitPreviousPageFinish(bool),這裡卻把 ignoreTimeScale 傳進去,導致 ignoreTimeScale 實際失效、且語意混淆。建議用具名參數或補上正確位置。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions