All Episodes

September 24, 2024 • 42 mins

Ben Scheirman of NSScreenCast comes on to talk about migrating apps such as a Nike's Sneakers app from UIKit to SwiftUI and all the little things you don't think about. This is part 1 of a 2 part interview.

Guest

Announcements

Links

Related Episodes

Social Media

Email
leo@brightdigit.com
GitHub - @brightdigit

Twitter
BrightDigit - @brightdigit

Leo - @leogdi

Mark as Played
Transcript

Episode Transcript

Available transcripts are automatically generated. Complete accuracy is not guaranteed.
Leo Dion (host) (00:00):
Hey folks.
As you can here I am slowly settingthis studio up here in my new home.
Before I go off to Jolly Englandto talk about Vapor, I want to
release the first part of theseepisodes I did with Ben Scheirman.
of NSScreencast.
I hope you enjoy this one, and the

(00:21):
second part will becoming out next week.
If you're on Patreon, you can get bothright now as well as a bonus chat I
did about setting this whole studio up.
So I hope you enjoy and havea good rest of your week.
Welcome to anotherepisode of Empower Apps.
I'm your host, Leo Dion.

(00:42):
Today I'm joined with Ben Scheirman.
Ben, thank you so much for coming

Ben Scheirman (guest) (00:47):
Yeah.
Thanks for having me.
It's, it's really good to be here.

Leo Dion (host) (00:50):
Obviously a lot of people know you from
NSScreencast, but I'll let you go
ahead and introduce yourself.

Ben Scheirman (guest) (00:56):
Yeah.
It started NA Screencast in 2012.
Yeah.
So it's been.
You know, 12 years of, ofdoing the screen casting
thing.
And,
I've also done a course on.
Combined Swift.
We can have links to all this stuffin the, in the show notes later.
Yeah.
And that's, you know, I, I have a
couple of

(01:16):
side apps that I've work
on independently.
One of them is sideMirror, which is a Mac app.
I have another one called TonalTherapy, which is for tinnitus.
And that's on the iPhone.
And I am currently working onanother independent app because I'm
a glutton for punishment, and I just
can't, I can't get these ideasoutta my head unless I try

(01:38):
to build them.
But then on top of all that, I, I'malso a lead software engineer at Nike.
So that's my full-time gig.
And so I'm just constantly,you know changing
hats into, into different modes.

Leo Dion (host) (01:50):
Yeah.
Awesome.
What do you do at Nike?
If you mind, what apps do you
work on?

Ben Scheirman (guest) (01:54):
I've worked on the sneakers app, so
it's, it's for all of the sort ofstreet wear and sneaker community,
all of the
The sort of hot drops.
Hot, hot drops.

Leo Dion (host) (02:04):
like everything has a hot drop right now
because we all gotta be

Ben Scheirman (guest) (02:07):
Yeah.

Leo Dion (host) (02:08):
temu for

Ben Scheirman (guest) (02:09):
They literally measure the releases
as in terms of heat level.
So like, there's likean atomic and a high
heat.
And because, because they haveto scale traffic to accommodate
the demand, it's, it's,
You know, not unlike, you know,iPhone, pre-orders or Taylor
Swift tickets or whatever.
I mean,
you
know, in a different scale, butsame ideas where you have a lot,
you have a lot of people whowant the thing at that exact

(02:31):
moment.
And so that actually makes somefun design choices that you
get to make on thebackend and on the client.

Leo Dion (host) (02:37):
That's awesome.
So we're chatting in Chicago.
I wanted, I've been wanting to haveyou on for ages and one of the things
you mentioned is like trying, likeslowly migrating your apps to swift ey.
And that migration is one
of my favorite topics.
It's a little bit boring,but at the end of the day,

(02:58):
there's good majority of whatpeople do in the real world
is

Ben Scheirman (guest) (03:02):
Yeah.
How, how often do youdo file new projects?

Leo Dion (host) (03:04):
right, right.
I did a whole video about migratingfrom a Objective-C because there's still
apps with Objective-C and good lucktrying to hire an Objective-C developer.
Let's just migrate it to Swift andpeople will know what to do with it.
Or there's
just stuff you can't do inObjective-C like Swift UI
for instance, whichwe'll talk about today.
But
yeah, I think it's like a real world

(03:25):
topic that a lot of
people have to deal with is migrating
from UIKit, in this case, theSwift UI or something like that.
When do you think, when isa good point at which you're
like, yeah, this is not worth me
doing another storyboardor another zip or doing
another programmatic layout.

(03:46):
Let's
just migrate this to Swift y.
At what point do you thinkthat decision needs to be made?

Ben Scheirman (guest): Certainly is a nuanced question. (03:51):
undefined
We have, I mean.
I'm gonna say we a lot because Ihave, you know, in my, alongside my
independent apps, I also work on a team.
And so,
you know, I
have to
consider that for, for
my own apps, I'm usually willing to
adopt the newer thing sooner.
I'm willing to
sort of bite the bullet and you know,procrastinate by exploring some new

(04:15):
technology or some new technique.
And it, it, to me, it, it, like,
it, it becomes a way for me to explore
and learn and
flex the muscles and all thatstuff, you know about learning
new technologies and those, thoseI may cover on a, in a screen
caster, of course.
But when you're in acompany and you're on a team
and you're shipping a product someof the things are sort of low risk

(04:36):
changes and some of the things are
high risk changes.
So like a setting
screen is pretty low risk.
There, it's something that'snot core to the app flow.
A user may only go to
it once ever.
And it's also pretty easy to build.
So it's like that's an easy
win.
You could just rewrite it in the time it
takes probably to update a storyboardor update a view controller
and add auto layout constraintsand, and things like that.

