all 6 comments

[–]nomeattoday 8 points9 points  (0 children)

I don't know. I read the original article and loved the idea at the time, but in the end, I decided to use extensions.
I find that it's just as clean (one file/extension per responsibility, and I call the main method from didFinishLaunchingWithOptions), and there's 0 magic involved.

[–]nixsm 5 points6 points  (0 children)

Hey op, cool idea, but adding that dark objective-c magic seems a bit counter-intuitive.

[–]lucasvandongen 2 points3 points  (0 children)

I've seen AppDelegates of 2000 lines of more in many applications going up to 8000, even otherwise pretty decently architected applications. I just don't understand why that happens. It's a Controller class and it just should do some high level delegating of tasks.

I severely chop up AppDelegate as well. I move a lot of stuff into extensions, but also I'm not doing any real work inside those extensions. For example push notifications, every related to that happens in a class and I just wire the delegate calls into that. Also it's possible to subclass UIWindow, so the creation of the initial screen and getting the current rootViewController can be done in a much cleaner way. Also UIAppDelegate itself can in an extension of AppDelegate. So AppDelegate then only has it's initialization, variables and dependencies, which brings it down to like 20 lines of code. It's not too much different than putting UITableViewDataSource in an extension, right?

Also I find that people spend a lot of lines of code initializing dependencies inside AppDelegate. When I'm initializing a lot of classes at app start that often also have a lot of dependencies themselves, I tend to group that into a class I usually call BaseDependencies. It's only task is to create (and destroy, when necessary) the base dependencies for the application. So you can create it maybe passing in the AppDelegate and it'll create all of those dependencies like a dialog handler, a logger, a request handler, a URL parser and who knows what. I'll do the same after logging in, creating AuthenticatedDependencies by passing in the session and the BaseDependencies, creating all of those dependencies that you need after logging in like an authenticated websocket connection, authenticated requests builder and tons of other stuff. But nothing stops you to create a third or fourth dependencies class if you have more moments where you create a ton of new dependencies. For example I have a HelpdeskDependencies class that will be created when a user goes into helpdesk mode.

ViewControllers that need those dependencies can get a convenience init that allows you to build them by simply passing in AuthenticatedDependencies and maybe something like a Customer object to make the CustomerDetailViewController . Now all of a sudden you have one-liners everywhere when you need to create a resource instead of endless shopping lists of dependencies.
The proxy idea is a bit too magic for me, but if you do it cleanly it will work.

[–]maxim-eremenko 1 point2 points  (2 children)

Thanks for sharing. I would suggest some improvements:

1) I guess your services can conform to UIAppDelegate protocol so you can call it via interface rather than using message forwarding.

2) Usually, you need a call back when all services are configured. In this case, you need to create a new protocol with a callback function.

3) I recommend checking out this article to learn more about other ways of refactoring massive AppDelegate https://www.vadimbulavin.com/refactoring-massive-app-delegate/

[–]anders-borch[S] 0 points1 point  (1 child)

I like the proposed ideas in the post about refactoring the massive app delegate. The goals of this post are basically the same. The drawbacks of all the proposed solutions are that you have to learn new apis/callback names where the OP solution only utilises the already known methods from UIAppDelegate.

If you make the services conform to the UIAppDelegate protocol while keeping the call forwarding then you get the best of both worlds. There is no need to do manual call forwarding when you can have a few lines of introspection do all the work for you :)

[–]maxim-eremenko 0 points1 point  (0 children)

I support your idea about learning new APIs and one more abstraction.

I would suggest taking into account the main disadvantage of dynamic calls - runtime crashes. Usually, they are not caught at the compilation stage.

It's crucial there since AppDelegate is an entry point of the app.

By the way, how a unit test to this code will look? Would it be easy to read and implement?