johnno1962 / injectionforxcode

Runtime Code Injection for Objective-C & Swift
MIT License
6.55k stars 565 forks source link

Lazy loading view does not work #259

Closed shakesVan closed 5 years ago

shakesVan commented 5 years ago

this is my code:

class MYVC: UIViewController {

    lazy var btn: UIButton = {
        let btn = UIButton()
        btn.backgroundColor = UIColor.green
        //btn.backgroundColor = UIColor.blue
        return btn
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupView()
    }

    func setupView() {
        view.addSubview(btn)
        //btn.backgroundColor = UIColor.red
        btn.frame = CGRect(x: 100, y: 100, width: 100, height: 100)

    }
}

then I set btn.backgroundColor = UIColor.blue, it does not work in the closure . I want used the lazy-loding in the Injecttion , how to do this ?

zenangst commented 5 years ago

I'm guessing that you need a new instance of the button for it to work, as the instance variable is declared as lazy.

@johnno1962 correct me if I'm wrong here :)

shakesVan commented 5 years ago

@zenangst I know what you say, but I can not at all in view viewDidLoad initialization, and I think it is unreasonable. These views should also be initialized when the controller is initialized, not in viewDidLoad. ViewDidLoad should only add views to self.view.

zenangst commented 5 years ago

Yeah, I see the value of using lazy for these kinds of things. However, as you've noticed, it might not render the results that you want in cases like these. What I tend to do (depending on context) is to have a separate method for configuring views that I call in viewDidLoad. It does not really make that much difference when it comes to when the views are initialized on the controller as the lazy annotation will prevent the view from being created until it is accessed the first time. Which for this particular scenario is when you add the view to the view hierarchy. So for this scenario, the run-time code do the same thing, both with and without lazy.

And don't get me wrong, if you need to keep a reference to the views, it is totally fine to use lazy. Just remember not to do configuration inside of the lazy closure.

I've started applying injection at the controller creation level rather than specifically inside one view controller. It might sound a bit icky but it works for my workflow. For more inspiration about different ways of applying injection, you can head over to Vaccine or give my Medium article a read: Code Injection In Swift.

Vaccine has some view controller extensions that might help you if you tend to use child view controller etc.

https://github.com/zenangst/Vaccine/blob/master/Source/iOS%2BtvOS/UIViewController%2BExtensions.swift#L34

shakesVan commented 5 years ago

@zenangst Thanks very much, I fix it by this way:

class MYVC: UIViewController {

    var myView: MYView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupView()
        myView.data = "this is title"
    }

    func setupView() {
        myView = MYView()
        myView.backgroundColor = UIColor.red
        myView.layer.cornerRadius = 5
        view.addSubview(myView)
        myView.frame = CGRect(x: 50, y: 100, width: 300, height: 300)

    }
}

now, it's work when I change some thing in the MYView class. then, I add this for fix command + s don't work in a UIView class

extension UIView {
    #if DEBUG
    @objc func injected() {
        print("injected UIView")
        //find now VC 
        guard let nowVC = viewController() else {
            return
        }
        for subV in nowVC.view.subviews {
            subV.removeFromSuperview()
        }
        nowVC.viewDidLoad()
    }
    #endif
}
zenangst commented 5 years ago

@shakesVan awesome, super nice that you were able to solve it :)

shakesVan commented 5 years ago

@zenangst @johnno1962 I'm trouble with the real device, like this:

image

I refer to the following content, but I am prompted with this exception. Am I missing something?https://github.com/johnno1962/injectionforxcode/blob/master/documentation/patching_injection.md

zenangst commented 5 years ago

Injection only works in the simulator due to changes in iOS sandboxing.

Reference: https://github.com/johnno1962/injectionforxcode/issues/202

shakesVan commented 5 years ago

@zenangst Thanks