(04:58):
Where things become a little bit morechallenging or when they are in the
core flow of your app, or if certain
experiences are a must haveand those may be challenging
or missing in swift ey.
And so for those I thinkyou need to, you know, take
a more cautioned approach.
But I think that, you know,nobody's going to, going to just
let you stand still for six monthswhile you rewrite the whole app.

(05:21):
And so the approach is generallygonna be sort of rewrite
little pieces as needed.
If something doesn't need to bechanged you know, don't change it.
But in our case, in a lot of casesI've been on, the cost of new
features just sort of generallygoes up over time because the
code base is harder to work in.
It was never designed to dothe thing you're trying to do.

(05:42):
And so getting that flexibilitymeans you have to be able
to refactor the code.
And refactoring the code that waswritten a decade ago sometimes
is a little challenging.
You know, this code is probablynot written by you, or it's
written by people that areno longer at the company.
And, and so I do mention this with a,with a slight warning that it is sort

(06:02):
of a natural programmer tendency tojust be like, oh, I didn't write this.
I wanna rewrite it.

Leo Dion (host) (06:06):
Yeah.

Ben Scheirman (guest): know, like as your way of (06:07):
undefined
understanding, you rewrite it.
And that's a, you know, that's nota great trait, but there are cases
where I know that if we have writtenthis in the, in, in a way that is more
flexible, that it will adapt to the,the needs we have now and then some.

Leo Dion (host) (06:24):
Yeah.

Ben Scheirman (guest) (06:25):
And so that's kind of the approach we're, you know,
we've taken and slowly but surely,more and more important and riskier,
You know, I say riskier,but like more important
screens are being
migrated.
And so we do that so thatwe can tackle these new
features and not have to dealwith some legacy code that's
been there for 10 plus years.

(06:46):
And and then you risk, you know,breaking something that used to
work and nobody ever understoodwhy, you know, things like that.
And so that's kind of our,our approach has been,
To do that just one piece at a time.
And slowly but surely, likethe lar larger and larger parts
of the app become Swift UI.

Leo Dion (host) (07:03):
One of the things you mentioned in your
notes is the fact that you stillsupport iOS 16 is how does that
affect the migration?
Are you
like, eh, we gotta do this reallydelicately because we still have people
on older phones, or like, how does that
work?

Ben Scheirman (guest): so if we rewind a year, (07:21):
undefined
we were supporting iOS 15 and at thattime we were like, oh, Swift UIs, rough
edges are mostly
sanded over, right?
There was some, therewas some kind of really
rough things in I 13 and 14, but by 15,
I'm trying to think of the
the flag
pole features that they had or,
Was it navigation view?
No.
Navigation view.

(07:42):
Was
there navigation stack orNo, a navigation stack is
16.

Leo Dion (host) (07:46):
Okay.
Okay.

Ben Scheirman (guest): I'm forgetting Anyway, (07:47):
undefined
So there.
Yeah,
so we were like, okay, at 15, let's
start looking at Swift UI.
And this is, so one yearago, so we're, we're building
for Iowa 17, but supporting 15.
And and so then, you know, weimplement a screen and we ended
up running into some problems.
And then Iowa
16 comes out, and then that'sdifferent behavior again,

(08:10):
which is like, okay, this is,
You know, it's not, it's not nicewhen you have like a workaround that
you did for iOS 15, and thenIowa 16 comes out and changes
that behavior and that workaroundeither no longer works or behaves
differently, and so you end up with
sort of this conditional code.
So it is really challengingactually, if you're not going to,
Target the latest versionor even like n minus one.

(08:34):
It, it definitely is challenging.
Like Apple released so manynice things in iOS 18, and I'm
like, I can't use any of them.
So an example of that.
Is pull to refresh
behavior.
So we have a custom pullto refresh in our app.
And this is implemented as asort of taps into the scroll

(08:58):
position of a scroll view.
Any, any scroll view throughout the app.
It does not use the UI refresh controllike API because that I think is too
limited to do what we're trying to do.
Like one of the behaviorsof the system, one is that
if you
keep pulling, eventuallyit'll just start refreshing.

Leo Dion (host) (09:14):
Right,

Ben Scheirman (guest) (09:14):
But, But, we wanted a like sort of a mid state of
like release to refresh, so that way you
can sort of see what the threshold is.
And if you, if you let go after the
threshold, it refreshes if youmove your thumb back up, it
doesn't.
And then on top of that, you've gotlike the progress of that drag so that
you could do all kinds of interestingthings like animate shapes or whatever,

(09:35):
you know, you could get creativewith it, whereas apples is kind of
boring.
It's a, you know, it's just pulled

Leo Dion (host) (09:41):
And you did this all in UIKit, right?

Ben Scheirman (guest) (09:44):
originally, yeah.
And, and you say you, but I
didn't do it.
It was done long, long ago.
Right.
So, like,
you know, again,
nobody on the team now werethere when it was written.
And so, so we're like, okayfirst understand how it
works, can we customize it?
Yada, yada yada.
Then we go to start buildingsomething in Swift UI and we're
like, oh, this screen is really easy.

(10:06):
It's just, it's literally a list ofthings with image And, text, but we
needed that pull to refresh view on it.
And
so trying to get that to work wasreally tricky because we needed access
to the collection view underneath,
or the table view.
And so.
We, you know, looked around a lot.
Intro Spec was theoption that we went with.

