krzysztofzablocki / Inject

Hot Reloading for Swift applications!
MIT License
2.14k stars 114 forks source link

Inject View Controller which conforms to protocol #38

Closed romaHerman closed 2 years ago

romaHerman commented 2 years ago

First Thanks for the great tool!!!

Here is my question: I have a view controller which conforms to protocol "MyProtocol" then I do let calendar = Inject.ViewControllerHost(CalendarViewController()) and try to pass this calendar to the SideMenu which expects VC of MyProtocol type but calendar returns nil, when I do calendar as? MyProtocol

are there any workarounds of this ?

johnno1962 commented 2 years ago

Where is MyProtocol defined? Is it in its own file or is it being injected as well? Or, you could also try setting the environment variable INJECTION_DYNAMIC_CAST in your scheme.

romaHerman commented 2 years ago

It's In it's own file Will try with env var now and let you know P.S. Thanks for such fast reply!

romaHerman commented 2 years ago

unfortunately it didn't help

johnno1962 commented 2 years ago

Any chance of a small example project so I could look into what's going on?

romaHerman commented 2 years ago

Yes Let me try to construct one

romaHerman commented 2 years ago

Here is a sample project https://github.com/romaHerman/InjectTest It has TestComponents xCodeProject and main xCodeProject in SceneDelegate you can find test invocations of methods

it's similar to my setup in main project

johnno1962 commented 2 years ago

Thanks for the example project. Injection aside, I can see that Inject.ViewControllerHost(CalendarViewController()) has type Inject._ViewControllerHost<CalendarViewController> not CalendarViewController which even though it is defined as a subclass of CalendarViewController does not acquire the conformance to TestProtocol. This seems to be a Swift thing. @krzysztofzablocki?

johnno1962 commented 2 years ago

... Perhaps you need to do something like:


        if let vc = vc.instance as? TestProtocol {
            vc.testPrint()
        }
romaHerman commented 2 years ago

Thanks!

It does work in this case with vc.TestPrint()

but unfortunately it won't solve problem with passing this view to side menu

I have SideMenu which does navigationController.pushViewcontroller(<VC>) and in order Inject to work in should push vc not vc.instance

problem is here

let calendar = Inject.ViewControllerHost(CalendarViewController())
sideMenu.view = calendar.instance
johnno1962 commented 2 years ago

How do you mean "for inject to work"? If you save the file containing CalendarViewController, its methods will have been overridden for the next time they are called again.

romaHerman commented 2 years ago

here is what I'm trying to do

let calendar = Inject.ViewControllerHost(CalendarViewController())

viewControllers = [NewsViewController(), calendar.instance] menu.viewcontrollers = viewControllers

inside menu viewControllers variable is declared like this var viewControllers: [MenuProtocol] = [] and when I do menu.selectedIndex = 1 inside it does following navigationController.setViewcontrollers[viewControllers[selectedIndex] so it sets calendar.instance not the calendar itself and I think this the problem why Inject doesn't hot reload it for me

johnno1962 commented 2 years ago

It's possible the "Hosting" model Inject uses may not be for you in this instance. When you save the file containing NewsViewController it will have been "swizzled" correctly. Perhaps you just need a way to force it to redraw. Have you looked at creating an `@objc func injected()' method which should be called when the class is injected inside which you call viewDidLoad() or configure() or something to force the redraw so you can see the hot reload.

romaHerman commented 2 years ago

Thanks

I've overlooked this How I can do that ?

johnno1962 commented 2 years ago

create an @objc func injected() function in your class and see if it gets called. If it does, then you can do some stuff in it.

romaHerman commented 2 years ago

Maybe I will have to change SideMenu somehow to accept viewControllers injected doesn't get called

johnno1962 commented 2 years ago

I can zoom if you get stuck.

romaHerman commented 2 years ago

wow, thanks a lot! if it works for you I'm ready Tell me when you have time for that

johnno1962 commented 2 years ago

Or TeamView. Send an invite/login to github at johnholdsworth.com

johnno1962 commented 2 years ago

Actually, TeamView if you can thanks.

romaHerman commented 2 years ago

well I've changed my setup and now I don't need to solve this problem but somehow InjectionIII just quit working

I can see InjectionIII connected /Users//Documents/App.xcworkspace 💉 Watching files under /Users//Documents/App.xcworkspace and when I open debug view hierarchy in Xcode I can sett that there is InjectionHostVC also I gave access to all files and folders in mac's security

But when I change view and save nothing happens

I've tried reinstalling app and installing again, installing from Mac App Store and also restarting Mac

johnno1962 commented 2 years ago

You seem to be watching the workspace file instead of watching the directory containing the workspace file. Use menu item "Open Project" to set it again.

romaHerman commented 2 years ago

Ohhh I somehow thought that I should select workspace

It's working now Thanks a lot!!!

BTW here is how I hacked thing that I can't add this view to menu directly because of protocol added this line in viewWillAppear so view controller will re-instantiate itself and thus re-add itself with Injected host I will have to remove this code once I'm done working with this VC but it solves the issue

if injectSelf {
            let eventVC = Inject.ViewControllerHost(EventsViewController())
            eventVC.injectSelf = false
            navigationController?.setViewControllers([eventVC], animated: false)
        }
krzysztofzablocki commented 2 years ago

for passing specific type only .instance can work, but in that scenario I'd recommend probably not commiting host changes, I usually just do host swap in separate commit I can easily delete at the end of feature work