You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift如何让UIViewController在viewWillAppear/Disappear时打印子类类型

结论

可以实现,无需修改任何现有UIViewController子类的代码,基于Objective-C runtime的方法交换(Method Swizzling)机制即可全局插入生命周期打印逻辑。

实现方案

方法交换的核心逻辑是在运行时替换UIViewController生命周期方法的默认实现,插入自定义打印代码后再调用原有实现,所有子类默认继承该逻辑。
以下分别提供Swift和Objective-C的实现示例:

Swift 实现

  1. 给UIViewController添加扩展,实现方法交换逻辑和自定义生命周期方法:
import UIKit

extension UIViewController {
    static func enableLifeCycleLog() {
        guard !isLoggingEnabled else { return }
        isLoggingEnabled = true
        
        // 交换viewWillAppear
        swapMethods(
            original: #selector(UIViewController.viewWillAppear(_:)),
            swizzled: #selector(UIViewController.swizzled_viewWillAppear(_:))
        )
        // 交换viewWillDisappear
        swapMethods(
            original: #selector(UIViewController.viewWillDisappear(_:)),
            swizzled: #selector(UIViewController.swizzled_viewWillDisappear(_:))
        )
    }
    
    private static var isLoggingEnabled = false
    
    private static func swapMethods(original: Selector, swizzled: Selector) {
        guard let originalMethod = class_getInstanceMethod(UIViewController.self, original),
              let swizzledMethod = class_getInstanceMethod(UIViewController.self, swizzled) else {
            return
        }
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
    
    @objc private func swizzled_viewWillAppear(_ animated: Bool) {
        swizzled_viewWillAppear(animated)
        print("🔵 [viewWillAppear] \(type(of: self)) 地址: \(Unmanaged.passUnretained(self).toOpaque())")
    }
    
    @objc private func swizzled_viewWillDisappear(_ animated: Bool) {
        swizzled_viewWillDisappear(animated)
        print("🔴 [viewWillDisappear] \(type(of: self)) 地址: \(Unmanaged.passUnretained(self).toOpaque())")
    }
}
  1. 在App启动时触发方法交换,在AppDelegate.application(_:didFinishLaunchingWithOptions:)中添加一行代码即可:
UIViewController.enableLifeCycleLog()

Objective-C 实现

  1. 创建UIViewController分类:
// UIViewController+LifeCycleLog.h
#import <UIKit/UIKit.h>

@interface UIViewController (LifeCycleLog)
@end

// UIViewController+LifeCycleLog.m
#import "UIViewController+LifeCycleLog.h"
#import <objc/runtime.h>

@implementation UIViewController (LifeCycleLog)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 交换viewWillAppear
        Method originalViewWillAppear = class_getInstanceMethod(self, @selector(viewWillAppear:));
        Method swizzledViewWillAppear = class_getInstanceMethod(self, @selector(ll_viewWillAppear:));
        method_exchangeImplementations(originalViewWillAppear, swizzledViewWillAppear);
        
        // 交换viewWillDisappear
        Method originalViewWillDisappear = class_getInstanceMethod(self, @selector(viewWillDisappear:));
        Method swizzledViewWillDisappear = class_getInstanceMethod(self, @selector(ll_viewWillDisappear:));
        method_exchangeImplementations(originalViewWillDisappear, swizzledViewWillDisappear);
    });
}

- (void)ll_viewWillAppear:(BOOL)animated {
    [self ll_viewWillAppear:animated];
    NSLog(@"🔵 [viewWillAppear] %@ 地址: %p", NSStringFromClass([self class]), self);
}

- (void)ll_viewWillDisappear:(BOOL)animated {
    [self ll_viewWillDisappear:animated];
    NSLog(@"🔴 [viewWillDisappear] %@ 地址: %p", NSStringFromClass([self class]), self);
}

@end
  1. 无需额外调用,分类的load方法会在App启动时自动执行,打印逻辑全局生效。
注意事项
  • 该逻辑仅可在Debug模式下使用,上线前必须移除,避免产生不必要的性能消耗和日志泄露。
  • 若你的自定义子类重写了生命周期方法但未调用super对应的方法,打印逻辑不会触发,补全super调用即可。
  • 日志中添加了实例内存地址,可以更精准的追踪同一个实例的生命周期调用顺序,排查重复dismiss的问题更方便。

内容的提问来源于stack exchange,提问作者Timothy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 18:06:05