(10:28):
And at the time had a, the newer APIis definitely better, but the original
API for Intro Spec, and for those whodon't know, intro Spec is a library that
sort of lets you peek under the coversat what Swift UI is doing and access
some of the hidden UIKit hierarchy.
Underneath it is,
it's a glorious hack, and it'slike kind of a last, last,

(10:50):
It's like your last resort,
And it, I call it theSwift UI Escape Hatch.
And I actually publisheda video on this,
Which is, which is a free, it's afree video on, in a Screencast and
to show how that technique works.
And so what, what happens is youcreate a UIViewRepresentable,

(11:11):
Which is a way of
wrapping UIKit views andtreat them like Swift UI.
So and there's also a viewUIViewControllerRepresentable as well.
So if you add a UI, viewrepresentable as like a background
or an overlay, that's just like
an invisible view.
It gets installed in a viewhierarchy that has access to

(11:34):
super view and parent controllerand stuff in the case of a
controller.
So at some, at that pointyou've like created this
like this little thing thatit gets hooked into this
environment that now you
traverse.
And so what it woulddo is it would walk up
the, walk up the hierarchy until itfinds a known parent and then walk
back down and look at siblings tosee like, oh, is this a scroll view?

(11:57):
Is this a collection view?
Is this a table view?
So

Leo Dion (host) (12:00):
Basically the kind of
stuff that you get if you were to like,look at the UI hierarchy in Xcode,
if you

Ben Scheirman (guest) (12:07):
Yeah, so like, if Apple said, if Apple said hey, we have a
new photo
picker control and controller,
and that thing is aUIKit view controller.
You could look at his view controllers,you could look at his sub views.
Even though those are conconsidered like private API,
you could technically go inthere and fiddle with things.
So the
the thing about Swift UI is ithides all that stuff from you.

(12:28):
So if you need access to the underlyingthe underlying scroll view or,
or table view or collection view.
I say those three separatelybecause it's, that
distinction becomesimportant in a minute.
The, the, at the Swift UIcall site, you would just say
Intro spec on a Swift UI list.
You'd say do introspect, and thenit, and then the closure that you

(12:49):
provide is passed in the scroll view.
And so then you can do what you want.
You can add a delegate or you can addan observer for the content offset.
And so, so it's like, it, itenables you to sort of stitch
these two things together.
Well, so when I was 16 came out,that broke because lists became.
Stopped being implemented by atable view and instead is now

(13:11):
implemented with collection
view.
So then we had to add a,add a separate one for that.
And so this is kind oflike the nature of it.
You're, you're you know, programmingagainst an API that is not public,
that the, it's an implementationdetail that Apple decides.
And one day it may never be basedon a UI ki view controller ever.
You know, they can do whatever theywant under the hood and it's an opaque

(13:31):
API to us.
And so introspective is certainlynot a long-term solution.
I do like the newer API that ithas though, where it codifies the
things that are known based on a OS
version.
So you could say, I want tointrospect this list on iOS
15, and the value you get
is a squirrel view.

(13:51):
But then you can also sayon, I do the same thing, I
wanna introspect it on iOS 16,
the value you get as a collection view.
So it sort of codifies what is known at
that OS version.
And so then when iOS 18 comes along, younow have a build error and you gotta,
you, you have to like figure out whatis the current way of doing that thing.
So it, you, sort of catchit right away as soon as you

(14:13):
start building with the new

Leo Dion (host) (14:15):
That's so interesting because like with Bushel, my VM
app for the Mac I used, I ended upcreating like what do you call it?
A MO view modifier so I can then grabthe NS window and add a delegate to
it
And it's the same
idea.
I would assume they're never going togo away from NSWindow, I would assume,

(14:36):
you know, anytime soon.

Ben Scheirman (guest) (14:38):
That's a pretty, that's a much safer assumption than
some component that happens to beimplemented with collection view.
Right, But, but at somepoint that may break,

Leo Dion (host) (14:45):
right, right.
And I know this year they added a
bunch of window stuff to Swift UI,
so maybe a lot of that can bedeprecated and things like that.
So yeah, that makes total
sense

Ben Scheirman (guest) (14:56):
and it's important to know that, like as you find
these workarounds or these things I dida series on building a Mastodon app for
for the Mac with Gui
Rambo.
And I talked to him about this idea of
like, is it a failing ofswift ey if you have to drop
down to NSViewRepresentableor UIViewRepresentable.

(15:17):
And, and his, his take on that was,
it's necessary.
It's like you're always
gonna have to do
it because Swift UI isstill a young framework.
They're, they haven't
implemented every last thing.
And if you don't want your appsto look and behave exactly like
the mail app on, on iOS, right?
If you want anything custom, any kindof custom non-standard behavior, which

(15:39):
I think the, the industry is moving backtowards that things that look nice and
feel nice, you know, a little bit ofskew amorphism, things like that I think
should be celebrated.
A little bit of surprise and delight.
You know, like I mentionedwith the pull to refresh
indicator, the, the stock one is
super boring.
And I think that you can get creativewith stuff like that and, and,

(16:01):
if, if Apple doesn't provide it, right?
The UI refresh control, sorry, therefresh control modifier in Swift UI
only gives you the default behaviorand you can't customize it at all.
So sort, sort of goingback to that, that example
I.
Of needing to customize that.
We ended up using intro spec as,yeah, this kind of sucks, but

(16:24):
we don't have a better solution.
So we, we went with it and I was15, you know, targeting, I was
15, I was 16, ended up having differentbehaviors, so we had to fix that.
And then now we actually have a realsolution that doesn't require such hacks
but is sort of a new beast on its own.

