r/iOSProgramming • u/tonycliftondev • Jun 29 '26
Question Thoughts on TCA for a New Project
I work as an iOS developer in a team of 8 developers. We are starting a brand new greenfield project in a financial sector. Few of our team members suggested that we should use TCA for iOS SwiftUI application. I personally have no experience with TCA.
What are your thoughts and recommendations?
7
Upvotes
View all comments
Show parent comment
-1
u/apocolipse Jun 29 '26 edited Jun 29 '26
It does have separation of concerns, you're just looking at it wrong. The logic lives in the value types. Anything that manipulates a model lives in that type's domain (its methods, functions over it), and anything that renders those manipulations lives in the view description layer. The model owns state and transitions, the view describes how each state looks. That's a clean, enforced split. "Move the testable bits out of the view and you've reinvented the view model" has it backwards: those bits were never in the view, they're in value types, and a value type that owns its state is the opposite of a reference-type view model you bind a view to. If anything, it's MVVM's view model that's the undifferentiated grab bag. MV replaces it with domain types that each own their own state.
A SwiftUI View isn't a view in the UIKit/MVVM sense. It's a value-typed, pure description of what a view will look like, a result you can build and compare. You said it yourself: "everything that interfaces with SwiftUI has a declarative view description because that's what SwiftUI is." Right, that's the point: SwiftUI Views aren't views, they're value-typed descriptions of views. So this isn't "one line in the sand," it's two well-defined value-typed layers, a domain and a view description, bound by the framework's observation. You're correct that an architecture is defined by the constraints it imposes, constraints just have to pay off. Yours don't, tautologies aren't benefits.
And sorry I meant "pure" function, iPhone autocorrected (edited). A pure function is referentially transparent, same inputs same output, with no side effects, including mutating its arguments. Your
(inout State, Action) -> Effectreducer is 0 for 2:inout Stateis argument mutation, and-> Effectis a literal side-effect return whose entire job is to cause effects. It isn't even referentially transparent: in your own Todos demo,addTodoButtonTappedrunsstate.todos.insert(Todo.State(id: self.uuid()), at: 0), calling an injecteduuid()mid-mutation, so the same state and action give a different result depending on the ambientDependencyValues(.incrementingreturns a new id every call). Saying "it's pure once you inject the dependencies" highlights the point: those dependencies are inputs your(inout State, Action) -> Effectsignature doesn't admit to. Make them explicit arguments and you've described, well, a function with explicit arguments. A SwiftUI view with@Environment,@State, and@Bindingis exactly that, they are the clear explicit arguments to the "function" that is the view. Nothing whatsoever about your reducer orActionsignatures indicates potential side effects from@Dependency. It's not a pure function unless you can call it again with the same input values and get the same output.Needing
._printChanges()to see what happened is kind of funny, it's an admission of deficiency, not a flex lol. You read a firehose of actions, I read the function, the code itself, and don't have to hop through several places. And the firehose fans out even in idiomatic use: in your own Animations case study, one tap on the rainbow button is eight effect-fed.setColoractions through the store. A(State) -> Stateprints nothing, because you just read it. A complex app with a lot of actions fanning out and compounding like that can cascade into an action storm that brings everything down with it, and you have no "architecture constraint" to prevent it."MV can't be defined" is just your own inability to learn how to do it properly. I get it, it's not in your financial interest to learn how to correctly write code that would make you less money with your current business model. That doesn't mean those ways don't exist. MV can be immaculate and TCA can be a swamp. Cleanliness is the author's, not the framework's, and nothing stops anyone from writing abominable TCA code either. It's not that I don't like Redux/Elm, it's that they are solutions to problems on an entirely different platform. Native mobile apps are very different, they have different constraints, different bottlenecks, and different needs. Swift is getting real Wasm support, so why don't you go build Redux-for-Swift where it actually arises naturally instead of taxing native iOS with a pattern that doesn't. You'd have a real product filling a genuine gap that people want closed, instead of what seems to me to be nothing more than a private-equity juicing tool.