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

iOS 延遲執行:performSelector:withObject:afterDelay: 與現代替代方案

     編輯:程式設計綜合問答

傳統方案


// 經典 API
[self performSelector:@selector(myMethod) withObject:nil afterDelay:23.0];

- (void)myMethod {
    // 23 秒後執行
}

優點:簡單、單行程式碼。缺點:無法取消、無法傳遞多參數、不支援 Swift、RunLoop 模式敏感。

現代替代方案

1. GCD dispatch_after (Objective-C/Swift 通用)


// Objective-C
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(23.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self myMethod];
});

// Swift
DispatchQueue.main.asyncAfter(deadline: .now() + 23.0) {
    self.myMethod()
}

優點:可取消 (儲存 DispatchWorkItem)、支援閉包/多參數、主執行緒安全。

2. Timer.scheduledTimer (需手動 invalidate)


Timer.scheduledTimer(withTimeInterval: 23.0, repeats: false) { _ in
    self.myMethod()
}

3. Swift Concurrency (iOS 15+)


Task {
    try await Task.sleep(nanoseconds: 23_000_000_000)
    await MainActor.run { self.myMethod() }
}

4. 可取消的封裝工具類


class DelayExecutor {
    private var workItem: DispatchWorkItem?
    
    func execute(after delay: TimeInterval, block: @escaping () -> Void) {
        cancel()
        workItem = DispatchWorkItem(block: block)
        DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem!)
    }
    
    func cancel() {
        workItem?.cancel()
        workItem = nil
    }
}

// 使用
let delay = DelayExecutor()
delay.execute(after: 23) { self.myMethod() }
// 需要取消時
delay.cancel()

選擇建議

場景推薦方案
簡單一次性延遲、無需取消performSelector:afterDelay: / asyncAfter
需取消/傳參/現代語法DispatchWorkItem / asyncAfter
週期性/複雜排程Timer / DispatchSourceTimer
Swift 非同步流程中Task.sleep

核心注意點

  • 弱引用 self:[weak self] in self?.method() 避免循環引用。
  • 主執行緒更新 UI:延遲閉包預設在主佇列,但 Task.sleep 需 MainActor.run。
  • 取消機制:長延遲操作(如網路請求超時)必須可取消,防止對象已釋放仍執行。

拋棄 performSelector 這個 Objective-C 時代產物,擁抱 GCD/Swift Concurrency 的類型安全、可取消、可組合的現代非同步編程。

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