(16:44):
So I think that I, I mean, I can talkabout this, this idea, it's, it's sort
of specific to what we are trying todo, but but I think that this is kind of
like the, the strategies that you have,if you start using Swift UI, everything
is nice and clean and neat and you know,you can iterate fast and then all of a
sudden it doesn't do the thing you wantand you have no view modifier that can.

(17:08):
Make it do the thing you want.
The, the tool at your disposalis UIViewRepresentable or
UIViewControllerRepresentable to like,okay, I know how to do this in UIKit,
how can I translate that to Swift UI?
So we came up with something, I, I have
a, it's a terrible name, but it'sbasically a collection view Swift
UI view that wraps a UI collectionview that uses compositional layout

(17:31):
under the
hood.
And we do that for two reasons.
One is performance.
If you have an infinite list ofcontent, so imagine you're building
a Mastodon client and you're justscrolling through stuff that has
images and links and text and stuff.
The
lazy
VST stack
is just not gonna work and list.

Leo Dion (host) (17:49):
Do you know what it does underneath That makes it
so, so much slower.

Ben Scheirman (guest) (17:53):
so if you can kind of squint and look at the.
What Apple was doing
with collection
views and table viewsto make things fast.
And, and especially with
around layout, like knowing howtall a cell is is really important
for knowing like how far you arescrolled through the content.
You know, what does thescroll bar look like?

(18:14):
How big should the scroll bar view be?
Scroll bar B,
because if that stuff changesdynamically, then you gotta
stop and compute, compute
it.
La So we run into problems
with lazy vs stack because it needsto know sort of the layout of all the
different items so it knows like, howmany am I showing on this first page?
So if you, if you look at LazyVStackand you, and you try to chain like a

(18:38):
task modifier or a, an appear modifieronto an element, you may be surprised
that it gets called right away, eventhough it's the last item in the

Leo Dion (host) (18:46):
Okay.

Ben Scheirman (guest) (18:47):
And so like something like an auto paging to the
next page in Pure Swift UI, one wayto implement this would be to have
your, for each, with all the itemsin it, and at the very end add like a
loading row that, that has a spinner,and then the, on a peer modifier for
the loading row kicks off the, thefetch for the next page of content.

(19:09):
And so the idea is you get tothe bottom, it loads, you get
to the bottom, it loads again.
So with LazyVStack, because it wastrying to like probe to see how many
items it could fit on the page, I gotmy appear modifier right away and I
loaded the page number two Right, away.
And

Leo Dion (host) (19:22):
Yeah.

Ben Scheirman (guest) (19:23):
so it was, it was like just kind of
frustrating 'cause there, therewasn't a lot that I could do
to I, I'm sure there's maybea different approach I could
take, but so that was one issue.
Performance on these lists was not, I.
Fantastic when we did justsome initial tests of like
infinitely scrolling lists.
But I still wanted to use SwiftUI for the content of the cells.

(19:44):
So I was thinking like,let's make a collection view
driven skeleton, where all, all the,all the meat is Swift UI and and
Apple provided UIHostingconfiguration.
It, and I feel like a lot of people,myself included, just kind of
avoided all those modern collectionview APIs that were like, here's
a sales content configuration.

(20:06):
And instead of, instead of likeunsetting things in the wheel
display cell and then there, therewas like prepare for reuse that you
could override on a cell subclass.
You would have to like unseteverything that you set before.
You know, like if, if, if there wasa label, like say a subtitle label.
And one of the elements didn'thave a subtitle and you just

(20:28):
skipped over setting it.
Well, then if that gets reused,it would just inherit the
value from the previous one.
So, you know, like there was stuff likethat that, that apple was trying to
make better and they, they implementedthat cell content configuration
and background configuration
and there's stuff about
updating the
state when
somebody hovers or, orpresses and holds or whatever.

Leo Dion (host) (20:49):
wanna say like of all the things that like Apple has updated
on UIKit, it's been collect collectionview, you could just see that's still a
keynote, or not keynote, but maybe like
primary piece of UIKit that'sconstantly being improved.
So yeah, I'm not surprised by that.

Ben Scheirman (guest) (21:05):
yeah.
And it's it's complex and
I,
I don't love the
APIs that.
Because they just, they don't just
like come naturally.
It's, this is
a, a component that has beeniterated on a bunch, but they
also have to like havebackward compatibility.
But so I mentioned thecontent configuration stuff.
They added a UIHostingconfigurationwhere if your entire

(21:27):
content comes from a
single cell,
sorry, single Swift UI view,
then you can set the cellscontent configuration to a
UIHostingconfiguration andgive it a Swift UI view.
And now you've got Swift UI cellsinside of a collection view.
So we implemented that, I, I did itin a test with an infinite list of

(21:47):
like just random emoji basically,and gradients and images and stuff.
So I could scroll throughand see like how it behaves.
Yeah.
Then now that I have a collection view,I have the ability to say and this
is the kind of the behavior you want.
I never want them to seea loading row at the end.

Leo Dion (host) (22:02):
Right.

Ben Scheirman (guest) (22:02):
would like it to be like, if you're scrolling
down and you're like certain numberof screen lengths from the bottom,
like the fetch more content.
And I know collection view hasa way to like prefetch Prefetch
rows or something like that.
I'm trying to remember the API for that.
But anyway, so this lets me doit because now I have access to
the collection view because Ihave access to the collection
view.
I also have access to the rawcontent, offset content inset.

