I hope your Thursday is going well ☀️ Today's issue covers topics such as architecture, Combine, Swift, SwiftUI, UIKit, and development process. Let's dive in!
Architectures are for humans
Last week a particular topic resonated through the community: the mental toll the different architectures bring on developers. The issue is especially prominent for complex architectures such as VIPER, which is known for having many similarly-named small files per each screen.
@collinodonnel shared his experience, which triggered many others to come forward. Dozens of developers shared similar experiences last week.
Any task required routing through six classes, and I found myself physically exhausted when I had to interact with it.
I have struggled with VIPER myself in exactly the same way.
Let this serve as a reminder to all of us. Not that VIPER is a bad architecture pattern, but that architectures are not only about clean code or testability. They're also about people. It's us humans who have to be able to understand the codebase, reason about it, and work on it - productively.
Retain cycles with Combine
Combine's map operator retains the transform closure during the publisher's lifetime. When we pass a function declared on self, self is retained as well. If the subscription is kept alive by the same object, then we have an unbreakable retain cycle that prevents self from ever deallocating.
Marking self as unowned would leave the possibility of the app crashing. @eneko shares a safe way to resolve the retain cycle:
Configuring SwiftUI views with Environment
Majid shares a real-life example of how to leverage custom environment variables to configure custom SwiftUI views. Check out his article if you want to understand SwiftUI's Environment better. The way we do things in SwiftUI is definitely different from how we used to do them in UIKit 🙈
Reverse arrays for free
An interesting fact shared by @swiftandtips: reversing an array with reversed() doesn't use any new memory, and has constant time complexity (read: is very, very fast). Read documentation with examples here.
Detecting orientation changes in UIKit
Why do we want to know about changes in device orientation? Most often it is to know about screen size changes. In today's variety of devices, device orientation is not the only possible cause for the app's window to change size - think moving the app to split screen on iPad. Individual view controllers can also change size - f.ex. when changing width of columns in UISplitViewController.
Because of all this, it's much safer to rely on viewWillTransitionToSize for concrete size changes in view controllers, and on traitCollectionDidChange for general changes in environment, such as size class, dark mode, preferred text size and so on. Thanks @mluisbrown for bringing this up!
Getting unstuck in the morning
This tip is not about tweaking the code, but about tweaking your own development process. Are you sometimes feeling stuck when picking up a new task in the morning? There are some smart ideas in @nicklockwood's thread.
My favourite trick is to create the pull request in the morning, even if I finished the implementation and pushed the commits the day before. Besides the productivity boost, it gives a chance to look at the solution with fresh eyes and think of missed edge cases.
Did you enjoy this issue? Let me know by pressing the buttons below, so I can improve the newsletter.
Got feedback? I’d love to hear your thoughts! Reply to this email or reach out on Twitter via @ios_code_review 🙌