Disabling has also changed the semantic meaning of this view. It’s not really that this view is disabled, it’s just that we want to put in a static, inert version of the UI. Applying a disabled attribute might be a little too heavy handed for this situation, and could impact the user experience in ways that we are not aware of right now, such as accessibility.
Disabling may not disable everything you expect it to. It certainly disables things like buttons, text fields and other UI controls, but other events will still fire. For example, if we had an
.onAppear
modifier in this list so that we could fire off some analytics or an API request, that logic would still execute just like normal, even if the whole view is disabled.
Also, once you disable a view hierarchy there is no way to selectively re-enable parts of the inside of the view. This is possible with redactions. We haven’t covered it yet, but soon we will see that within a redacted view we can un-redact certain parts to make it visible to the user again. This impedance mismatch between these two APIs is really pointing at the fact that disabling UI is not a great way for handling this functionality. There may be times that we want to un-redact a little bit of the view, and inside that view we have a button. We will have no way of re-enabling it and so it will stay stuck as disabled. And what if that button did something important, like canceled the inflight request? It’s definitely not acceptable to just blanket disable everything.
So what we are seeing is that using disabled
to handle this kind of placeholder functionality is not great, and so when building an application in the vanilla SwiftUI approach we may need to sprinkle bits of logic all around our view to selectively disable parts of its logic.
The main reason this is happening is that our view is inextricably linked with its logic. We have this view model object that is just plopped right down into this view, and whatever happens in the view is going to always be relayed back to the view model. This is a very tight coupling and doesn’t give us much freedom to adapt.
We feel that although SwiftUI views are an amazing technology, they are ripe for abuse in this regard. There is a phrase that people in the programming community that is very popular and seen as a kind of “north star” for software development, and it says that we should try to “separate concerns” in our applications. Now of course there is no precise definition of what “separate” and “concerns” means. Does separate mean put code in separate files, or does it mean something deeper? And can an entire screen be one concern, or must it be composed of many concerns, and how granular should we get? For this reason we think the “separation of concerns” adage is a very broad guideline, and not something that can be rigorously applied.
But, having said that, we think that SwiftUI views, when built in this kind of straightforward manner, are some of the biggest offenders of concerns not being separated. Views tend to accumulate lots of logic, especially in action closures on various UI controls, and there’s really no way in which we can say that the view and its view model are separate, isolated units.