(22:28):
And there's another one called
it's not, is Active.
It's on scroll view.
I can look it up in a minute, but,
So what it is, is, is so like how do youknow if you, let's say you're Swift UI
and you have a binding to a content andset property, right, which is a float.
And you, and you might thinkthat that's all you need to
do, pull to refresh, right?
Like, if I pull down thatcontent, inset becomes positive,

(22:53):
right?
Because as you scroll throughthe normal content, the content
inset becomes negative, right?
There's our content content offset.
So
or maybe I have that reverse.
I, I don't remember.
So you pull down
and the,
The pulter refresh thing isgoing to activate as soon as
you've passed that threshold.
Right, but what happens if I'm like,okay, I scroll up a little bit and

(23:17):
then I scroll down really fast.
You'll get that bouncing rubber bandingbehavior when you hit the top, right?
I don't want that behavior toshow the partial pull to refresh
logic,
Right, I only want it to, whenyour fingers down is tracking,
sorry, is tracking is the nameof the property on scroll view.
So scroll views is tracking, tells youif the user's finger is on the scroll

(23:40):
view.
And so this is how you can implementthat preventing rubber banding from
also showing your pull to refresh logic.
But also like if you wanta release to refresh.
Part of the pulter refreshcycle, that's also useful.
So you
can, you can do all that.
And so I take all those values, Ibundle 'em up into a struct and I

(24:00):
send them to Swift U iland, and thenall of a sudden my pulter refresh
is like mega easy to implement.
I can, I can customizeit however I want.
I've got a progress for how far you haveto drag, which I use to animate like a
little line that spreads across the, the
header.
And when, when that line touches theedges, that's when you're reloading.

Leo Dion (host) (24:19):
Got it.
Okay.

Ben Scheirman (guest) (24:20):
And so, so anyway, so I had to do this
by implementing a mega UI view,representable component that
is backed by a collection view.
And I had to do my own likecompositional layout, which, you
know, I thought maybe I wouldnever have to do that stuff again.
But turns out it was really important.
Now, the benefit of this approach,despite it being a lot more code.

(24:41):
Is we, this will never change, right?
Like Apple can change their mindon how lists work or whatever,
but this is our component.
We can decide to, you know, ditchit in the future if the apple
comes up with something better.
But the, like, for instance, the scrollview stuff in iOS 18, it's gonna be
two more years before we can use it.

(25:02):
So in that time, I need to beable to make some progress on it.
Also, I don't think that
the is tracking touchdown, youknow, logic is part of that
new iOS 18 scroll view, API.
And so you would probably stillneed to have some sort of UI view
representable, which was,which was tracking touches
down, touches began, or whatever.
Just to know.

(25:22):
So I think it would be possibleand probably be cleaner, and
I always say teen, but stillI don't think goes all the
way that we that to meet our needs.

Leo Dion (host) (25:29):
Do you like, how do,
you look at a piece of code andfigure out so I guess if you have
a new view, If it does what you
want it to do, you would go withswift y pretty much, or try to go
to Swift UI as much as possible.

Ben Scheirman (guest) (25:42):
If I find it to be far more productive
than, UIKit and especially like, Ihaven't used storyboards in a long time.
I sort of
saw that, that like wwasn't what I wanted.
And, and so I was like, got usedto writing constraints by hand and
I, I sort of, I can kind of geta sense for what's going on when
I see
constraints.

(26:02):
But nowadays when I look at'em, I'm like, this is a lot of
code to express something pretty
simple.
And,
And, there's,
I won't say there's no
scenario that Swift UI just can't
handle that constraints can, but there's
very few,

Leo Dion (host) (26:16):
right?

Ben Scheirman (guest) (26:17):
I, I, remember seeing a challenge.
Somebody's like, oh, somebody
implement this in UIKit, andI watched Chris eof do it
and he couldn't.
And so if if Chris eof
can't do it, then I certainlycan't it probably can't be done.

Leo Dion (host) (26:30):
Maybe he could do it in type script, but not, yeah.
Do I what?
Oh gosh.
Now I forgot what I was gonna say.
Oh yeah.
If your design team comes upwith something that's oh my
gosh, this is do you have any wiggleroom to be like, you know what?
We could easily dothis in Swift UI if we
don't do this, and this.
Do you have
any

Ben Scheirman (guest) (26:49):
Implementation costs and difficulty and
complexity and stuff like thatis definitely, it's a definitely
conversation and we just,sometimes designers aren't aware

Leo Dion (host) (26:58):
great.

Ben Scheirman (guest): of, of, like, what are the (26:59):
undefined
standards on iOS?
What, what is
free and what costs 10 grand?
You
know what I mean?
And so like
if, if that's not importantto them or they're like, oh,
I, you know, I just put that
in there because itlooked good, Or whatever.
But there are gonna be

Leo Dion (host) (27:14):
it's just an afterthought that's oh, I
assumed that, that's what it ha.
Yeah.
I,

Ben Scheirman (guest) (27:19):
And so, but there are gonna be
things that, thatdesigners will be like,
no, this is a primary interaction oranimation that, that is gonna like, make
our app feel more fluid or whatever.
And it's
worth that time to invest it.
I feel like the design and engineering
should always be twoway conversation and it
shouldn't be a
handoff,
right?
Because there are things thatcome up that you're like,
Hey, actually now that I'm in

(27:40):
it, I realize that this isgonna be really tricky because
when you scroll, this other
thing comes on top.
And
So so you have to
kind of come up with those solutionsand workarounds and trade-offs.
And
I think
that implementation
cost is a hundred percent part of
that conversation.

