SwiftUI in 2022
mjtsai.com
mjtsai.com
A few startups ago we built our app using SwiftUI 1.0. At that time, while 90% of it was fantastic, 10% was either unworkable or extremely unreliable, causing for some maddening bugs. The documentation was laughable so for these reasons I chose to do the app for a subsequent startup in UIKit.
Fast forward to my most recent company; decided to give SwiftUI another shot (targeting iOS 14 & SwiftUI 2). I am 100% glad we did. It’s been pretty incredible; we’ve built a reasonably complex banking app at a pace not possible with UIKit. The animations in particular are crazy good to work with; we’ve got some very complex animated flows that would have taken weeks and thousands of lines with UIKit… with SwiftUI it was about 5 days.
It’s definitely not without its downsides; documentation is still slim at best, but there’s plenty of blogs and resources (https://swiftui-lab.com/ is the most helpful IMO) available now. There are also still some maddening bugs that appear in production and take a day or two of head scratching only to discover it’s a bug in the framework (most recently; using #available causes code to crash on the platform it’s protecting against lol), but there are always workarounds. Still, time wasted on these has been vastly outweighed by the weeks / months of time saved.
Finally, you can always use UIKit as an escape hatch through UIViewRepresentable.
iOS 15 is at 85% adoption, so we plan to drop support for 14 somewhat soon, which will give us an even more robust framework as well as async await APIs. Not feasible for most companies I know, but even supporting 14+ Will be pretty reasonable when iOS 16 drops in September.
I also recently did some work with Vapor on the server side. Night and day difference there. The old Vapor EventLoop stuff was doable, if you squinted just right and concentrated really hard. The async/await version is as delightful as anything else I've ever used. Nearly as easy as writing Python.
Again, just guessing, but I would imagine that it’s managing that state and animating it in a sane way which requires LOTS of code, less so the animations themselves.
(shameless plug; check us out at https://www.withapollo.com we're YCS21, just launched last week, and are hiring an iOS engineer!)
[Edit]: Thank you kind stranger.
Animations are so often an ill-advised, interaction-slowing pain in the ass for users that I'm curious about beneficial and non-annoying use cases.
I think it depends on what the goal of the screen is. If the goal is to simple provide information to the user, it makes sense to have clean, simple, and snappy animations.
However, I think there are also situations where the experience itself is the goal. i.e. give the user a visually pleasing graphic, animation, interaction, etc. In this case going a little wild with animations can be a good thing.
Most in app situations should be the first (snappy, clean, useful). But selectively sprinkling a few instances of the second throughout your app can bring the experience to the next level.
In our case, we wanted the rewards flow (it's a banking/brokerage app) to be a fun, gamified experience to separate us from typical banks. So we opted to add a very visual, interactive experience in this single part of the app. There's a demo video above. While it's certainly extra, I think it makes the core flow of the app a unique experience.
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.
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.
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. >
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.
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.
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.
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.
I've been working on an app that's mostly SwiftUI for about a year now. It feels magical when it works, but I don't think I've saved time vs. using UIKit at this point due to all of the workarounds that I've needed to find.
Particularly, SwiftUI List views are still loosely supported, and in some cases broken. Unfortunately for devs, lists are the cornerstone of many apps.
For example, it's very difficult to get the content offset of list. You cannot put multiple buttons in a list row without breaking their tap targets. You can't change the background color of a grouped list without changing it globally (and it's very difficult to customize many SwiftUI components, like the navigation bar). It's difficult to control the spacing between sections in grouped lists. I could go on.
Developers are stuck in a hard place right now. If you're starting an iOS app today, do you go with UIKit (and accept that your code will soon be considered legacy by Apple and many engineers?) Or do you go with SwiftUI, and accept that many things will be broken or impossible to make right?
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.
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).
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.
To give you an example, it's quite easy to add the swipe to delete function (within a list) just adding .onDelete() but if you want to add swipe to delete to a LazyVStack (similar to a List) you need to implement the gesture detection and a few more things [0].
From my POV, SwiftUI IS the future, declarative UIs are awesome, I'm confident that Apple will reach a point where all the quirkiness are mostly gone.
0: https://stackoverflow.com/questions/67585037/swiftui-ondelet...
I've not tried SwiftUI yet because my app needs to work on older devices than this allows, but it's also a solution for a problem I don't really have. It can't be as bad as AutoLayout at least.
Non-Apple programmers are probably shocked to learn that to this day there's still no graceful way to scale an Apple UI up. You can't just set "scale symmetrically" on a view. It comes down to positioning things with multiplication factors and literally trying and retrying those decimal numbers on every goddamned control/label combo. Over and over and over...
Then we needed to build a cross-platform desktop app, and went with Qt and QML. I expected to dislike QML, but no; it's really nice to work with, and our app looks great. QML has been around for years, so it's disappointing that SwiftUI has turned out to be such an apparent fiasco.
Shameless plug -> I recently open-sourced an app showcasing how to use effectively use SwiftUI + MVVM: https://github.com/maxhumber/BreadBuddy
I have been writing ObjC, Swift for 7 good years. Me or my team will never write anything important in SwiftUI until Apple starts to adopt it non trivially. Blogs, Twitter threads != production code. Teams hate workaround driven development.
I started developing with UIKit for a year, hated it, then switched to SwiftUI and have built multiple apps over the past few years. IMO the "last 10%" bugs are not that big of a detractor compared to the benefits. Of course some of this is my bias; I'm more likely to spend time trying Stack Overflow hacks on SwiftUI bugs when the UIKit solution is better. I have to "work with the grain" sometimes if something just isn't possible in SwiftUI, but I'm fine making that tradeoff. I feel lucky not having the bias of years of UIKit, it's hard to let go of something when you're so used to it. I'm also lucky to not be working on apps with backwards compatibility issues, but I do think SwiftUI is the way to go for new consumer startups.
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...
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.
> Combine is an abstraction to encapsulate changes in state over time
so is https://github.com/apple/swift-async-algorithmsNot talking about award winning, unique apps that may require more device specific capabilities, rather the 90% of apps out there that just want to offer users an easier way to CRUD into a database.
Inevitably, while developing a UI, I find it necessary to investigate some part of the framework implementation. This is impossible with a closed source framework. Indeed, many of the complaints that appear on this site seem like exactly the sort of mysterious behavior one faces and might be resolved with access to the source.
SwiftUI is closed source, correct? I made an effort to discover the source and it doesn't appear to be available.
For CRUD stuff we do regular Web applications, naturally with the necessary optimizations for mobile Web, in the process you can also make use of PWA features for mobile devices.
Try it out on your device, https://whatwebcando.today/
It was ~2mo before they even had to learn what a retain cycle was, and that was from using UIKit.
Of course you still eventually see this if / when you use `@ObservedObjects` and their implementation, but in our case we were also using https://github.com/pointfreeco/swift-composable-architecture which hides this away as well.
Seems fine to me for building apps but I don't really know enough.
There was definitely a lot of time spent looking why basic things are not working as expected. There are many counterintuitive things to it, I think, and some bugs.
But overall, as a newbie to iOS development, it was a fairly nice experience. I am skeptical I could've iterated/developed something complete (despite the issues) as fast with UIKit.
I only wish they made it open source. It feels like it would really benefit from being run more like the open source Swift frameworks, rather than this opaque update-once-a-year thing.
a square, screen width, 10x padding, red background.
inside it, a little square, centered and a little square, top left corner, 10px padding, blue background for both.
Tell me that was easy, so that I know you're lying :)
Change frame (screen width) to 300, 500 to see why.
Now tell me, why did it break? Do you even know? Because I don't.
I don't know why half the shit works as it does, and I've written non-trivial SwiftUI code for 6 months. I did not have this problem with UIKit and interface builder.
Saying "you can't use GeometryReader" would be like saying you can't use UIKit's Auto Layout...
struct ContentView: View {
var body: some View {
ZStack {
Rectangle()
.fill(Color.red)
Rectangle()
.fill(Color.blue)
.frame(width: 100, height: 100)
HStack {
VStack {
Rectangle()
.fill(Color.blue)
.frame(width: 100, height: 100)
Spacer()
}
Spacer()
}
.padding(10)
}
.aspectRatio(1, contentMode: .fit)
.padding(10)
}
}The larger point being - placing squares on a page went from drag and dropping and setting a few constraints, to now doing zstack/hstack/vstack/spacer wizardry.
i wonder how one could go about implementing custom layout in swiftui, something like `layoutSubViews` so we could implement something simplified like:
View(layout: .grid) { ... }
or View(layout: .stack(.vertical)) { ... }Very few iOS developers I know did "drag and drop"/IB development, layouts are typically done in code even in UIKit.
The zstack/hstack/vstack bits don't seem wizardy at all if you're used to looking at layouts in code.
struct ContentView: View {
var body: some View {
ZStack {
Color.red
Color.blue
.frame(width: 50, height: 50)
.padding(10)
Color.blue
.frame(width: 50, height: 50)
.position(x: 50/2, y: 50/2)
.padding(10)
}
.aspectRatio(1, contentMode: .fit)
.padding(10)
}
}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.
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.
On recent versions of iOS it's capable of doing 99% of the stuff I'll ever want to do and it will look nice. Just as long as I don't want to step too far outside of what Apple thinks is the right way (tm).
macOS - on the other hand - is far more more buggy/inconsistent e.g. Focus with List's of TextFields. It is also missing a lot pretty basic macOS functionallity e.g. no way to implement drag 'n' drop in Finder'eque recursive outline views, open tabs or windows - in fact window management and routing is just not much fun.
So for iOS I'd not hesitate. It's good, better than React Native and getting better. It does't really feel like a half baked abstraction layer over the top of UIKit.
For macOS on the other hand; it's much less clear. It's missing so much. And then there is the Catalyst auto-translate iOS app's stuff, which is kind of a worry that the grand plan is the moment it's feasible to dump it on macOS, it'll be dumped. So still not sure I'd use it for anything sizeable. Hopefully though will have a clearer picture of Apple's intents for the platform after the next WWDC.
For anyone wondering: "cross-plaftorm" means Apple platforms, not real multiplatform like Flutter.
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
We're dropping into UIKit land quite frequently but for the user of the API, that remains implementation detail and while likely change as SwiftUI advances.
Ironically, a "Stock iOS" style app like Mail or Contacts is much harder to pull off with SwiftUI than an app like AirBnB that brings has its own design aesthetic and establishes its own conventions – cooperating closely with your designers and keeping them aware of what's easy/hard is a much better use of your time than trying to rewrite a pixel perfect `UISearchController` clone.
That said, navigation remains a complete mess and I hope that's a top priority for iOS 16.
[1]: You might find this relevant to your interest if you write SwiftUI for a living: https://movingparts.io/variadic-views-in-swiftui
App demo: https://www.notion.so/ale0sx/Miurror-Demo-62eaeed2679d4756a0...
> “Hey I got 90% of what I wanted really quick! Neat!” “…oh turns out that last 10% is basically impossible, eh?”
(Not impossible, but it's like transitioning from a pleasant stroll on a comfortable downhill trail to slogging through mud, and dense brush, with mosquitos and biting flys everywhere.)
“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.
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.
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:
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.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...
At thid point, unless you really need to reach the absolute top of UX, there is no reason not to go for react native, or flutter.
Knowing that videogames are already developped in cross platform tools, it only leave a very very small market IMHO.
I had hopes that swiftui would be cross-platform ( or at least ios + web, since apple don't want to facilitate android adoption), but i don't think it's going to happen now..
Worked perfect for me, besides issues around navigation, especially showing alerts. Would use SwiftUI screens using UIKit navigation next time.
Also more complex scenarios that sing combine can get a bit more hairy. The most important issue is that all changes are emitted at didSet so the new value is not known anywhere outside of the closure.
Jetpack Compose performance is a pain versus traditional Android views, hence some performance related talks at Google IO 2022.
The UWP, WinUI 2.0, WinUI 3.0 mess, that makes it more fun to keep using Forms/WPF/MFC than adopt them.
Makes one wonder where are those teams coming from, with what resources are they dealing with, that in the end we get such quality.
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.
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.
The good:
* Making all the graphs (they're drawn by hand!) was very nice and easy. The speed at which I could iterate with them was incredible, and I could just move code around and lay things out in a way that AppKit (or UIKit) would not allow, at all.
* I could keep the code very clean, with each component being very specific and isolated. Plumbing bindings through made things very natural and I can imagine taking the code I made there and just plopping it into another project as-is.
* The result is actually kind of nice, IMO? There's a lot of focus on whether SwiftUI works and stuff but not much focuses on what the end result is. I had an app in my mind that I wanted to make, and it was mostly possible to make it in SwiftUI. In some places I was pleasantly surprised that things I would have been hesitant to try before (slider in a toolbar!) "just worked".
The middling:
* I initially supported macOS 12.0 only. Someone asked me to backdeploy to 11.0, which was a little painful mostly because Material didn't exist back then and neither did support for initializing a color from a NSColor. I did kind of a lazy stab at it and the end result being fairly simple, but took about an hour to write: https://github.com/saagarjha/EffectivePower/blob/main/Effect.... If I had to support 10.15 I think I would honestly rewrite large parts of the app in AppKit, maybe keeping just the graphs as view representables.
* My data model has tens of thousands of elements. Ensuring the "reactivity" didn't cause a bunch of things to be recalculated when they shouldn't was a bit of a challenge. The place I have it now is very nice (I have them defined in such a way that they will never update unless they need a redraw) but this definitely does not come "for free", you'll find out about it after profiling and need to figure out how to fix it.
* I wrote simple versions of things that don't seem to exist in SwiftUI but AppKit provides for free, such as magnification bouncing. It was like three lines of code to get something that seems reasonable, but with SwiftUI I'm never sure if this is a "we just didn't add it yet" thing or a "oh this is so simple in the framework that you should just write it yourself".
The bad:
* Things are broken and I don't know why. If you use magnification gestures the callbacks stop getting called. No indication why. I have some commented out code that would've used a table in the sidebar, but I had to use a List instead because it seems like SwiftUI does not properly update the table and it crashes with an assertion.
* Documentation sucks but that's nothing new. There's a lot of things that work but you need to be clever at arriving to getting to that point. It's a fun challenge for a toy project but for a production thing I can see this being super frustrating.
* If you mismatch a type somewhere the compiler is just going to time out rather than telling you what is wrong. Thankfully you can just go through and comment out large parts of the app to reduce the scope of where the error is coming from, but the fact that this is necessary is kind of annoying.
Absolute no-brainer if you ask me. Set it and forget it. Use the cool stuff when it works, let others beta test.
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.
SwiftUI is the best UI/app framework on the market, nothing come close to it
Fun fact, Miguel de Icaza (gnome/mono/MS) fell in love with it
https://twitter.com/migueldeicaza/status/1372551091905236999
Supporting iOS 13 with a SwiftUI app (a reasonable thing most customers will want) is essentially impossible to do without game breaking bugs between different point releases. It's really bad.
The jury is still out on Swift itself.