【问题标题】:Is it possible to swizzle deinit using swift. if yes then how to achieve this是否可以使用 swift 来调配 deinit。如果是,那么如何实现这一目标
【发布时间】:2017-03-31 13:24:38
【问题描述】:

我想在我的项目中 UIViewController 的每个子类中的 deinit 中记录一些语句。我不想在每个视图控制器子类中复制/粘贴相同的行。

【问题讨论】:

  • 您是在谈论您创建的自定义视图控制器,还是 iOS SDK 提供的标准视图控制器也需要这个?
  • 我目前需要的是自定义视图控制器,但我关心的是检查 deint 的 swizzle 可用性。
  • 你找到解决办法了吗?
  • 仍未找到。 @保罗
  • 啊啊啊啊,我们需要这个!

标签: ios swift swizzling deinit


【解决方案1】:

有办法实现这一点。

你不能混用deinit,但你可以混用另一种方法,比如viewDidLoad,用associatedObject 毒化类。当 viewController 解除分配时,关联对象也被解除分配。

final class Deallocator {

    var closure: () -> Void

    init(_ closure: @escaping () -> Void) {
        self.closure = closure
    }

    deinit {
        closure()
    }
}

private var associatedObjectAddr = ""

extension UIViewController {

    @objc fileprivate func swizzled_viewDidLoad() {
        let deallocator = Deallocator { print("Deallocated") }
        objc_setAssociatedObject(self, &associatedObjectAddr, deallocator, .OBJC_ASSOCIATION_RETAIN)
        swizzled_viewDidLoad()
    }

    static let classInit: Void = {
        let originalSelector = #selector(viewDidLoad)
        let swizzledSelector = #selector(swizzled_viewDidLoad)
        let forClass: AnyClass = UIViewController.self
        let originalMethod = class_getInstanceMethod(forClass, originalSelector)
        let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector)
        method_exchangeImplementations(originalMethod!, swizzledMethod!)
    }()
}

警告

当 viewController 被释放时,闭包不会被调用确切,因为 Deallocator 被释放 viewController 被完全释放后。

【讨论】:

    【解决方案2】:

    我更新了间接调用swift代码的解决方案,可能不是最好的。您可以使用NSSelectorFromString 获得 de-init 实现,并通过 swizzling 扩展实现并通过桥接调用 swift 代码。试试这个可能对你有帮助的代码:

    //
    //  UIViewController+ExtendDealloc.h
    //  extension
    //
    //  Created by Amir Kamali on 26/2/19.
    //  Copyright © 2019 Amir Kamali. All rights reserved.
    //
    
    @import UIKit;
    
    @interface UIViewController (ExtendDealloc)
    
    
    @end
    

    .m 文件:

    //
    //  UIViewController+ExtendDealloc.m
    //  extension
    //
    //  Created by Amir Kamali on 26/2/19.
    //  Copyright © 2019 Amir Kamali. All rights reserved.
    //
    
    #import "UIViewController+ExtendDealloc.h"
    #import <objc/runtime.h>
    #import "test_objc-Swift.h"
    
    
    @implementation UIViewController (ExtendDealloc)
    
    #pragma mark - Swizzle Dealloc
    + (void)load {
        // is this the best solution?
        method_exchangeImplementations(class_getInstanceMethod(self.class, NSSelectorFromString(@"dealloc")),
                                       class_getInstanceMethod(self.class, @selector(swizzledDealloc)));
    }
    
    - (void)swizzledDealloc {
        [CustomBehaviorHandler printMe];
        [self swizzledDealloc];
    }
    
    @end
    

    Swift 代码:

    import Foundation
    import UIKit
    
    class CustomBehaviorHandler:NSObject {
    
        @objc
        static func printMe() {
            print("deinitializing ....")
        }
    }
    

    [更新]

    【讨论】:

    • 问题是针对 Swift 的,你也可以添加一个 Swift 示例用法吗?
    • 看不到任何直接的解决方案,但是我更新了上面间接调用swift代码的代码。
    • 从 Xcode 10.2 beta 3 开始,您无法在任何扩展程序(此处为 UIViewController (ExtendDealloc))上调用 +load。
    猜你喜欢
    • 2017-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多