Leo Dion (host) (27:54):
One thing I was also gonna mention was the idea
of having to step back to UIKitfor doing more complex things.
It's not, I don't think it's cheatingbecause in some sense there was always
the ability in UIKit to step down ifyou need to customize thing, God forbid,
like you would always have core graphicsor core animation or something else.

(28:15):
So there's always gonna be anotherlayer removed from that abstraction
to always customize things anyways.
Right.
So it's it's just a be like you said,
is it worth the $10,000 to do itlike it might be, I don't know.
Yeah.

Ben Scheirman (guest) (28:30):
Yeah.
And I think, you know, I'm, I'm justbecoming more comfortable with that
decision of like, it's I used to getfrustrated, like there should be a way
to do this in pure swift ey.
And sometimes those
involve really complicated
solutions that involve preferencekeys and geometry readers
and like.
You know, to do something simplelike I need to know how big

(28:51):
this frame is so that I can replicatethat size in a different place, in
a different view hierarchy, right?
So like doing preference keys for that.
I, I still feel like, thepreference key system, it's like
for people who don't watch all thevideos and like read all the articles
and stuff like that, people who are justsort of doing their job, I don't think

(29:11):
people really understand how this works.
And so
as soon as you startseeing preference keys,
like this preference constructand extending environment
values or preference
you know, all thosedifferent like Swift UI
things that are like,what are you trying to do?
Oh, I've gotta create these threetypes I need to extend to this
thing.
I think that kind of getslost 'cause it is kind of

(29:32):
complex.
And so like some of
the pure Swift UI solutionsaren't quite as clean as you
would hope they would be anyway.

Leo Dion (host) (29:38):
I also wanted to chat a bit about stages.
Do you, so we talked about if youhave a new thing, you'd try to go
Swift two eyes as much as possible.
Do you have stages from going froma UI view controller to a Swift UI
view, or is it just kinda like we'rejust gonna rewrite this as a Swift UI
view?

(29:59):
I'll give you an example.
For instance,
like.
When it comes to like Objective-C to
Swift, like the first step is to youknow, maybe have ui te U unit tests
perhaps.
It might be adding syntactic sugarto the Objective-C so that you
can specify whether something isnil or what generic type it is.
And then maybe I might createlike an NS object class NS object.

(30:23):
Even though you'd wanna do a sw, likea struct, at some point you might
do like a class that derives fromNS object, so that way it can be
taken still ingested fromObjective-C while still
being written in a swift,you know what I mean?
Are there stages you can split up a
migration?

Ben Scheirman (guest) (30:40):
So I think that some of the things I've been talking
about are both changing the architecture
and the UI
paradigm, right?
Because you also have to consider like,how does the data flow into this system?
And
if it's like interactable, how doesthat data come back out and mutate your
model?
And in UIKit, that's usually very
different than a Swift
ui.
Bindings can help a lot there

(31:01):
You know, because you can, youknow, pass a mutable reference to
a thing, into a binding, and then
the edit screen, for
instance, can mutate it.
And then when you hit back, whenyou go back, it's already done.
That sort of thing.
But I think, you know, ifyou're just sort of trying to
start small and work from from theinside out is probably the best

(31:21):
approach if you're not trying to
also improve the architecture as you go.
So so if you imagine like I keep goingback to the Mastodon example because I
think most people are familiar with likesocial apps favoring an item, right?
So like,
say you tap on the starand it does a little dance,
I don't know, do that in swifty y andput that in your UI table view cell

(31:43):
and that's, you know, one step closer.
You know, over time you'll get moreconfident to take larger leaps.
Like maybe the whole cellbecomes Swift UI before the,
the surrounding screen becomes.

Leo Dion (host) (31:57):
Yeah, it, that reminds me of the whole thing with like
navigation too, where it waslike yeah, I mean, you want at
the outside, you want that app
delegate
still, and then you have a hostingcontroller, and then you could
deal with navigation that way asopposed to the other way where it's
yeah, you're just gonna have an
application and then work like,yeah, I think that makes total
sense.

(32:17):
You start with the
smallest piece on the inside and then
working

Ben Scheirman (guest) (32:19):
really tricky.

Leo Dion (host) (32:21):
it is really
tricky.

Ben Scheirman (guest): when you're mixing. (32:22):
undefined
I, I think it's tricky
in
general.
I am not a fan
of the,
the approach
that
view controllers know that they need
to push the next viewcontroller in the chain.
Like in a navigation controller,
Scenario, it means thatyour view controller knows
it's embedded
in a navigation controller,
which

(32:42):
it shouldn't shouldn't know.
Rou, Klu has this
amazing
quote,
I think it was at NS Spain in like,
I dunno, a long time ago.
He said
children
shouldn't tell their parents what to do.

Leo Dion (host) (32:55):
Yeah.
That is

Ben Scheirman (guest): software and in software, (32:56):
undefined
he would
argue That children know shouldn't know
who their parents are.

Leo Dion (host) (33:02):
Yeah,
that is

Ben Scheirman (guest): And it's like, it's a good (33:03):
undefined
sort of, I think aboutthis a lot because this
is kind of where the
coordinator pattern came out, where youhave these view controllers that can be
embedded
in different contexts if you needed.
But the point is, is they don't knowhow the navigation works, they just
delegate it up to a coordinator.
And the coordinator is like,oh, I'm in a navigation stack.
I need to push this other thing.

(33:24):
And what, what That allowsyou to do is avoid the
situation where, say you have A, Band C view controllers, and the C
view controller has a couple
dependencies.
So now A needs to create and push B.
B needs to create and pushC, but B doesn't have C'S
dependencies to pass along.

