首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

iOS UITableView 滑動時彈幕動畫暫停問題:RunLoop 模式深度解析與解決方案

     編輯:程式設計綜合問答

現象本質:RunLoop 模式切換導致 Timer 失效

當用戶手指按住屏幕拖動 UITableView 時,主線程 RunLoop 從 kCFRunLoopDefaultMode 切換至 UITrackingRunLoopMode(系統內部模式,對應 NSRunLoopCommonModes 標記)。默認模式下添加的 NSTimer、CADisplayLink、GCD 主隊列任務 均會被暫停,導致彈幕動畫、倒計時等依賴主線程定時觸發的邏輯凍結。

三種解決方案對比

方案一:將 Timer 加入 Common Modes(推薦,最簡潔)

NSTimer *timer = [NSTimer timerWithTimeInterval:1.0
                                         target:self
                                       selector:@selector(updateDanmaku:)
                                       userInfo:nil
                                        repeats:YES];
// 關鍵:註冊到 Common Modes,包含 DefaultMode 與 TrackingMode
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

優點:一行代碼解決,無需修改業務邏輯。
適用場景:低頻定時器(>16ms)、非極高精度動畫。

方案二:CADisplayLink + Common Modes(適合高幂動畫)

CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(renderFrame:)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
// 關鍵:CADisplayLink 綁定屏幕刷新率,配合 Common Modes 實現滑動不掉幂

優點:與屏幕 VSync 同步,動畫流暢度最佳;自動適配 ProMotion 120Hz 屏幕。
注意:preferredFramesPerSecond 控制幂率,避免過度消耗 CPU。

方案三:後台線程驅動 + 主線程渲染(極高性能場景)

// 後台線程
dispatch_queue_t renderQueue = dispatch_queue_create("com.app.danmaku.render", DISPATCH_QUEUE_SERIAL);
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, renderQueue);
dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), 16 * NSEC_PER_MSEC, 0);
dispatch_source_set_event_handler(timer, ^{
    // 計算彈幕位置、碰撞檢測等純計算邏輯
    DanmakuFrame *frame = [self computeNextFrame];
    // 回主線程僅做 CALayer 屬性更新
    dispatch_async(dispatch_get_main_queue(), ^{
        [self updateLayersWithFrame:frame];
    });
});
dispatch_resume(timer);

優點:完全脫離主線程 RunLoop 限制,滑動時計算不阻塞、渲染不掉幂。
適用場景:數百條彈幕並發、複雜碰撞檢測、粒子特效等重計算場景。

進階優化建議

  • 離屏渲染優化:彈幕文字預先繪製至 CATextLayer 或位圖緩存,滑動時僅修改 position/transform,避免重複排版。
  • 視圖復用池:參照 UITableViewCell 機制,實現彈幕 Label/Layer 的對象池,減少分配開銷。
  • 優先級調度:CADisplayLink 設置 preferredFramesPerSecond = 30 降低功耗;後台計算隊列設置 QOS_CLASS_UTILITY。
  • 多模式兼容:同時加入 NSRunLoopCommonModes 與 UITrackingRunLoopMode 雙重保障,應對系統版本差異。

核心原則:將「計算」與「渲染」解耦,計算放後台或 Common Modes Timer,渲染綁定 CADisplayLink,實現滑動流暢與動畫連續的雙贏。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved