Post

Replies

Boosts

Views

Activity

Reply to Add Return key subview to keyboard
Add this somewhere: extension UIViewController {     static func swizzleLifecycleMethods() {         //this makes sure it can only swizzle once         _ = self.actuallySwizzleLifecycleMethods     }        private static let actuallySwizzleLifecycleMethods: Void = {         let originalVdlMethod = class_getInstanceMethod(UIViewController.self, #selector(viewDidLoad))         let swizzledVdlMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewDidLoad))         method_exchangeImplementations(originalVdlMethod!, swizzledVdlMethod!)               let originalVwaMethod = class_getInstanceMethod(UIViewController.self, #selector(viewWillAppear(_:)))         let swizzledVwaMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewWillAppear(_:)))         method_exchangeImplementations(originalVwaMethod!, swizzledVwaMethod!)         let originalVdaMethod = class_getInstanceMethod(UIViewController.self, #selector(viewDidAppear(_:)))         let swizzledVdaMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewDidAppear(_:)))         method_exchangeImplementations(originalVdaMethod!, swizzledVdaMethod!)         let originalVddMethod = class_getInstanceMethod(UIViewController.self, #selector(viewDidDisappear(_:)))         let swizzledVddMethod = class_getInstanceMethod(UIViewController.self, #selector(swizzledViewDidDisappear(_:)))         method_exchangeImplementations(originalVddMethod!, swizzledVddMethod!)     }()     @objc private func swizzledViewDidLoad() -> Void {         swizzledViewDidLoad() //run original implementation         print("swizzledViewDidLoad \(self)")     }         @objc private func swizzledViewWillAppear(_ animated: Bool) -> Void {         swizzledViewWillAppear(animated) //run original implementation print("swizzledViewWillAppear \(self)")         if type(of: self).description() == "UICompatibilityInputViewController" {             self.view.printSubViews()             if (self.view?.subviews.count == 0) {                 self.view?.backgroundColor = .red             }         }     }     @objc private func swizzledViewDidAppear(_ animated: Bool) -> Void {         swizzledViewDidAppear(animated) //run original implementation         print("swizzledViewDidAppear \(self)")     }     @objc private func swizzledViewDidDisappear(_ animated: Bool) -> Void {         swizzledViewDidDisappear(animated) //run original implementation         print("swizzledViewDidDisappear \(self)")         DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in             if let self {                 print("swizzled VC stil in memory after disappearing for 1s: \(self)")             }         }     } } extension UIView {     /**     Recursively prints all subviews to console, indented according to level for easy view tree assessment.     - Parameter level: initial indentation level, default is 0     */     func printSubViews(level : UInt = 0) {         var tabs = ""         for _ in 0..<level {             tabs += "\t"         }         //do your print() here of whatever you'd like to know of each view:         print("\(tabs)\(self)")         for subview in self.subviews {             subview.printSubViews(level: level+1)         }     } } Then call UIViewController.swizzleLifecycleMethods() once somewhere to activate the swizzling, I suggest in didFinishLaunchingWithOptions. All keyboards should look red now :). It should print lifecycle events of all VCs to the console, including system ones like the keyboard.
Jan ’23
Reply to UITextView stuck in memory after link preview
iOS 17 still has the same issue but at least now there is a way to avoid it: The leak will clear once you set isSelectable to false. So I'd advice to do this before removeFromSuperview() or in VC's deinit. myTextView.isSelectable = false myTextView.removeFromSuperview() //in ViewController deinit { myTextView.isSelectable = false } Or even better is to just subclass UITextView and override removeFromSuperview(): //in UITextView subclass override func removeFromSuperview() { let wasSelectable = isSelectable isSelectable = false super.removeFromSuperview() isSelectable = wasSelectable } Even setting isSelectable directly back to true the next line will work (at least in debug builds). This way the links still work if you decide to reuse the view.
Sep ’23
Reply to iOS17 UITextView inputView becomFirstResponder does not work
I noticed UITextFields don't always deinit when closing its VC (or using removeFromSuperview()), but only if it has become first responder at least once. Actually, if you have a VC with multiple UITextFields, let one become first responder, then close the VC, ALL UITextFields won't deinit! Then if you activate another UITextField in another VC they will deinit after all. I believe it happens more often when textContentType isn't nil. To check yourself just subclass UITextField and check the deinit calls in the console: class TestTextField: UITextField { deinit { print("deinitted textfield \(self.placeholder ?? "") \(self.text ?? "")") } }
Sep ’23