(33:44):
And so you either you.
Sort of what I would
consider anti-patterns,which is like static service
lookup and where C says, Hey, giveme my global dependency for this.
I don't know terms ofservice fetcher or whatever.
I, I much prefer the dependencyinjection approach, but B
doesn't need that and shouldn'teven know it exists, right?
So it's a dependency problemwhere, where I think that these

(34:07):
controllers create in creatingthemselves or creating their
siblings is kind of a patternthat I don't like in, in UI kids.
So this is why, I mean, that navigationis hard and navigation in Swift
UI is, has similar problems, but Ithink that that can be smoothed over
by the fact that you can put thingsin the environment and then you can

(34:27):
go three levels farther and thenpull them outta the environment.
So you don't necessarily have tocarry them along each step of the way.
But the problem that, that I see is that
like the, the model forSwift UI navigation is.
Either a binding to a Boolean ofwhether or not a thing is presented
or a binding to a, an array ofpath elements which identify

(34:49):
the items being presented.
So like when this path elementhas a value of the a user, I'm
gonna present the user edit
screen.
I like that sort of decorativemodel based approach because then
when the user dismisses the screen,that binding gets set back to
nil, meaning nothing is presented.
But in UIKit, you don't have that.
You just have push and

(35:09):
pop and there's no way for you totell, for instance, if you, if you
want model this since if Youi, but thenpart of this is a UIKit view hierarchy,

Leo Dion (host) (35:19):
Yeah.

Ben Scheirman (guest): it becomes difficult. (35:19):
undefined
Like how do you, how do you presentsomething in UIKit and then bubble
up the fact that they dismissed toa Swift UI binding so that it can
be modeled appropriately in Swift UI.
And I found, or I, I wasintroduced to this idea from
the point free video series.
They have a recent series on UIKit,sort of building observable models and

(35:45):
sort of adapting Swift UI tools to UIKitand it's really, really great series.
And they implemented a on dnetclass that holds onto a closure.
And then you assign that ondnet handler as an associated
object.
So you're going way back toObjective-C runtime, trickery

(36:09):
set that as an associatedobject on the view controller.
And that way you don't haveto touch the view controller
that you're presenting at all.
It doesn't need any new
API, it just has this this extrabit of state that is attached to it
by the Objective-C runtime system.
And so for folks that aren'taware there is a Objective-C like

(36:30):
BJC associated value andget associated value,

Leo Dion (host) (36:34):
you
can deep dive into the object and dowhatever the heck you want with it.
Yeah,

Ben Scheirman (guest) (36:38):
yeah.
And so like this is a way to like sortof piggyback some storage onto the,
onto the lifecycle of another object.
And
so what, what you would do thereis you just assign this on DNA
helper as an associated object.
And then when that view controllergoes away, it clears out that on
dnet object that you just set.
And so the idea is thatin the, in the Dnet

(36:59):
of the on Dnet helper,you execute the closure.
So that gives you
a hook that you can
apply to
any UI
view controller.

Leo Dion (host) (37:07):
When you're talking about

Ben Scheirman (guest) (37:08):
idea is that.

Leo Dion (host) (37:09):
ahead.

Ben Scheirman (guest) (37:10):
So the idea
there
is
that you that's where you
set the binding back
to, to is presented false ornailing out the, the presented
model whatever your binding
is.
There's, there's those two differentflavors of one that is just a true
false and one that takes like an item.

Leo Dion (host) (37:24):
I was just thinking back to any work I've done with web
development, I've, I still do some likeVJS stuff and like some type script and
I'm like, how did they do navigation?
And then I was like, well, either the
parent is responsible for it oruses the URL and I'm like, that
sounds a lot more like what you weresaying about using the path thing,

(37:44):
right?
Where you have an enum of the pathand you have an environment variable.
It's like that's basically what that
Is

Ben Scheirman (guest) (37:50):
The url, the ur l can be constructed
to say, Hey, I handle all
slash admin.

Leo Dion (host) (37:55):
Right?
Right.

Ben Scheirman (guest) (37:56):
And from that point onward.
And then from inside of admin,you have admin slash users
or whatever, and that
can, and then
that one has a sub route of user slash
you know,
25.

Leo Dion (host) (38:04):
And you almost.
You could kind of do that,
right?
You
sort of could do that with

Ben Scheirman (guest) (38:08):
can do
that in Swift UI.

Leo Dion (host) (38:10):
with an associated URL too, right?
So yeah.

Ben Scheirman (guest) (38:14):
you can do it with deep links.

Leo Dion (host) (38:15):
Or deep links.
Sorry.
That's what I meant.
yeah.

Ben Scheirman (guest) (38:18):
I, that that system is kind of confusing,

Leo Dion (host) (38:22):
Yes it
is.

Ben Scheirman (guest) (38:23):
but it does work.
The,
But I, I like the
path element approach that
navigation stack uses in iOS
16.
So, so the Swift UI binding to that item
that you can, you can mutate becausesome other UIKit thing did a D
in it is really, really helpfulAnd allows us to do things
like, we have a,

(38:45):
Flow that you have to gothrough as like, sort of like
onboarding.
And this has to be checkedevery time you log in.
And we need to make sure that your
locale is in a supported locale,
For.
For like the markets that we're, thatwe operate in and that you've agreed to,
to, or I've, you've confirmedon like a mobile number.
So there's a bunch ofsort of checks and it goes
through this state machine,

Leo Dion (host) (39:07):
Yeah.

