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

iOS Timer userInfo 參數深度解析:類型安全傳遞與常見陷阱避坑指南

     編輯:程式設計疑難解答

NSTimer userInfo 參數完全指南:從基本用法到類型安全封裝的最佳實踐

NSTimer (現 Timer) 的 userInfo 參數是定時器回調中傳遞上下文數據的核心機制。本文詳細講解其類型本質、常見用法模式、類型安全風險及 Swift 現代化封裝方案。

核心機制解析


// 創建定時器時傳遞 userInfo
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(timerFired(_:)), userInfo: someObject, repeats: true)

// 回調中接收
@objc func timerFired(_ timer: Timer) {
    let btn = timer.userInfo as? UIButton  // 類型轉換
    btn?.setTitle("Clicked", for: .normal)
}

本質:userInfo 是 Any? (OC 中 id _Nullable),可攜帶任意對象引用。定時器內部強引用 userInfo,直到定時器失效釋放。

常見使用場景

  1. 標識定時器用途:傳遞枚舉/字符串標識,一個回調處理多種定時任務。
  2. 傳遞業務上下文:按鈕、模型對象、請求 ID、閉包封裝 (需注意循環引用)。
  3. 攜帶時間戳/序列號:實現定時器去重、順序驗證。

類型安全陷阱與防範

  • 強制轉換崩潰:timer.userInfo as! MyClass 若類型不匹配直接崩潰。必須用 as? 可選綁定。
  • 值類型包裝:Int、Struct 需裝箱 NSNumber、NSValue 或自定義類。
  • 循環引用風險:userInfo 持有 self,且 self 持有定時器 → 內存洩漏。解決:userInfo 傳遞弱引用封裝或不傳 self。
  • 定時器復用混淆:同一對象多個定時器共用回調,userInfo 未正確區分導致邏輯錯誤。

Swift 現代化封裝:類型安全 Timer 包裝器


final class TypedTimer {
    private var timer: Timer?
    private let handler: (Context) -> Void
    
    init(interval: TimeInterval, repeats: Bool, context: Context, handler: @escaping (Context) -> Void) {
        self.handler = handler
        timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: repeats) { [weak self] _ in
            self?.handler(context)
        }
    }
    
    func invalidate() { timer?.invalidate(); timer = nil }
    deinit { invalidate() }
}

// 使用示例
let btn = UIButton()
let timer = TypedTimer(interval: 1.0, repeats: true, context: btn) { button in
    button.setTitle("⏱ \(Date())", for: .normal)
}
// 無需類型轉換,上下文類型安全,自動釋放

OC 時代遺留代碼遷移建議

  • 將 @selector 回調遷移為基於閉包的 Timer.scheduledTimer(withTimeInterval:repeats:block:) (iOS 10+)。
  • 使用 WeakProxy 封裝 target 避免定時器強引用導致控制器不釋放。
  • 統一使用 TypedTimer 或 Combine 框架 (Timer.publish) 替代裸 NSTimer。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved