SwiftUI for Mac 2024
troz.net
troz.net
The pattern it enforces is theoretically great, but you will get much more mileage out of learning to write in a "reactive" style manually (When state changes, update view to match. It doesn't need to literally be a function of state to make it a function of state. E.g. don't leave ifs without elses.)
A perfect combination would be a SwiftUI-style UI editor (sans bugs) to define UI, constraints included, but traditional layout management at runtime. Well, that or a ground-up redesign of SwiftUI's API.
I wrote a couple of small sized apps trying to use only SwiftUI “the right way” to learn the framework and as you say whenever I wanted to do something specific with a lot of control I’d hit a wall with SwiftUI and have to go crazy with wild work arounds and trial-error throw spaghetti at the wall or just give up.
Now I’m writing another app and making heavy use of NSViewRepresentable use AppKit from SwiftUI, and NSHostingView to embed SwiftUI in AppKit views. I’m using mostly SeiftUI at the “leafs” of the view hierarchy, and AppKit towards the root; all my windows use a NSWindow subclass and/or a view controller.
Much happier with this!
Having tried to make a NavigationSplitView with multiple lists in the sidebar, I can fully agree with this sentiment.
Sadly, this has been my experience. I built a moderately complex app, only to bump into more and more problems, and I find myself fighting the framework, building hacks, and implementing workarounds. When you venture into more advanced UIs, the leaky abstraction comes back to haunt you.
In those frameworks (particularly Flutter, which generally has less ceremony), I have found simple UIs easy, and complex UIs slightly harder to build, but then they're much more predictable (fewer surprising edge case bugs) and much much more maintainable.
Two-way data binding makes for shorter demos, but it doesn't scale nearly as well as one-way data binding. I've found in SwiftUI the way state gets updated across components becomes very messy very quickly.
Jetpack Compose is definitely inspired by React, hooks and all. I much prefer working with Jetpack Compose for this reason.
I used to work on an app where we used the UI builder at the time (I forgot the name) at first, but my colleague asserted that building the UI in code resulted in a faster app, because (according to him) parsing and rendering the XML output took longer than interpreting the code. I don't know if he was right, but a while later Apple introduced devices with different sizes (iirc the iphone 5 which was a little taller and the ipad) and doing all the layouting became impossible.
Anyway when I rejoined later it was a (I believe) healthy mix of the UI builder tool and custom code for some graphic / coded elements (think a fancy progress indicator). I suspect it'll be the same for SwiftUI.
I wouldn't say that. I've worked for a couple of marquee corporations that did a lot of work with Apple.
They do things like assign direct contacts to larger corps. They don't really rely on their "popular" culture docs to support bigger companies.
It's pretty natural to use their popular front as an "onboarding" system for smaller acts, with the plan to integrate them more tightly, if they get successful enough.
That said, their App Store is quite restrictive, and can be a big fat pain to deal with; even as a bigger corporation.
Quite doable, though. I've released over 20 apps to the iOS/Mac App stores, over the last dozen years.
Source? I haven't heard of any large company with complex projects fully adopting SwiftUI in their main product and not immediately regretting it. Successful adoption seems to be achieved only if the product is really simple or when using it in a very specific / isolated place of their main product (also simple). Everything else is UIKit because SwiftUI sucks at complicated logic.
I have experience with various iterations of UIKit’s auto layout, Yoga, as well as CSS and some Swift UI. I’ve found CSS to be considerably easier to work with, particularly when using flexbox and grid.
Outer
+---------------------------------+
| |
| Left Middle Right |
| |
+---------------------------------+
Everything should be vertically centered. Left should stick to the "left" of the outer div, "middle" should be centered, "right" should stick to the right. Left/middle/right can have different widths and heights.In AutoLayout this is achieved by 6 constraints:
- left.left = outer.left
- left.centerY = outer.centerY
- middle.centerX = outer.centerX
- middle.centerY = outer.centerY
- right.right = outer.right
- right.centerY = outer.centerY
I'd like to see how you implement it in CSS. (note: extra wrapper divs are not allowed)
.outer { display: flex; justify-content: space-between; align-items: center; }
…and that’s it. (This is assuming your items are of equal width of course. It gets a little bit more complicated if not.)
So here's how your example would work using it:
.outer { width: 100%; height: 400px; background: aliceblue; anchor-name: --outer; }
.left { width: 100px; height: 100px; background: white; position: absolute; position-anchor: --outer; left: anchor(left); align-self: anchor-center; }
.center { width: 150px; height: 200px; background: pink; position: absolute; position-anchor: --outer; justify-self: anchor-center; align-self: anchor-center; }
.right { width: 160px; height: 150px; background: gray; position: absolute; position-anchor: --outer; right: anchor(right); align-self: anchor-center; }
Source: https://developer.chrome.com/blog/anchor-positioning-api
An interesting thing you can do with grid is align the tracks.
I wrote about this here:
There is also fit-content:
E.g: grid-template-columns: fit-content(150px) …
Tracks is a grid term for rows or columns, as it works in both dimensions.
As you can see, the middle element is not centered.
https://jsfiddle.net/Lah5g3vb/
Changes:
- each col is now 1fr (3 cols, 33% each)
- the child elements align inside the col using `justify-self: start | center | end`
See: https://jsfiddle.net/e0un5Lxk/
The middle content is unnecessarily wrapped into two lines, even though there's plenty of space available.
But this does not keep the center col exactly centered, but it does allow the content to take the free white space and then wrap when needed.
In your original post with Swift, what happens?
I am not familiar with auto layout so I do not know the exact behaviour vs CSS. Do you have a few screen shots of how it would handle different sized content?
Regarding AutoLayout: the six constraints from my original comment, don't say anything about the relationship between the left/middle/right items, so they will simply overlap if there isn't enough space. This can be remedied by adding two extra constraints:
1. left.right < middle.left
2. middle.right < right.left
It's just a bunch of equations. No weird tricks, no special cases, no hacks. You describe what you want with equations, and the solver spits out the solution.
Auto layout does sound neat.
We did have to use some CSS "tricks" (transform for absolute centring), but once you've learnt those then CSS is indeed quite sane.
outer {
flex-direction: row;
justify-content: center;
align-items: center; }
left, right {
position: absolute;
top: 50%;
transform: translateY(-50%); }
left {
left: 0; }
right {
right: 0; }
(This kind of layout, which is common in eg top nav bars, is slightly deceptive.
robin_reala's solution does not conform to requirements that left and right can be different widths, which would cause middle to be not centred under simple justify-content: space-between.)Which underlines the original point, that CSS is a hodgepodge of different ideas with no overarching system behind them. A simple task like this needed 3 different positioning systems:
1. flexbox for positioning the middle item
2. absolute positioning for left/right
3. and the translateY(-50%) trick for vertically positioning the absolute positioned items
In its defence, I suppose recognising this is important, as to make potential box overlaps explicit (which is typically unwanted).
CSS also handles a whole lot of things other than layout, which I'm not well informed of layout constraint systems being able to handle. Being a hodgepodge is an advantage, comparable to how its a great advantage that one can invoke any hodgepodge systems task from bash, as one single tool.
.outer {
display: flex;
justify-content: space-between;
align-items: center;
}
.left {
flex: 1;
display: flex;
justify-content: flex-start;
}
.middle {
flex: 1;
display: flex;
justify-content: center;
}
.right {
flex: 1;
display: flex;
justify-content: flex-end;
}I really like the fundamental ideas of SwiftUI, and want it to work, but have found that it doesn't allow me to write the kinds of apps that I like to release, so I still use UIKit/AppKit for my shipping apps.
The documentation for SwiftUI (and most new Apple SDKs) is awful. It's clear that they are relying almost entirely on inline code docs. They used to have a legendary documentation team.
Inline code docs can actually work quite well (I do it, myself[0]), but it requires serious discipline. If you cloc my codebases, it usually comes up 50/50 between docs and executable.
[0] https://littlegreenviper.com/miscellany/leaving-a-legacy/
What's the best way to learn UIKit/AppKit in 2024?
I like his sense of humor, as well.
There are probably a lot of resources and tutorials out there for learning the UIKit-Swift combination. For AppKit, on the other hand, most of the best resources are "old", which means they were written before Swift was introduced. Thus, if you want to learn AppKit, you probably want to learn Objective-C too.
You can of course write AppKit-Swift code, and many AppKit developers do. However, these AppKit developers learned AppKit-ObjC first and only later switched to Swift. I'm not aware of a lot of AppKit-Swift learning resources.
ObjC: [[FooClass alloc] initWithFoo: foo and bar: bar]
Swift: FooClass(initWithFoo: foo and bar: bar)
Often looks like:
FooClass(foo: foo, and: bar)
These days.Most of the new stuff seems to use SwiftUI, but UIKit has been around since they first opened the SDK, and AppKit has been around longer than that.
Apple likes to pretend everyone uses SwiftUI, but I'll lay odds that most AAA apps are ObjC-based.
And you’ll probably find yourself dropping down to UICollectionView and NSCollectionView for performance. Xcode remains a terrible IDE.
Yup.
I like to have a lot of fairly involved stuff, and SwiftUI falls down hard, when you stray from the beaten path.
That's not unusual, but SwiftUI has no "in-between." You either do it 100% their way, or ... good luck with that.
I really despise Auto Layout, but with IB and UIKit, I can do just about any type of UI I want.
Right now I'm stuck in a situation where any SwiftUI widget except for List has terrible performance but List imposes all these other constraints I can't live with so it looks like once again it's back to UI/NSCollectionView for me.
One of the reasons I've left development for the Apple ecosystem is that these things happen all the time. They are tedious to fix and often require reverse engineering their system.
Bugs in beta software?
It looks a lot like Stockholm syndrome from the outside at least.
But I genuinely don’t understand how or why anyone would pick up native iOS / MacOS development in 2024. It seems like an incredibly shit medium to long term bet.
AppKit/UIKit aren’t afraid to be opinionated either which is occasionally annoying but 90% of the time a good thing, because that makes for tested and supported happy paths that work well. Android Framework is the biggest contrast here, being littered with multiple half-baked ways to do everything, none of which Google has shown any particular preference toward until in just the past few years.
What would get me to move for my personal projects is something with that solidly “batteries included” aspect to it (there’s no excuse for needing to rope in a third party library to get something as mundane as a scrolling sortable table view with headers in a desktop UI framework, that’s like new cars coming without wheels) and similar opinionation, along with support for Swift or compiled Swift-like language.
I was really hoping their version of CoPilot would help with this but, unless this is just beta bugs, it looks like that’s not the case.
I get the distinct impression that Apple will begrudgingly allow me to develop and market a commercial tool, provided I pay them for the privilege, and that they very much hope that someday they will be able to rid themselves of third party developers once and for all.
Gemini on AS is so good and most of the time accurate and adopts to how you name your variables and functions. Xcode 16 on the other hand, what a shitshow.
And yeah, if you let a project lapse on gradle and library updates for any length of time at all be prepared for a fight to get it all brought back up to speed. Swift Package Manager is generally less of a headache.
Some of AS’ “smart” features are also more of a hindrance than a help at times, and don’t even get me started on ProGuard (which has no Apple ecosystem equivalent).