Ben Scheirman (guest) (39:08):
to say like, okay, I'm gonna go from here to
here, I'm gonna check that and ifit's not there, I need to pause
here, present some ui, let theuser go through that flow and then,
and then come back to that spot.
And that is a pure swift just model
of model of the, of the walkthroughthe user has to go through.
So knowing when they're done with aparticular flow that is in UIKit and

(39:28):
those components are built by anotherteam that we don't influence, that
is really handy to be able to, to do
that sort of thing without having
to
wrap in a parent view controller,
you know, without having to do aPR on that particular component.
So,
The other thing though, that'sreally, really important, I
think it's really easy to, I.

(39:48):
For or not realize that youhave retained cycles in a view
controller,
which would lead to that viewcontroller never being deallocated.
And then, then your
on DN net
would never get called.
Yeah.
If you're using like,
Combined subscriptions and you dolike dot assigned to inside of a
view did load which it's just so easyto do, it's so tempting to do that.
But
that if, if you if youassign to anything,

(40:11):
it's basically calling self
value equals new valueand capturing that self.
And so if the self is holdingonto the subscription and the
subscription's holding onto
self, then
that view controllerjust never goes away.
Right.
This is a
common, common

Leo Dion (host) (40:26):
Could you do a disappear and cancel
on disappear or something?
Or
What can you

Ben Scheirman (guest) (40:31):
Yeah, you could,

Leo Dion (host) (40:31):
okay.
I'm just trying to think

Ben Scheirman (guest): some way of breaking that. (40:33):
undefined
Yeah.
And then the, the realanswer is usually just
do a
sync
and in the sink closure doweak self, so that way you're
never capturing
self.
But yeah, I think just knowingwhat, what, a retain cycle looks
like, you should be able to spot itpretty quick with closures, right?
Like it
I think with async

(40:53):
streams, this is also a bigproblem, that it's not always
obvious that you're retaining self,

Leo Dion (host) (40:58):
Let's,

Ben Scheirman (guest) (40:58):
Especially because tasks have an implicit self.
So it's like you can justcall methods directly.
And so I think it can hide,
Retained cycles.
So I would definitely say.
Use the you know, use amemory graph, debugger.
There are some othertools you could use, like
Christophe Slosky hasa tool called Lifetime
Tracker, which you can say like, Hey,I only ever want one of these screens

(41:21):
to be created, ever one of these few
And so basically itasserts, it creates like a
global counter and it assertsif you ever get more than your,
your, so for instance, like user profile
controller, there shouldliterally only ever be
one ever.
And if there's ever two crash

Leo Dion (host) (41:36):
Yeah.

Ben Scheirman (guest) (41:37):
crash via like debug assertion, which is really nice
'cause you want, you wanna catch these
things early.

Leo Dion (host) (41:42):
Yeah, yeah, totally.
Yeah, that's Awesome.
We'll put links to all thatstuff too in the show notes
so People can look that up.
Well Ben, thank you so much forjoining me for today's episodes.
We'll be talking more in thesecond part about Swift UI and
UIKit and migration, as well assome stuff about Swift packages.
So be sure to be on thelookout for that well.

(42:03):
Ben, where can people find you online?

Ben Scheirman (guest) (42:06):
You can find me.
My
website is ben Scheirman.com and,
I'm on Mastodon at ben
And yeah, my website will have linksto NSScreencast and Combined Swift
and some of the other apps I work on.
I.

Leo Dion (host) (42:19):
Awesome.
People can find me on Twittercompany is Bright Digit.
If you're looking for a developerApple space, please reach out to me.
You can find me onMacon at Leo Dion CI am.
If you enjoy this episode, watching thison video it's please, and subscribe.
I greatly appreciate it.
And if you're listening to this ona podcast player, gimme a review.

(42:41):
Thank you so much.
I look forward
to talking to you in thenext half of this episode.
Bye everybody.
Advertise With Us

Popular Podcasts

On Purpose with Jay Shetty

On Purpose with Jay Shetty

I’m Jay Shetty host of On Purpose the worlds #1 Mental Health podcast and I’m so grateful you found us. I started this podcast 5 years ago to invite you into conversations and workshops that are designed to help make you happier, healthier and more healed. I believe that when you (yes you) feel seen, heard and understood you’re able to deal with relationship struggles, work challenges and life’s ups and downs with more ease and grace. I interview experts, celebrities, thought leaders and athletes so that we can grow our mindset, build better habits and uncover a side of them we’ve never seen before. New episodes every Monday and Friday. Your support means the world to me and I don’t take it for granted — click the follow button and leave a review to help us spread the love with On Purpose. I can’t wait for you to listen to your first or 500th episode!

Crime Junkie

Crime Junkie

Does hearing about a true crime case always leave you scouring the internet for the truth behind the story? Dive into your next mystery with Crime Junkie. Every Monday, join your host Ashley Flowers as she unravels all the details of infamous and underreported true crime cases with her best friend Brit Prawat. From cold cases to missing persons and heroes in our community who seek justice, Crime Junkie is your destination for theories and stories you won’t hear anywhere else. Whether you're a seasoned true crime enthusiast or new to the genre, you'll find yourself on the edge of your seat awaiting a new episode every Monday. If you can never get enough true crime... Congratulations, you’ve found your people. Follow to join a community of Crime Junkies! Crime Junkie is presented by audiochuck Media Company.

Ridiculous History

Ridiculous History

History is beautiful, brutal and, often, ridiculous. Join Ben Bowlin and Noel Brown as they dive into some of the weirdest stories from across the span of human civilization in Ridiculous History, a podcast by iHeartRadio.

Music, radio and podcasts, all free. Listen online or download the iHeart App.

Connect

© 2025 iHeartMedia, Inc.