I looked a bit of the posts on Twitter, and wow, it’s really polarized. People seem to either love it or hate it. Is SwiftUI still that controversial, or is it just an effect of people posting on Twitter?
> People seem to either love it or hate it. Or is that just an effect of people posting on Twitter?
I'm sure that a big part of that is the effect of it being Twitter. How often do we feel the urge to post something online that we have no strong feelings about?
More on topic, though: I'm a SwiftUI hater still. It's a cool concept, but there are two big problems with it, IMO:
1. It's totally out of place with the rest of the Swift programming language. They had to add new crap to the language to accommodate its declarative style, when Swift is (was) unapologetically imperative syntax-wise. It's an obvious bolt-on and leaves a really bad taste in my mouth.
2. It's still a very leaky abstraction, in that there's still a lot of stuff you have to reach into UIKit for, whether it's for uncommon UI design parts or for performance reasons. As a polyglot dev for my day job, I loathe leaky abstractions. I refuse to learn two "frameworks"/"paradigms"/whatever when I could just use one of them and ignore the other. I feel largely the same way about ORMs: it's guaranteed that I'm going to have to be considerate of the generated SQL queries regardless, so why do I have to be an expert at SQL and whatever complexity is in the ORM around caching, flushing, transactions, default values, etc? Ain't nobody got time for that.
I love being a polyglot dev and I love learning and using different programming languages, frameworks, and app platforms. The issue I have is with learning redundant frameworks that don't actually give me more power.
To continue berating ORMs, I am in charge of several different projects at work that communicate with SQL databases. The set of programming languages that span these projects is: Kotlin, PHP, Rust, and JavaScript (being phased out). I love getting to switch between these languages (just not too frequently, lest the context switching kills my brain), and I feel like it helps me to see the strengths and flaws in each, and it's just really fun to find effective patterns in each.
Whether I use an ORM in all or none of those projects, I'm going to have to be competent with SQL. But if I decided to use an ORM for all four, I'd have to learn five different ways to get data in and out of our databases. Rather than learning four redundant, incomplete, data retrieval "languages" that sit on top of SQL, I rather learn... almost anything else.
I have used lots of ORMs: The Symfony one for PHP whose name I can't recall, Magento's weird one for PHP, Hibernate (Java), Sequelize (JavaScript), and a few others in other languages. They all have subtle issues. And they are "issues" and not just different design choices- I'll never ever accept that Hibernate/JPA/JDBC returning a `(int) 0` when it encounters a null result from a nullable integer SQL value is anything short of lunacy when Java has a native null value. And they all have stupid things like that. Learning those gotchas, bugs, abstraction leaks, performance problems, etc, is not the fun kind of learning for me- it's just tedious and frustrating.
So, to bring it back to SwiftUI, I love that I manage an iOS app. I like learning about how iOS works, and I like working with Swift. It's still required that we know how to use UIKit APIs for non-trivial stuff, so why would I learn SwiftUI (and its problems and gotchas) so that I can do 75% of my work with SwiftUI and 25% with UIKit APIs? It's possible that it would make me an even better iOS dev, but I doubt it (at this point). I think my time is better spent learning something that will allow me to accomplish tasks with computers that I don't already know how to do.
> It's totally out of place with the rest of the Swift programming language. They had to add new crap to the language to accommodate its declarative style, when Swift is (was) unapologetically imperative syntax-wise. It's an obvious bolt-on and leaves a really bad taste in my mouth.
Woah now, that's interesting! In my mind swift has had awesome support for functional programming paradigms since launch. I understand it to be leaning in about as far as it can given that it's built with first class support for Obj-c oriented frameworks.
What makes you feel like it's unapologetically imperative?
My experience of SwiftUI is that all of the love and all of the hate is simultaneously correct.
It makes some tasks much much easier, e.g. low vision users really benefit from variable font sizes, which Storyboards can do but it feels unnecessarily hard to do in a non-fragile way.
I can also see the benefits of reactive UI over the Storyboard approach, especially with UICollectionView and UITableView.
But…
The code examples, even from WWDC slides and Apple docs, don’t even always compile; the widgets are different enough it’s not always clear how to get to the desired UI when you’re starting from UIKit, and the integration between UIKit and SwiftUI (in both directions) isn’t as easy as I’d like, and you have to keep resuming the canvas view because it’s not smart enough to figure out for itself when the code now represents a valid view.
> It makes some tasks much much easier, e.g. low vision users really benefit from variable font sizes, which Storyboards can do but it feels unnecessarily hard to do in a non-fragile way.
Code-only UIKit (no storyboards or XIBs) with autolayout handles this case pretty well in my experience. There’s a few gotcha’s but no more than with SwiftUI. You mainly just need to remember to use UIFont’s preferredFont(forTextStyle:) when setting up labels and controls.
It's new and requires different mindset than UIKit. Many times I was thinking "it must be broken!" only to find out later that I was doing things wrong. I suspect many posts on Twitter follow the same pattern.
My advise is to try it, and learn along the way. After a while the idea of going back to UIKit will become scary.
> Conundrum: do I spend the hours required to try different combinations of SwiftUI modifiers to hopefully find a fix for this layout issue, with potential of it breaking again in the future, or do I spend same hours porting to UIKit knowing I’ll likely never have to touch it again
Absolute no-brainer if you ask me. Set it and forget it. Use the cool stuff when it works, let others beta test.
SwiftUI has been a game changer for me as a solo dev. Sure - you have to make tradeoffs like backwards compatibility, and some strange things are missing/don't work. But - it's been a force multiplier. You can break apart complex views into components by copy/pasting its body into a new `View` struct. It's so much simpler than ripping apart a storyboard into a XIB or fighting with layout constraints. The simplicity lets you try things and fail fast without too much of an investment in design complexity.
I find that I can deliver features and iterate much faster and that makes up for the time I spend fixing edge case bugs or bridging to UIKit when I need an unsupported feature.
I hear you, even though I've chosen to just deal with fighting the layout constraints. For what it's worth, I just use a zillion nested UIStackViews when I'm in "try things and fail fast" mode and it tends to work okay for just seeing if the overall thing works like I want. Then I go back and do more precise design work fiddling with spacing, alignment, compression pressure, etc.
Another solo dev, and I can second your sentiment.
I would like to add that I found SwiftUI to be extremely robust against developer mistakes. Things either work, or they give error messages. It's rare that a view is subtly broken.
[Edit: Everyone read ChrisMarshallNY's comment, it's a less terse and more eloquent version of this :)]
My humble belief is that once one understands the inner workings of UIKit, Swift UI is about half of the interactivity of UIKit (read interactivity not as animations or formatting, but actual user controls and inferences from intended actions).
I had requirements to fully understand UITextView, then TextKit and NSLayout, then new ways to interact with text that I have no earthly idea how I would build my interactions in SwiftUI.
In SwiftUI, you get a lot of bang for your buck, but if you want to build something truly remarkable, you need to get your hands dirty and codify your opinions with UIKit.
$0.02 on this is that I see a great many people doing the typical “all or nothing” with SwiftUI. I think this is a mistake. Like every single other engineering tool in existence, this one has costs and benefits.
For the people saying it doesn’t work: use UIKit for those pieces.
Otherwise, use it where it makes sense, and no more. I see this in Compose in Android too - lots of devs doing wholesale refactoring to replace components. Bad move.
SwiftUI is powerful and offers a new way of defining the interface that is focused on the expressiveness it offers to devs. UIKit is just a modified version of that trade off : it offers less expressiveness for more power and sometimes correctness.
To be fair, though, I feel like the difference between SwiftUI and UIKit or XIB is much bigger than the difference between UIKit and XIB.
I don't have much practice with SwiftUI since I have to support some older iOS devices, but how awkward is it to do navigation between screens implementing with SwiftUI Views and those using UIViewController and friends? How does UINavigationController work into all of that?
Yeah, sorry. I wasn't being precise. When I say "UIKit" I mean what iOS devs usually refer to as "programmatic views" where you do all the UI stuff in Swift code files rather than the UI Builder and Storyboard tools that Xcode offers.
I'm sure SwiftUI is UIKit underneath, too, for what it's worth.
If you use SwiftUI at all, the app has to start with the SwiftUI lifecycle (Edit: May not be true, see replies). But then you can wrap any UIView or UIViewController in a SwiftUI wrapper (UIViewRepresentable and UIViewControllerRepresentable). So that view/controller will be presented by SwiftUI's navigation logic, but inside that view/controller, you can write a whole UIKit app if you want.
Cool. Thank you for that. I've got through the SwiftUI tutorials and stuff, but I've never tried to make a real project that mixed both approaches, so I had no idea about UIViewRepresentable, etc.
I think that adds to my point that SwiftUI isn't something that's very amenable to "just use it where it's appropriate", or "gradually try it out by migrating a small part of your project", etc. It sounds like you have to commit to "this is a SwiftUI app now, and we can integrate with old stuff if/where/when we need to".
You can absolutely slowly migrate a UIKit project to begin using SwiftUI – it's part of what I've been doing at work for the past 8 months.
The way to cross the boundary from UIKit to SwiftUI or SwiftUI to UIKit (either direction) involves implementing one or maybe two classes/structs and is not too difficult to do.
What's involved in the "jumping back and forth"? Is it pretty cumbersome or no? Do you use a UINavigationController at all in your app, or do your UIViewControllers do all of the navigating/presenting themselves?
We do use UINagivationController in our app, so that's no issue.
Crossing the boundary from UIKit to SwiftUI involves instantiating the SwiftUIView, handing that over to a UIHostingController, then presenting that controller. Something like this:
let myView = MySwiftUIView()
let hostingVC = UIHostingController(rootView: myView)
navigationController.present(hostingVC, animated: true)
Crossing the boundary from SwiftUI to UIKit is slightly more boilerplate to write, but it's not too bad. You have to implement either a UIViewControllerRepresentable or a UIViewRepresentable (depends on your needs). Those protocols only needs two functions defined: makeUIView/makeUIViewController and updateUIView/updateUIViewController. For the simplest views and view controllers, you can leave the update definitions empty.
When you support a range of tools, or introduce a new one, you often do it to support different audiences. I'm not an iOS dev. Is it a case that SwiftUI is really intended for a different audience and set of use cases with no expectation of a 100% overlap with the UIKit use cases?
I think trying to re-tool an existing app to be swiftui is a mistake. Replace swiftui with anything and it's a mistake. But swiftui is marketed as a replacement for UIKit and it doesn't seem to work. If I was starting a new app it still seems like a bad idea. Every attempt my team has made to make even small components in swiftui has been a disaster.
I think this hides the actual pitfalls: it is possible to be lulled into thinking SwiftUI is the right tool, only to discover that a minor UI change is impossible, leaving you with little option than to dump it entirely for the component in question and rewrite it from scratch in UIKit or AppKit. It is a truism that you should "choose the best tool for the job". Yes, of course. You definitely shouldn't choose the worse tool for the job after all. The tricky bit has always been in determining which tool is best for the job. Once upon a time the answer was easy, there was only one tool, and critically, it was the tool Apple themselves dogfooded for their own stuff, so it was usually at least capable of doing most things. In the age of AppKit/SwiftUI/Catalyst, this is a significantly more difficult question, and this is ignoring things like Electron, etc. The problem with SwiftUi is precisely that if often feels like you only know if it was the best tool for the job after the fact. It requires being an expert in it before you can predict its limitations (which often are bug-related and not necessarily "conceptual"). This would maybe be excusable for a beta release, but SwiftUI is now around 4 years old.
Arguably, its original sin is simply not being open source, and on top of that is trapped behind one of the most opaque bug-reporting mechanisms in the industry. Every minor hack involves tremendous reverse-engineering, which may then have to be replicated throughout the community, instead of being a GitHub issue and PR request like in Electron for example. There are of course upsides to the closed-source model, but in 2022, you have to deliver on those upsides if you want to make a strong case for your framework. But as I've mentioned above, SwiftUI hasn't. It has none of the aura or magic of AppKit from the 2000's: a framework used by amazing apps at Apple that can get just about anything done. In fact it is the poster child of all the downsides of this model.
Is anyone using this really? My team is pretty excited about using it but I've been a little more hesitant mostly because I've not read of anyone using it at any sort of scale with success. Even for smaller project it still doesn't seem production ready.
I'm using SwiftUI extensively when I get the opportunity. The team that I'm on has decided to shift our UIKit+Storyboards app towards leveraging SwiftUI more. It won't work for 100% of the app, but that's alright because there are easy-to-implement escape hatches back into UIKit.
The worst part of the dev experience is that we are currently supporting back to iOS 13 (which is when SwiftUI was introduced). That means we can only really use the oldest SwiftUI components and modifiers; it's not too bad, but finding usable examples online is tricky sometimes (they often assume the latest).
I don’t think I would have attempted a project this large without it. I had to fall back to AppKit/NSViewRepresentable for the tabview, text editor, and a couple other views. There are probably over a hundred SwiftUI views though. And I am hoping I can switch the tabview to SwiftUI after WWDC so it’s easier to extend.
About WWDC, I wonder if we’ll see a CoreAnimation replacement this year that is exposed to SwiftUI views? I don’t know what the implications would be, but it makes sense when you look back at how they’ve refused to offer/expose the underlying UIKit/AppKit APIs that SwiftUI is wrapping for some controls.
I just finished a contract on an app with 400K users.
It was in pretty bad shape when I got my hands on it. Last update: February 2020. Targeting iOS 11+, mostly UIKit, powered by Cocoapods with 25 dependencies, and 1.3M LOC.
It took me 3 months to rewrite everything from scratch in SwiftUI, with 100% feature parity. Of the ~20 different view/components that I had to write, just one required me to dip into UIKit (with UIViewRepresentable to bridge).
Now the app is iOS 14+, 5 dependencies (all managed with Swift Package Manager) and 6.5K LOC, with 0 crashes in the last month.
Wait, it went from 1.3M LOC to 6.5K? Was the UI layer really that bloated or are you counting the 3rd party dependencies? I envy you the 3 months without adding any "customer value" (not joking, I'd love that).
Yeah. 1,300,000 to 6,500 (not counting the dependencies). While the previous devs obviously had programming experience, it was clear they were quite green in Swift/iOS.
Customer value was that the OG app was crashing like 1 in every 6 uses. Updated app was crash free. Plus, added two new features during the rewrite.
I've written architecture astronaut code of my own, so I saw this coming. Swift the language, and SwiftUI the gui toolkit, have a classic over-engineered magnum opus style to them. The generality and generic-ness just leak out all over the place. I also saw a bit of this early on in Dart and Flutter. From what I can tell they seem to have charted a better course and avoided getting stuck too deeply in their own perfection vision.
You are probably pulling firebase into your preview code somewhere. You should structure your previews to depend on mock implementations of your model (or mock data). It will make the previews much faster and more reliable.
My app also uses firebase and SwiftUI with hundreds of files (views, view models, and more) with no problems.
Got working SwiftUI previews on a 50-100k LOC project with many big libs as dependencies, must be hundreds of files but havent counted. SwiftUI code is gaining share of the total UI code, probably around 20-30% now
Mock data is a must.
Need to be mindful of the preview build (+ preview simulator startup) time too, sometimes it will timeout but just building again (now warmer) will make it work
Had some initial issues around processor arch (Intel vs M1/arm), think I’m still running XCode under rosetta otherwise it wouldnt work.
one other solution is to build a sub project that links to a subset of minimum dependencies needed for ui development and build your swiftui stuff there...
it will be lightning fast compared to large xcode project... and it might even be better architecturally too, since you'd have to factor out lower level logic (view models or whatever) anyways
Yes, I recently built an entire app with 70+ frameworks that works fine in Previews. The key is to isolate dependencies into their own modules, and also split those into interface / live implementation modules if needed if the live impl causes preview crashes. See https://www.pointfree.co/episodes/ep171-modularization-part-...
It's not a surprise there's zero overlap. The type of people who develop native Apple-only apps really care about having proper first-class native UI down to every detail, not merely something close enough. As you can see, for many even Apple's own SwiftUI isn't "native" enough, so at this level of detail using Google's generic UI framework is completely unthinkable.
For cases where portability or development time is valued more than having perfect Apple-HIG-compliant UI polish, there are lots of better options. Since Apple has flattened their Aqua interface out of existence down to mostly just gray text labels, even Electron apps started looking good-enough.
Could you give some examples? Most people I talked to really hate React Native, for example. Ionic doesn't seem to have gained enough momentum. You mention Electron, but the last time I checked it's only for the desktop, not mobile. Each year new options appear, but I'm not sure they are that great.
I had mostly desktops in mind where there are more widget toolkits to choose from. On mobile it's not so great indeed. Cordova is a mobile equivalent of Electron, but often you can get away with your own native app shell + WebView.
Objective-C compiles much faster. Fewer compiler errors. Fewer compiler crashes. Older projects still compile. The debugger is much more reliable. The entire Objective-C toolchain is more solid, because it's older, mature, and changes less.
Also, easier compatibility with cross-platform C and C++ source.
Once you get past the square brackets notation, ObjC is a really delightfiul language to code in largely because of it's message-passing object system. In many ways Swift was a step forward, and more approachable for beginners, but for me it's also a few steps backwards for programmer happiness.
If you know C, Objective-C is very little syntax on top of it.
I learnt it over a weekend ~12 years ago by mostly reading Apple's programming guide[1] and then the Objective-C runtime reference[2] and just playing with some code and GDB. That was enough for me to lead a small team of iOS devs and we built slew of popular apps for the next two years. My background prior to that was in desktop GUI development using Qt and C++.
I don't work in the iOS/macOS dev field anymore, but I've tried learning Swift in a similar fashion over weekends, to no avail. Incidentally, do you have any recommendations for learning Swift for someone coming from a C/ modern C++ background?
Objective-C can feel easier to different types of developers for different reasons.
For disciplined developers who always dot their I’s and cross their T’s, it feels easier because they can write code with full “trust” from the compiler that the developer knows what they’re doing.
For undisciplined developers, it can feel easier because the compiler isn’t calling them out on code smells and inattentiveness to nullability and types.
I’d like to think I’m somewhere in the middle (as I suspect most devs are) and for me Swift feels easier in most respects, even with its everything-and-the-kitchen-sink nature compared to Objective-C’s more spartan approach.
Swift is very strict. Objective-C lets you get away with more. E.g. optionals in Swift are kind of annoying. if let, guard let, blah blah blah. I like Swift more than Obj-C, but Obj-C is a fine language in its own right. Definitely easier to write once you get a hang of the notation. Swift may have a more familiar syntax, but it forces you to think about more things when writing code.
From my understanding, you have to use SwiftUI differently than it is eventually intended. First, you build 90% of the app in SwiftUI, then you use UIKit for the other 10% that can't be done in SwiftUI. Eventually you will be able to do everything in SwiftUI, but for now, this strategy works pretty well.
IMO SwiftUI feels limited b.c. it breaks itself away from the UIKit world: React succeeded because it is the DOM with all of raw HTML & CSS, a thin abstraction with official escape hatches. Mixing imperative and declarative code is natural and more abstractions can be built.
Instead, SwiftUI adopted a whole new set of primitives that doesn’t mix. Accessing the underlying UIView is discouraged, and wrapping up UIKit in SwiftUI feels like a legacy feature. IMO SwiftUI should have been a thin wrapper on UIKit.
There are official escape hatches in SwiftUI to let you leverage UIKit. As someone actively working on a slow migration from UIKit to SwiftUI (where possible), it doesn't feel discouraging to wrap a UIKit view to use it in SwiftUI if necessary.
That’s more of a compatibility solution than an escape hatch. An official SwiftUI escape hatch should have access to the underlying imperative object, call methods on it, etc… Unfortunately the underlying ‘things’ in SwiftUI is implementation detail, inspecting the view hierarchy and finding the UIViews that implement a SwiftUI view is a hack.
As I understand it, what you’re asking for is fundamentally incompatible with the paradigm itself (at least in a clean way).
The whole programming experience of declarative UIs is predicated on the fact that you’re manipulating lightweight structs (really just state representations) that are rendered into heavyweight views by the system only where necessary (determined by diffing the state changes).
React’s refs are an attempted answer to this very problem, and they get nasty fast.
Yup, and my understanding of the problem is that if you expose the heavy weight views to the state layer (structs) and allow direct manipulation, render calls lose incompetency, the structs are no longer the source of state truth and the whole abstraction gets terribly leaky.
Edit: once again I think it’s important to look at the limitations and advantages of prior work in this area and I believe React refs to be a good case study in that.
“Hey I got 90% of what I wanted really quick! Neat!” “…oh turns out that last 10% is basically impossible, eh?”
This seems to be the story of apple in general. Very beautiful and easy to use as long as you stay on the path and don’t go too far along lest you discover the 2nd mile is still under construction.
That last 10% is easily accessible by reaching into UIKit. Crossing that boundary is much easier in practice than one might expect at a first glance of the docs for doing so.
I'm really looking forward to what comes of it, but I have chosen to do my current major project in UIKit.
A couple of reasons:
1) The documentation for SwiftUI, when I started (about two years ago) was awful. I was shocked at how bad it was. I believe that it has since improved.
2) I knew of no major apps (even Apple ones) that had been done with it.
I already knew that UIKit was up to the task, and held my nose, while I set things up. It's working out extremely well, but (of course) I'd like to rewrite the whole thing (a sure sign that I'm approaching ship).
I like things like the MVVM pattern, but it's been my experience that it's really not such a good idea to implement it in UIKit, because UIKit was designed explicitly for MVC. I have learned that those ugly-ass UIViewControllers are really important, and I circumvent them at my peril.
I'm able to release fairly basic Apple apps in UIKit, in just hours, so speed of development isn't compelling.
What is compelling, is the ability to design a reactive system for a complex app (like the one I'm writing now). AppKit has allowed this for some time, and it's possible to force UIKit to do it (but it isn't really designed for that).
I really wish that SwiftUI had been a bit more mature, when I started this system, but I would have also needed to rewrite the two server SDKs I use, anyway. It wouldn't have worked, no matter how hard I bang my heels together.
But I'm looking forward to it.
One thing that I've learned, is that it's really OK to wait for things to mature. Companies always screech about how we need to jump on the bandwagon, but that's all hype. I have taken OpenDoc courses at Apple DU. I also busted my ass, getting my app ready for Copland. I have scars from Apple hype.
I did take a big chance, by jumping directly into Swift, but that has turned out to be a good decision.
I’ve been dabbling in SwiftUI in an existing UIKit app from time to time for a while now and have similar feelings. Even if you get past the lack of docs, SwiftUI is missing just enough bits and pieces to make it a pain. I can usually get things about 90% to where they’re supposed to be, and then I rewrite it in UIKit because that’s the only way to get the fine details right without convoluted hackery. Lack of backwards compatibility doesn’t help here — several times something I’ve needed has only been available for iOS 14/15+.
I think it has massive potential regardless, but yes it’s going to need some time to fully bake (much as UIKit did).
It’s too bad that Cocoa Bindings never found their way from AppKit into UIKit. I understand their exclusion was likely due to CPU power limitations early on, but that hasn’t been a problem for many years at this point.
Yeah UIKit is deeply MVC. It may not be the most conceptually elegant but in my experience you're almost always better off cutting with the grain of the underlying platform's abstractions instead of trying to superimpose a new leaky abstraction on top of them.
I worked on one large iOS codebase that went all in on the VIPER architecture and it was one of the most unweildy and baroque codebases I've ever had the misfortune to work in.
I apologize to the people who bought into this pattern but what was anyone thinking? Just reading through how it was supposed to be done set off so many red flags I never even considered it. There is so much useless abstraction it makes no sense.
I think it was designed to break up app development into large, relatively unskilled, teams. The traditional UIKit model (and, I suspect, the SwiftUI model) is for small (maybe single IC), skilled, teams.
It's sometimes impossible to fight the architecture astronauts, they can be deeply appalled at how software maps to their thinking and wish to bend it towards nonsense until it does
One recurring issue I see on native Android navigation is, when you open an image in a file manager, switch back to the file manager and open a second image in the same viewer, sometimes pressing Back takes you to the first image. As a specific example, in Foxy Droid, if you download 3 apps in the background, get 3 "app downloaded" notifications, and click each one in sequence, you have to press Back 3 times to get back to Foxy Droid's home screen. What's the best way to avoid this issue without reimplementing your own navigation system replacing activities?
Basically, don't use Intent flags you don't need to use. FLAG_ACTIVITY_NEW_TASK will launch the external activity in its own back stack according to its `launchMode` rules. If you just launch the Intent with no flags, the default behavior is to add the activity to your own task, which is usually what you want.
The other half of the equation is: don't override Back behavior unless you "own" the current task (it's rooted at one of your activities). When handling "Up" navigation and deep-links, you want Back to behave like "Up" and go to the logical parent of the current screen. When being launched in someone else's task, "Up" should launch a new task at the logical parent and "Back" should perform the default behavior (usually, Activity.finish()).
> better off cutting with the grain of the underlying platform's abstractions
That's a great little turn-of-phrase that I plan on stealing in the future. Apple's APIs will absolutely reward you for taking the time to step back, figure out how Apple wants you to use them, and try your hardest to use them in that way.
An example from the olden days of iOS development: many of the apps I worked on went out of their way to avoid subclassing UIView, filling their view controllers with layout and interface updates that would have made much more sense in a view. If only they had read all the docs for UIView would they know that doing something like subclassing a button and tweaking a few methods would have done exactly what they wanted with a minimal amount of work.
i've been developping for 20 years, and 10 years on iOS as a freelance.
I've seen all the horrors, and i can now safely claim that all the problems i've seen on iOS development come from not designing the model layer properly in their MVC app. Because most developers start by coding UIs and later end up wondering where to put that business logic and make it reusable.
And now every time i see another pattern that claim to facilitate refreshing the UI upon model change ( and vice versa), i know it's going to be a failure.
UIKit isnt even deeply MVC. Its purely C. The Controller is the god object by design, but also because the first 10 years of iOS tutorials never took the time to even split out a single View. So that became the gateway for everyone learning the platform, and is what they imitated.
Its not much better today overall, but is usually not an issue within companies themselves.
I think that most of the smaller Apple apps are now SwiftUI (and Catalyst).
But the app I'm writing is a good deal more complex than most of the utility apps, and I seriously doubt that the complex apps are SwiftUI. I would not be surprised if many of them are still ObjC.
> I like things like the MVVM pattern, but it's been my experience that it's really not such a good idea to implement it in UIKit, because UIKit was designed explicitly for MVC. I have learned that those ugly-ass UIViewControllers are really important, and I circumvent them at my peril.
I agree with everything you've said but this. I've worked on 3 very large app, one which is 85% using mvvm, the two others were still in experimentation phases with it and I am not sure where they've ended up. It's been a joy. The app is designed in a very reactive way and the data flow paths are very clearly defined and easy to follow.
Don't get me wrong the other two apps were heavily MVC with a lot of delegation and that was fine. I could easily switch back to an architecture like that but it's very possible and quite easy to switch over to an mvvm pattern.
I have heard many state that. It has not been my experience.
It may be because I want a "pure" MVVM, and it has to be sort of "impure" to work with UIKit apps. In that case, it just adds more code. I'm a "the best code I write, is the code I don't write" kind of guy.
> I like things like the MVVM pattern, but it's been my experience that it's really not such a good idea to implement it in UIKit, because UIKit was designed explicitly for MVC. I have learned that those ugly-ass UIViewControllers are really important, and I circumvent them at my peril.
I dont understand this. MVVM is an extremely abstract pattern. It transcends the technology stack. How it is implemented on the platform differs, and yes you are not going to avoid the UIViewController when doing it on iOS. But you are still doing MVVM even if your V is actually a UIViewController.
I use MVVM almost exclusively now, and I usually do it in a cross-platform framework (Xamarin/MAUI). The codebase is portable across both iOS and Android with no re-architecting of the high-level architecture pattern.
I liked the "cut with the grain" comment, someone made earlier.
The UIViewController must be present in a UIKit app. Most classic UIKit apps have the lions' share of code in UIViewControllers.
It's entirely possible to basically use a "skeletal" one, and have the main code in the linkages between the Model and the View, but that makes the Storyboard Editor useless.
I use the Storyboard Editor a lot. It is not my favorite editor, but it allows me to work incredibly quickly, and to make a really reflowable UI.
I know that the app I'm working on now, is larger than any I've seen from SwiftUI (around 40 screens, and communicating with three servers in realtime, using a couple of SDKs). I am able to make it all work.
I feel as if MVVM would make the parts of the app that link the UI to the servers a lot more graceful (it's a nasty state engine, right now -ick). I feel as if this kind of app is the kind of thing they had in mind, with SwiftUI.
I do know that it's really important to derive subclasses, and extend ObjC classes, when using UIKit/AppKit/WatchKit, and I feel sorry for folks that avoid inheritance like the plague. It must be a fair bit of work. Looks like SwiftUI doesn't really need that at all, but I haven't spent enough time with it, yet, to know for sure.
I have no doubt that I'll end up mastering it. I'm a quick study. I've spent 35 years, surfing the tech wave.
> The UIViewController must be present in a UIKit app. Most classic UIKit apps have the lions' share of code in UIViewControllers.
I dont think you understand the point I'm making. Just because Apple has created a framework that has something called UIViewController which has child UIViews doesnt matter when using a pattern called MVVM. The V is just the _visual_ representation of the pattern. It could be a terminal console if you want, it doesn't have to be the "underlying" view of the platform! Don't fight the platform to align its idea of the view with a specific thing called a View in the pattern.
EDIT: and yes IB is an issue if you want to be programmatic. I do all my views in code.
Actually, I understood just fine. I’ve been doing this kind of thing for a while. I’m not even disagreeing. I understand where you are coming from.
It’s just Apples and oranges.
I write in Swift, as a native developer of Apple software. I won’t go into all the reasons I do what I do (actually, I’ve covered a lot, in this thread). I have my reasons, and there’s nothing wrong with my approach. I get a lot done, very quickly, and at a fairly high Quality level.
Life is a compromise. We always need to make trade-offs.
You could write an opposite article featuring people using SwiftUI that have never touched UIKit or iOS code before and it would be nothing but glowing praise.
That's kinda like my story. Covid started and I wanted to learn something new so I started with Swift/SwiftUI. 2 years later I've been doing tons of crazy custom stuff in my portfolio tracker app https://stocketa.com (not launched yet) - I kept a thread with my progress since the first day I started my journey: https://twitter.com/Stammy/status/1527288954935922688 (scroll up).
> You could write an opposite article featuring people using SwiftUI that have never touched UIKit or iOS code before and it would be nothing but glowing praise.
How can one properly evaluate it with no point of comparison?
If you've never tasted chocolate, then vanilla might seem like the greatest flavor ever.
The point of comparison is that it has given people the ability to develop their own iOS apps from scratch, when previously they could not as UIKit was too daunting and the tools were not as advanced (live preview with swiftui/etc).
SwiftUI is not less daunting than UIKit. In fact I would say that the SwiftUI "magic" is far scarier for beginners than IBOutlets and UIViewControllers
I watched a youtube video about VStacks and Spacers and I was having fun making real layouts my first hour in - with a fast, live preview environment. That was my "oh wow" moment. What's the equivalent with UIKit? Interface Builder is nothing like what's now possible with SwiftUI. I've tried IB in the past and it was not for me.
I have been watching your progress on Stocketa and as an experienced iOS engineer who uses SwiftUI at work, I have been amazed by the speed with which you were able to build the app. The fact that you were able to ship a real app (with custom graph and polished animations) really speaks to how accessible SwiftUI is to new developers compared to UIKit.
I work for mid size company with a fairly big app with millions of users and we did a complete re-write of the app in SwiftUI and I can say with confidence that once a SwiftUI view layer is built out, building features on top of that is incredibly fast compared to UIKit.
UIStackView is much more boilerplate to use than just a HStack/VStack. And I do a lot of design work in SwiftUI–it's really easy to get stuff on the screen and directly how you want it to look, even for a design mockup. I'll just not hook up interactivity and it works just fine for that kind of storyboarding. If you have a designer that wants you to follow their lead "to the pixel" then they're probably not doing their job of UI design very well–a good process works both ways, where you provide insight into what works well on the platform and they provide their own suggestions until you meet in the middle.
Then again, you can eliminate a lot of that boilerplate. I have a demo app up where I generate UIViews using resultBuillder such that you get a very SwiftUI-like experience using UIKit views.
It may have a easier ramp-up, but it also has a huge cliff at the end of the ramp. Once you step off the happy path you're in for an even more daunting experience than UIKit, because SwiftUI doesn't give you much to get below the magic when you need to. Also, previews are fairly constantly broken in my experience. Interface builder has its problems too, but at least it renders the nib every time.
I have a similar experience (started working from scratch on an iPhone app back in January with SwiftUI). Live preview is really awful. I had to basically disable it throughout my project. It'll crash for no reason and require a manual click on a button to reload, errors it spits out tend to be unintelligible, etc. I definitely wouldn't use live preview as an example of SwiftUI being advanced and not being daunting to use.
It's quite a bit different experience working on an app by yourself and working on an app that has several hundred thousand lines of code that 10+ people are working on simultaneously. I've worked with a bunch of people that are complaining in this and the problems you face are quite a bit different.
You’re not wrong; that is the blog’s style. I enjoy the format for exposing me to a cross-section of opinions from across the internet, on topics I find interesting, with very little work on my part. That’s probably more an indictment on Twitter’s product stagnation than a shower of praise on this blog and it’s author.
As someone who got his start in programming with Obj-C and AppKit, I’m totally sold on Swift. I’ll still do small tools and the like with Obj-C sometimes but for projects with any complexity, Swift is my go-to. The number of stupid mistakes the Swift compiler catches and little QoL things like not having to maintain header files make it worth its comparative downsides.
As a solo, hobbyist iOS & macOS dev, I like SwiftUI. It's much easier to learn than all of UIKit and AppKit. Feels like React.
That said, I find myself dipping down into AppKit and UIKit quite often. Any kind of complex views or UI interactions outside the happy path, just grab that UIViewRepresentable.
Lots of great and specific points in these threads, many of which I have personally seen.
SwiftUI was really promising at first, and even fun to use (nothing like ripping out entire UI files or pages of code). Yet, issues were almost immediately apparent.
A major concern is that it seems to take Apple a really long time to address even basic issues, e.g. years go by and things still broken since day 1 are there, while other things are randomly introduced. And of course, “Feedbacks” have the usual dice-roll effect: will you even get a response, much less see any indication that the reported bug will ever be fixed? (Or will Apple just wait 2 years, close your bug as “probably fixed in this OS update, please confirm”, and repeat the whole thing?)
And the thing is, this is not hard to believe. If you auto-complete in SwiftUI (what else can you do, there is rarely good documentation?), some of the APIs are truly scary: levels of complexity and variation that really make me wonder if they can truly test, much less support, every variation of every API. I would strongly argue that some things just have way too many options instead of a handful of clear starting points.
SwiftUI also occasionally changes behaviors (e.g. subtle or gross layout differences). Worse, it is easy for Apple to not call any of these changes “breaking” because apparently you are just supposed to let SwiftUI figure out what is needed in any situation. Except that kind of “trust us, we’ll come up with something” approach is not great for writing stable production software.
The auto-generated hierarchies can do truly weird things. For example I realized at one point that an “auto-saved” window layout auto-generated preference names based not on a simple string but the entire SwiftUI view hierarchy, which was huge and indecipherable and of course would become a different value if any part of the window or view hierarchy was modified. So I discovered I had dozens of preference settings scattered throughout my defaults, 99% of which were completely obsolete because they were based on previous incarnations of the view I was developing, and they all had names that were almost impossible to type (so how do I delete them while preserving the rest?). What do you even do with that?
Yet another major concern is that SwiftUI is very dependent on Combine which is not necessarily the future given other developments in the Swift language. So what if they just decide to, say, deprecate Combine and move further toward actors and async APIs? How much of SwiftUI might just fundamentally change in, say, WWDC this year, completely invalidating years of effort people have put into it?
> Yet another major concern is that SwiftUI is very dependent on Combine which is not necessarily the future given other developments in the Swift language. So what if they just decide to, say, deprecate Combine and move further toward actors and async APIs? How much of SwiftUI might just fundamentally change in, say, WWDC this year, completely invalidating years of effort people have put into it?
If you’re talking about Combine vs async/await, I think they’ll continue to coexist because they fill different niches. In the UIKit app I’m responsible for I use both — async/await for things like network calls and Combine for keeping UI state in sync with data.
> deprecate Combine and move further toward actors and async APIs
Combine is an abstraction to encapsulate changes in state over time, while actors and async APIs are abstractions to encapsulate concurrent behavior. I think these are orthogonal concerns, so they wouldn't likely drop one in favor of the other.
> SwiftUI is very dependent on Combine
As someone who's been writing SwiftUI a lot over the last year or two, I've only touched Combine a few times. Even then, I only tried it because I wanted to see how it compares to RxSwift, not because it was something I needed.
Yeah I've never used Combine and I've written a decent amount of SwiftUI. My impression is that Swift Concurrency is the future and will slowly get more and more adoption in the APIs.
My team has two green field apps that we started a few weeks ago. The leads on the iOS team and Android team both spent a week evaluating the new UI systems in each platform, SwiftUI and Jetpack Compose.
The conclusion was that Apple made a huge mistake tying it the iOS version and effectively limiting updates and it's real world use for years at a time.
Both leads liked the design paradigms, but we are only going to use Jetpack Compose since it's made of multiple libraries that are all backwards compatible with our minimum supported version. iOS will stick to UIKit since it works and is backwards compatible
Yeah iOS is one thing as you can generally wait it out as Apple is pretty aggressive about upgrades there but on macOS I think this limitation has really killed it's viability, people just don't update their desktop OS.
Not to mention that Apple just orphaned a shitload of perfectly viable computers (first-gen Retina iMacs, for example).
I was also baffled to find that TestFlight can't be installed on pre-Monterey Macs. I mean... WTF? That makes no sense. Sure, we can pass DMGs around, but my company is new to Macs and standardizing our QA team on TestFlight on all devices would've been simple.
> The conclusion was that Apple made a huge mistake tying it the iOS version and effectively limiting updates and it's real world use for years at a time.
Exactly this. SwiftUI on iOS 13.x is practically unusable for anything above simple implementations, with some fairly major bugs that weren't fixed until iOS 14-15. Bugs aside, the lack of StateObject in SwiftUI (iOS) 13.x makes it a non-starter.
I've tried both SwiftUI and Jetpack Compose (the equivalent framework for Android). While conceptually they are very similar frameworks, in practice I found that Jetpack Compose + Kotlin had a far superior development experience than SwiftUI + Swift.
I genuinely cannot think of a single thing that SwiftUI does better than Jetpack Compose.
There are a lot of fundamental design decisions in SwiftUI that are questionable, like their reliance on two-way binding (which makes non-trivial event handling very difficult to implement), or having Views be structures rather than functions (which then necessitated special ForEach views, because you can't use regular control flow mechanisms).
The problem with SwiftUI is what Apple seems to consider its advantage: that it hides complexity from the developer (see their “Avocado toast maker” analogy in one of the WWDCs). The reason this is a problem is because sometimes you do need to break out of the paradigm, and doing so is basically always painful. At least with UIKit and AppKit you are always in full control. Complex apps will break out of the SwiftUI box all over the place, destroying the benefits. You can usually hack things to make it play with SwiftUI nicely, but it always feels like a hack.
One example I had was trying to put an ObservableObject into UserDefaults for persistent storage. There’s not really a nice way to do this. SwiftUI only knows how to store basic scalar values in UserDefaults. That kind of makes sense, because UserDefaults is only meant for small amounts of data, but what if I want to save a struct that has two fields? Trying to do this in SwiftUI is actually quite painful and that is a very simple example. Another pain point is app navigation which basically does not work properly at all.
Though one very nice thing is that it’s quite easy to use a SwiftUI view from UIKit
Overall though, somehow a far worse experience than using something like React
Apple tried to solve this with @AppStorage, but if you lean on MVVM... it doesn't really work. Hoping we get some new CoreData + UserDefaults stuff this upcoming WWDC
"tried" being the operative word. But you really shouldn't be persisting an ObservableObject. You should extract what you need into a model and use Codable...
Why shouldn't I try and persist an ObservableObject? Has some Apple guru given you this secret information in a WWDC, or personally? It seems totally reasonable to do so. Observability is something you bestow upon a model, it shouldn't exclude it from persistence. You are talking nonsense to defend Apple's lazy approach. They simply have not covered this base, that's the actual non-Apple-fanboy explanation. Get it together
215 comments
[ 3.1 ms ] story [ 255 ms ] threadI'm sure that a big part of that is the effect of it being Twitter. How often do we feel the urge to post something online that we have no strong feelings about?
More on topic, though: I'm a SwiftUI hater still. It's a cool concept, but there are two big problems with it, IMO:
1. It's totally out of place with the rest of the Swift programming language. They had to add new crap to the language to accommodate its declarative style, when Swift is (was) unapologetically imperative syntax-wise. It's an obvious bolt-on and leaves a really bad taste in my mouth.
2. It's still a very leaky abstraction, in that there's still a lot of stuff you have to reach into UIKit for, whether it's for uncommon UI design parts or for performance reasons. As a polyglot dev for my day job, I loathe leaky abstractions. I refuse to learn two "frameworks"/"paradigms"/whatever when I could just use one of them and ignore the other. I feel largely the same way about ORMs: it's guaranteed that I'm going to have to be considerate of the generated SQL queries regardless, so why do I have to be an expert at SQL and whatever complexity is in the ORM around caching, flushing, transactions, default values, etc? Ain't nobody got time for that.
I love being a polyglot dev and I love learning and using different programming languages, frameworks, and app platforms. The issue I have is with learning redundant frameworks that don't actually give me more power.
To continue berating ORMs, I am in charge of several different projects at work that communicate with SQL databases. The set of programming languages that span these projects is: Kotlin, PHP, Rust, and JavaScript (being phased out). I love getting to switch between these languages (just not too frequently, lest the context switching kills my brain), and I feel like it helps me to see the strengths and flaws in each, and it's just really fun to find effective patterns in each.
Whether I use an ORM in all or none of those projects, I'm going to have to be competent with SQL. But if I decided to use an ORM for all four, I'd have to learn five different ways to get data in and out of our databases. Rather than learning four redundant, incomplete, data retrieval "languages" that sit on top of SQL, I rather learn... almost anything else.
I have used lots of ORMs: The Symfony one for PHP whose name I can't recall, Magento's weird one for PHP, Hibernate (Java), Sequelize (JavaScript), and a few others in other languages. They all have subtle issues. And they are "issues" and not just different design choices- I'll never ever accept that Hibernate/JPA/JDBC returning a `(int) 0` when it encounters a null result from a nullable integer SQL value is anything short of lunacy when Java has a native null value. And they all have stupid things like that. Learning those gotchas, bugs, abstraction leaks, performance problems, etc, is not the fun kind of learning for me- it's just tedious and frustrating.
So, to bring it back to SwiftUI, I love that I manage an iOS app. I like learning about how iOS works, and I like working with Swift. It's still required that we know how to use UIKit APIs for non-trivial stuff, so why would I learn SwiftUI (and its problems and gotchas) so that I can do 75% of my work with SwiftUI and 25% with UIKit APIs? It's possible that it would make me an even better iOS dev, but I doubt it (at this point). I think my time is better spent learning something that will allow me to accomplish tasks with computers that I don't already know how to do.
Woah now, that's interesting! In my mind swift has had awesome support for functional programming paradigms since launch. I understand it to be leaning in about as far as it can given that it's built with first class support for Obj-c oriented frameworks.
What makes you feel like it's unapologetically imperative?
It makes some tasks much much easier, e.g. low vision users really benefit from variable font sizes, which Storyboards can do but it feels unnecessarily hard to do in a non-fragile way.
I can also see the benefits of reactive UI over the Storyboard approach, especially with UICollectionView and UITableView.
But…
The code examples, even from WWDC slides and Apple docs, don’t even always compile; the widgets are different enough it’s not always clear how to get to the desired UI when you’re starting from UIKit, and the integration between UIKit and SwiftUI (in both directions) isn’t as easy as I’d like, and you have to keep resuming the canvas view because it’s not smart enough to figure out for itself when the code now represents a valid view.
Code-only UIKit (no storyboards or XIBs) with autolayout handles this case pretty well in my experience. There’s a few gotcha’s but no more than with SwiftUI. You mainly just need to remember to use UIFont’s preferredFont(forTextStyle:) when setting up labels and controls.
My advise is to try it, and learn along the way. After a while the idea of going back to UIKit will become scary.
Absolute no-brainer if you ask me. Set it and forget it. Use the cool stuff when it works, let others beta test.
I find that I can deliver features and iterate much faster and that makes up for the time I spend fixing edge case bugs or bridging to UIKit when I need an unsupported feature.
I would like to add that I found SwiftUI to be extremely robust against developer mistakes. Things either work, or they give error messages. It's rare that a view is subtly broken.
My humble belief is that once one understands the inner workings of UIKit, Swift UI is about half of the interactivity of UIKit (read interactivity not as animations or formatting, but actual user controls and inferences from intended actions).
I had requirements to fully understand UITextView, then TextKit and NSLayout, then new ways to interact with text that I have no earthly idea how I would build my interactions in SwiftUI.
In SwiftUI, you get a lot of bang for your buck, but if you want to build something truly remarkable, you need to get your hands dirty and codify your opinions with UIKit.
For the people saying it doesn’t work: use UIKit for those pieces.
Otherwise, use it where it makes sense, and no more. I see this in Compose in Android too - lots of devs doing wholesale refactoring to replace components. Bad move.
SwiftUI is powerful and offers a new way of defining the interface that is focused on the expressiveness it offers to devs. UIKit is just a modified version of that trade off : it offers less expressiveness for more power and sometimes correctness.
Mix your poisons, don’t pick them.
I don't have much practice with SwiftUI since I have to support some older iOS devices, but how awkward is it to do navigation between screens implementing with SwiftUI Views and those using UIViewController and friends? How does UINavigationController work into all of that?
I'm sure SwiftUI is UIKit underneath, too, for what it's worth.
I think that adds to my point that SwiftUI isn't something that's very amenable to "just use it where it's appropriate", or "gradually try it out by migrating a small part of your project", etc. It sounds like you have to commit to "this is a SwiftUI app now, and we can integrate with old stuff if/where/when we need to".
The way to cross the boundary from UIKit to SwiftUI or SwiftUI to UIKit (either direction) involves implementing one or maybe two classes/structs and is not too difficult to do.
In fact, you can jump back and forth between UIKit and SwiftUI as many times as you like throughout your app's view hierarchy.
The current project I'm working on involves slowly porting an older UIKit+Storyboard app over to SwiftUI, so I'm seeing this in practice every day.
Crossing the boundary from UIKit to SwiftUI involves instantiating the SwiftUIView, handing that over to a UIHostingController, then presenting that controller. Something like this:
Crossing the boundary from SwiftUI to UIKit is slightly more boilerplate to write, but it's not too bad. You have to implement either a UIViewControllerRepresentable or a UIViewRepresentable (depends on your needs). Those protocols only needs two functions defined: makeUIView/makeUIViewController and updateUIView/updateUIViewController. For the simplest views and view controllers, you can leave the update definitions empty.But it doesn't address the part where devs find SwiftUI buggy and non-functional where there is a promise of functionality.
Kind of like Duplo vs Lego.
Arguably, its original sin is simply not being open source, and on top of that is trapped behind one of the most opaque bug-reporting mechanisms in the industry. Every minor hack involves tremendous reverse-engineering, which may then have to be replicated throughout the community, instead of being a GitHub issue and PR request like in Electron for example. There are of course upsides to the closed-source model, but in 2022, you have to deliver on those upsides if you want to make a strong case for your framework. But as I've mentioned above, SwiftUI hasn't. It has none of the aura or magic of AppKit from the 2000's: a framework used by amazing apps at Apple that can get just about anything done. In fact it is the poster child of all the downsides of this model.
And this doesn't even touch on the fact that Apple seems to repeatedly demonstrate that they don't take these technologies very seriously:https://twitter.com/stroughtonsmith/status/15294383578346332...
The worst part of the dev experience is that we are currently supporting back to iOS 13 (which is when SwiftUI was introduced). That means we can only really use the oldest SwiftUI components and modifiers; it's not too bad, but finding usable examples online is tricky sometimes (they often assume the latest).
I don’t think I would have attempted a project this large without it. I had to fall back to AppKit/NSViewRepresentable for the tabview, text editor, and a couple other views. There are probably over a hundred SwiftUI views though. And I am hoping I can switch the tabview to SwiftUI after WWDC so it’s easier to extend.
About WWDC, I wonder if we’ll see a CoreAnimation replacement this year that is exposed to SwiftUI views? I don’t know what the implications would be, but it makes sense when you look back at how they’ve refused to offer/expose the underlying UIKit/AppKit APIs that SwiftUI is wrapping for some controls.
It was in pretty bad shape when I got my hands on it. Last update: February 2020. Targeting iOS 11+, mostly UIKit, powered by Cocoapods with 25 dependencies, and 1.3M LOC.
It took me 3 months to rewrite everything from scratch in SwiftUI, with 100% feature parity. Of the ~20 different view/components that I had to write, just one required me to dip into UIKit (with UIViewRepresentable to bridge).
Now the app is iOS 14+, 5 dependencies (all managed with Swift Package Manager) and 6.5K LOC, with 0 crashes in the last month.
SwiftUI is production ready.
Customer value was that the OG app was crashing like 1 in every 6 uses. Updated app was crash free. Plus, added two new features during the rewrite.
My project utilizes Firebase as the backend and as soon as you add that dependency - SwiftUI previews never compile, due to build time outs.
My app also uses firebase and SwiftUI with hundreds of files (views, view models, and more) with no problems.
Got working SwiftUI previews on a 50-100k LOC project with many big libs as dependencies, must be hundreds of files but havent counted. SwiftUI code is gaining share of the total UI code, probably around 20-30% now
Mock data is a must.
Need to be mindful of the preview build (+ preview simulator startup) time too, sometimes it will timeout but just building again (now warmer) will make it work
Had some initial issues around processor arch (Intel vs M1/arm), think I’m still running XCode under rosetta otherwise it wouldnt work.
it will be lightning fast compared to large xcode project... and it might even be better architecturally too, since you'd have to factor out lower level logic (view models or whatever) anyways
Not JetPack or SwiftUI works for even a simple view!. Is incredible slow and still not true to how it will show up!
I miss the way Delphi do it...
For cases where portability or development time is valued more than having perfect Apple-HIG-compliant UI polish, there are lots of better options. Since Apple has flattened their Aqua interface out of existence down to mostly just gray text labels, even Electron apps started looking good-enough.
Could you give some examples? Most people I talked to really hate React Native, for example. Ionic doesn't seem to have gained enough momentum. You mention Electron, but the last time I checked it's only for the desktop, not mobile. Each year new options appear, but I'm not sure they are that great.
The types of companies that hire iOS developers and build iOS apps also hire android developers and build android apps, again, IME.
Objective-C compiles much faster. Fewer compiler errors. Fewer compiler crashes. Older projects still compile. The debugger is much more reliable. The entire Objective-C toolchain is more solid, because it's older, mature, and changes less.
Also, easier compatibility with cross-platform C and C++ source.
I don't work in the iOS/macOS dev field anymore, but I've tried learning Swift in a similar fashion over weekends, to no avail. Incidentally, do you have any recommendations for learning Swift for someone coming from a C/ modern C++ background?
[1]: https://developer.apple.com/library/archive/documentation/Co... [2]: https://developer.apple.com/documentation/objectivec/objecti...
For disciplined developers who always dot their I’s and cross their T’s, it feels easier because they can write code with full “trust” from the compiler that the developer knows what they’re doing.
For undisciplined developers, it can feel easier because the compiler isn’t calling them out on code smells and inattentiveness to nullability and types.
I’d like to think I’m somewhere in the middle (as I suspect most devs are) and for me Swift feels easier in most respects, even with its everything-and-the-kitchen-sink nature compared to Objective-C’s more spartan approach.
Instead, SwiftUI adopted a whole new set of primitives that doesn’t mix. Accessing the underlying UIView is discouraged, and wrapping up UIKit in SwiftUI feels like a legacy feature. IMO SwiftUI should have been a thin wrapper on UIKit.
The whole programming experience of declarative UIs is predicated on the fact that you’re manipulating lightweight structs (really just state representations) that are rendered into heavyweight views by the system only where necessary (determined by diffing the state changes).
React’s refs are an attempted answer to this very problem, and they get nasty fast.
Yes, and I’m arguing that not exposing the ‘heavyweight views’ to the programmers at all is a mistake.
Edit: once again I think it’s important to look at the limitations and advantages of prior work in this area and I believe React refs to be a good case study in that.
“Hey I got 90% of what I wanted really quick! Neat!” “…oh turns out that last 10% is basically impossible, eh?”
This seems to be the story of apple in general. Very beautiful and easy to use as long as you stay on the path and don’t go too far along lest you discover the 2nd mile is still under construction.
A couple of reasons:
1) The documentation for SwiftUI, when I started (about two years ago) was awful. I was shocked at how bad it was. I believe that it has since improved.
2) I knew of no major apps (even Apple ones) that had been done with it.
I already knew that UIKit was up to the task, and held my nose, while I set things up. It's working out extremely well, but (of course) I'd like to rewrite the whole thing (a sure sign that I'm approaching ship).
I like things like the MVVM pattern, but it's been my experience that it's really not such a good idea to implement it in UIKit, because UIKit was designed explicitly for MVC. I have learned that those ugly-ass UIViewControllers are really important, and I circumvent them at my peril.
I'm able to release fairly basic Apple apps in UIKit, in just hours, so speed of development isn't compelling.
What is compelling, is the ability to design a reactive system for a complex app (like the one I'm writing now). AppKit has allowed this for some time, and it's possible to force UIKit to do it (but it isn't really designed for that).
I really wish that SwiftUI had been a bit more mature, when I started this system, but I would have also needed to rewrite the two server SDKs I use, anyway. It wouldn't have worked, no matter how hard I bang my heels together.
But I'm looking forward to it.
One thing that I've learned, is that it's really OK to wait for things to mature. Companies always screech about how we need to jump on the bandwagon, but that's all hype. I have taken OpenDoc courses at Apple DU. I also busted my ass, getting my app ready for Copland. I have scars from Apple hype.
I did take a big chance, by jumping directly into Swift, but that has turned out to be a good decision.
I think it has massive potential regardless, but yes it’s going to need some time to fully bake (much as UIKit did).
It’s too bad that Cocoa Bindings never found their way from AppKit into UIKit. I understand their exclusion was likely due to CPU power limitations early on, but that hasn’t been a problem for many years at this point.
I worked on one large iOS codebase that went all in on the VIPER architecture and it was one of the most unweildy and baroque codebases I've ever had the misfortune to work in.
< Takes out a foil blanket. Hands you a flask. >
https://github.com/uber/RIBs
The other half of the equation is: don't override Back behavior unless you "own" the current task (it's rooted at one of your activities). When handling "Up" navigation and deep-links, you want Back to behave like "Up" and go to the logical parent of the current screen. When being launched in someone else's task, "Up" should launch a new task at the logical parent and "Back" should perform the default behavior (usually, Activity.finish()).
That's a great little turn-of-phrase that I plan on stealing in the future. Apple's APIs will absolutely reward you for taking the time to step back, figure out how Apple wants you to use them, and try your hardest to use them in that way.
An example from the olden days of iOS development: many of the apps I worked on went out of their way to avoid subclassing UIView, filling their view controllers with layout and interface updates that would have made much more sense in a view. If only they had read all the docs for UIView would they know that doing something like subclassing a button and tweaking a few methods would have done exactly what they wanted with a minimal amount of work.
I've seen all the horrors, and i can now safely claim that all the problems i've seen on iOS development come from not designing the model layer properly in their MVC app. Because most developers start by coding UIs and later end up wondering where to put that business logic and make it reusable.
And now every time i see another pattern that claim to facilitate refreshing the UI upon model change ( and vice versa), i know it's going to be a failure.
Its not much better today overall, but is usually not an issue within companies themselves.
Probably not ‘major’ as in ‘complex’, but I believed the Apple Pay sheet is now Swift UI
But the app I'm writing is a good deal more complex than most of the utility apps, and I seriously doubt that the complex apps are SwiftUI. I would not be surprised if many of them are still ObjC.
I agree with everything you've said but this. I've worked on 3 very large app, one which is 85% using mvvm, the two others were still in experimentation phases with it and I am not sure where they've ended up. It's been a joy. The app is designed in a very reactive way and the data flow paths are very clearly defined and easy to follow.
Don't get me wrong the other two apps were heavily MVC with a lot of delegation and that was fine. I could easily switch back to an architecture like that but it's very possible and quite easy to switch over to an mvvm pattern.
It may be because I want a "pure" MVVM, and it has to be sort of "impure" to work with UIKit apps. In that case, it just adds more code. I'm a "the best code I write, is the code I don't write" kind of guy.
I dont understand this. MVVM is an extremely abstract pattern. It transcends the technology stack. How it is implemented on the platform differs, and yes you are not going to avoid the UIViewController when doing it on iOS. But you are still doing MVVM even if your V is actually a UIViewController.
I use MVVM almost exclusively now, and I usually do it in a cross-platform framework (Xamarin/MAUI). The codebase is portable across both iOS and Android with no re-architecting of the high-level architecture pattern.
The UIViewController must be present in a UIKit app. Most classic UIKit apps have the lions' share of code in UIViewControllers.
It's entirely possible to basically use a "skeletal" one, and have the main code in the linkages between the Model and the View, but that makes the Storyboard Editor useless.
I use the Storyboard Editor a lot. It is not my favorite editor, but it allows me to work incredibly quickly, and to make a really reflowable UI.
I know that the app I'm working on now, is larger than any I've seen from SwiftUI (around 40 screens, and communicating with three servers in realtime, using a couple of SDKs). I am able to make it all work.
I feel as if MVVM would make the parts of the app that link the UI to the servers a lot more graceful (it's a nasty state engine, right now -ick). I feel as if this kind of app is the kind of thing they had in mind, with SwiftUI.
I do know that it's really important to derive subclasses, and extend ObjC classes, when using UIKit/AppKit/WatchKit, and I feel sorry for folks that avoid inheritance like the plague. It must be a fair bit of work. Looks like SwiftUI doesn't really need that at all, but I haven't spent enough time with it, yet, to know for sure.
I have no doubt that I'll end up mastering it. I'm a quick study. I've spent 35 years, surfing the tech wave.
I dont think you understand the point I'm making. Just because Apple has created a framework that has something called UIViewController which has child UIViews doesnt matter when using a pattern called MVVM. The V is just the _visual_ representation of the pattern. It could be a terminal console if you want, it doesn't have to be the "underlying" view of the platform! Don't fight the platform to align its idea of the view with a specific thing called a View in the pattern.
EDIT: and yes IB is an issue if you want to be programmatic. I do all my views in code.
It’s just Apples and oranges.
I write in Swift, as a native developer of Apple software. I won’t go into all the reasons I do what I do (actually, I’ve covered a lot, in this thread). I have my reasons, and there’s nothing wrong with my approach. I get a lot done, very quickly, and at a fairly high Quality level.
Life is a compromise. We always need to make trade-offs.
That's kinda like my story. Covid started and I wanted to learn something new so I started with Swift/SwiftUI. 2 years later I've been doing tons of crazy custom stuff in my portfolio tracker app https://stocketa.com (not launched yet) - I kept a thread with my progress since the first day I started my journey: https://twitter.com/Stammy/status/1527288954935922688 (scroll up).
This was last june but I wrote about my experience with SwiftUI at the time: https://paulstamatiou.com/getting-started-with-swiftui/
How can one properly evaluate it with no point of comparison?
If you've never tasted chocolate, then vanilla might seem like the greatest flavor ever.
UIStackView
> I was having fun making real layouts my first hour in
Good. Now take a pixel-perfect mockup of a new screen from your designer at work and implement that.
I'm also a designer and have built many detailed screens with custom components/interactions in SwiftUI.
I work for mid size company with a fairly big app with millions of users and we did a complete re-write of the app in SwiftUI and I can say with confidence that once a SwiftUI view layer is built out, building features on top of that is incredibly fast compared to UIKit.
It is. It's also far more flexible in return.
But the point is that if someone has to ask this question then they don't have enough experience with UIKit to be comparing SwiftUI and UIKit.
https://github.com/hmlongco/Builder
I have a similar experience (started working from scratch on an iPhone app back in January with SwiftUI). Live preview is really awful. I had to basically disable it throughout my project. It'll crash for no reason and require a manual click on a button to reload, errors it spits out tend to be unintelligible, etc. I definitely wouldn't use live preview as an example of SwiftUI being advanced and not being daunting to use.
Your app looks sharp though I like it.
The jury is still out on Swift itself.
That said, I find myself dipping down into AppKit and UIKit quite often. Any kind of complex views or UI interactions outside the happy path, just grab that UIViewRepresentable.
SwiftUI was really promising at first, and even fun to use (nothing like ripping out entire UI files or pages of code). Yet, issues were almost immediately apparent.
A major concern is that it seems to take Apple a really long time to address even basic issues, e.g. years go by and things still broken since day 1 are there, while other things are randomly introduced. And of course, “Feedbacks” have the usual dice-roll effect: will you even get a response, much less see any indication that the reported bug will ever be fixed? (Or will Apple just wait 2 years, close your bug as “probably fixed in this OS update, please confirm”, and repeat the whole thing?)
And the thing is, this is not hard to believe. If you auto-complete in SwiftUI (what else can you do, there is rarely good documentation?), some of the APIs are truly scary: levels of complexity and variation that really make me wonder if they can truly test, much less support, every variation of every API. I would strongly argue that some things just have way too many options instead of a handful of clear starting points.
SwiftUI also occasionally changes behaviors (e.g. subtle or gross layout differences). Worse, it is easy for Apple to not call any of these changes “breaking” because apparently you are just supposed to let SwiftUI figure out what is needed in any situation. Except that kind of “trust us, we’ll come up with something” approach is not great for writing stable production software.
The auto-generated hierarchies can do truly weird things. For example I realized at one point that an “auto-saved” window layout auto-generated preference names based not on a simple string but the entire SwiftUI view hierarchy, which was huge and indecipherable and of course would become a different value if any part of the window or view hierarchy was modified. So I discovered I had dozens of preference settings scattered throughout my defaults, 99% of which were completely obsolete because they were based on previous incarnations of the view I was developing, and they all had names that were almost impossible to type (so how do I delete them while preserving the rest?). What do you even do with that?
Yet another major concern is that SwiftUI is very dependent on Combine which is not necessarily the future given other developments in the Swift language. So what if they just decide to, say, deprecate Combine and move further toward actors and async APIs? How much of SwiftUI might just fundamentally change in, say, WWDC this year, completely invalidating years of effort people have put into it?
If you’re talking about Combine vs async/await, I think they’ll continue to coexist because they fill different niches. In the UIKit app I’m responsible for I use both — async/await for things like network calls and Combine for keeping UI state in sync with data.
Combine is an abstraction to encapsulate changes in state over time, while actors and async APIs are abstractions to encapsulate concurrent behavior. I think these are orthogonal concerns, so they wouldn't likely drop one in favor of the other.
> SwiftUI is very dependent on Combine
As someone who's been writing SwiftUI a lot over the last year or two, I've only touched Combine a few times. Even then, I only tried it because I wanted to see how it compares to RxSwift, not because it was something I needed.
The conclusion was that Apple made a huge mistake tying it the iOS version and effectively limiting updates and it's real world use for years at a time.
Both leads liked the design paradigms, but we are only going to use Jetpack Compose since it's made of multiple libraries that are all backwards compatible with our minimum supported version. iOS will stick to UIKit since it works and is backwards compatible
I was also baffled to find that TestFlight can't be installed on pre-Monterey Macs. I mean... WTF? That makes no sense. Sure, we can pass DMGs around, but my company is new to Macs and standardizing our QA team on TestFlight on all devices would've been simple.
Exactly this. SwiftUI on iOS 13.x is practically unusable for anything above simple implementations, with some fairly major bugs that weren't fixed until iOS 14-15. Bugs aside, the lack of StateObject in SwiftUI (iOS) 13.x makes it a non-starter.
I genuinely cannot think of a single thing that SwiftUI does better than Jetpack Compose.
There are a lot of fundamental design decisions in SwiftUI that are questionable, like their reliance on two-way binding (which makes non-trivial event handling very difficult to implement), or having Views be structures rather than functions (which then necessitated special ForEach views, because you can't use regular control flow mechanisms).
I agree with many of the negative comments in the article and Apple should get busy resolving issues.
That said, I really like the idea of Swift and SwiftUI and especially Apple’s awesome deep learning support in apps.
One example I had was trying to put an ObservableObject into UserDefaults for persistent storage. There’s not really a nice way to do this. SwiftUI only knows how to store basic scalar values in UserDefaults. That kind of makes sense, because UserDefaults is only meant for small amounts of data, but what if I want to save a struct that has two fields? Trying to do this in SwiftUI is actually quite painful and that is a very simple example. Another pain point is app navigation which basically does not work properly at all.
Though one very nice thing is that it’s quite easy to use a SwiftUI view from UIKit
Overall though, somehow a far worse experience than using something like React
Shameless plug -> I recently open-sourced an app showcasing how to use effectively use SwiftUI + MVVM: https://github.com/maxhumber/BreadBuddy