Можно ли прокачать дейнит с помощью swift. если да то как этого добиться

Я хочу регистрировать некоторые операторы в deinit в каждом подклассе UIViewController в моем проекте. Я не хочу копировать/вставлять одни и те же строки в каждый подкласс контроллера представления.


person ZaEeM ZaFaR    schedule 17.11.2016    source источник
comment
Вы говорите только о настраиваемых контроллерах представления, которые вы создаете, или вам также нужно это для стандартных контроллеров представления, предоставляемых iOS SDK?   -  person rmaddy    schedule 17.11.2016
comment
В настоящее время мне нужны настраиваемые контроллеры представления, но я беспокоюсь о том, чтобы проверить доступность swizzle для deint.   -  person ZaEeM ZaFaR    schedule 17.11.2016
comment
Вы нашли какие-то решения?   -  person Paul    schedule 26.05.2017
comment
Все еще не найдено. @Павел   -  person ZaEeM ZaFaR    schedule 06.06.2017
comment
Ааааааа, нам это нужно!   -  person ullstrm    schedule 15.06.2017


Ответы (2)


Есть способ добиться этого.

Вы не можете использовать 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.

person farzadshbfn    schedule 13.06.2018

Я обновил решение, которое косвенно вызывает быстрый код, возможно, не самое лучшее. Вы можете получить реализацию de-init с помощью NSSelectorFromString и расширить реализацию с помощью swizzling и вызвать быстрый код через мост. Попробуйте этот код, который может вам помочь:

//
//  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

.м файл:

//
//  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

Свифт-код:

import Foundation
import UIKit

class CustomBehaviorHandler:NSObject {

    @objc
    static func printMe() {
        print("deinitializing ....")
    }
}

[ОБНОВЛЕНО]

person Amir.n3t    schedule 26.02.2019
comment
Вопрос для Swift, можете ли вы также добавить пример использования Swift? - person Cristik; 26.02.2019
comment
Не удалось найти прямого решения, однако я обновил приведенный выше код, который косвенно вызывает быстрые коды. - person Amir.n3t; 26.02.2019
comment
Вы больше не можете вызывать +load для любого расширения (здесь UIViewController (ExtendDealloc)), начиная с Xcode 10.2 beta 3. - person Cœur; 26.02.2019