Leo Dion (host): Welcome Apps.
I'm your host, Leo Dion.
Today I'm joined
with Ben Scheirman Ben, thank
you so much for coming on one elephant in the room we haven't talked about, and
you kind of just briefly mentioned it?
Is your data.
You've got Like 32 choices of how you can have your hooked up
to Swift UI, and on top of that you have to work with UIKit.
How are you doing it?
Are you still doing observed Object?
You still using Combined?
Are you migrating to observable
Ben Scheirman (guest): So we because can't 16.
actually fantastic
and I am looking forward to forward to being able to do that.
Leo Dion (host): In the year
2026
Ben Scheirman (guest): but yeah 2026 probably but
but we gotta move forward.
So there's also the library by point freeze, and that is a
Leo Dion (host): course point
free
Ben Scheirman (guest): Yeah,
that is a back port Yeah free
framework that works
Leo Dion (host): Oh that's
Ben Scheirman (guest): maybe even 15.
remember what, but basically it's, it does the exact same thing.
It's, it's not rocket science.
Like you can go look at the source code.
It's, it's not too terrible to understand.
But side, problem is that we currently are not yet.
on SWIFT package managers.
So we can't pull in libraries like that just yet.
and stuck place where we, we, we would like to be able to adopt
libraries like that but can't.
So with the observable objects, I guess that the
primary reason why observable object versus observable is that when you, I.
When you property.
So if you do that at the root of your app and anything in that
changes, it triggers like a reflow of all the views inside of
Leo Dion (host): Unless you mark it as
observed, ignored
on purpose.
Ben Scheirman (guest): yes yeah, but like the observation framework
just makes this a non-issue.
'cause it's just whatever you access in the view.
So if you just own the object children, you don't need to when.
when that happens, and, and you can, you can stuff in the environment
and like four layers deep, it can pull it out again, and then at that
layer it observes those are the views that are gonna get re-render.
important.
But we, we object, currently called a model that we use
for each one of our views.
That model is, is, I hate to use the term view model because
this is like overloaded, but like as as know what thing is
you know, call it what you want.
I think the term model for if it's ex like.
it's a, it's nested inside of our view type.
So it's obvious that and that lets us pull dependencies handle all
of the, any kind of action that happens from a button click or
whatever gets routed to the model.
Because we wanna be able to these tests, right?
You should to test without touching the view.
And then we have a pretty complicated dependency graph, and I don't want to,
send the entire world into these models.
I want something really light and focused so that
these things can dead simple.
Like, I need to fetch this thing and get back some results.
And so if that dependency.
That, that we were calling is a little bit obtuse or, you know, it doesn't
fit, doesn't quite fit the need then, or maybe it requires two other
dependencies to actually 'cause it needs to pull in data from here and
then consult this list over here in order to return the right set of data.
I will hide all that stuff in a closure.
And that closure becomes the, the, the new dependency.
So This is gonna be like a, like a, I'm trying to think of a, an this is
your which will just give you right?
It doesn't need to consult.
Oh, I need to get information from this orders API.
Then I need to get images for the products over here or whatever.
And then I need to check to see if this thing was whatever it is.
You can marry those things in a way that they, you encapsulate
all that logic closure and just pass that closure to the model
so that it knows how to fetch data.
And that way your view isn't really
interesting it, you know, you sort of separated responsibilities
in that way and you can of course test all these things.
But it becomes trivial now for that dependency just by providing
a new closure that just returns a single item, returns two
Leo Dion (host): Yep.
Yep.
Ben Scheirman (guest): that's another thing we haven't really talked
about, but previews huge superpower that I I people were as, as I am.
I think a lot of people just abandoned previews 'cause they're kind of kind of
hard, you know, they're hard,
to do.
Right.
Especially in
a big app.
Leo Dion (host): Yeah.
I mean I've had issues with just like previews not compiling
properly and not and I've just had to like, I don't want to
abandon 'em 'cause I
want to quickly see stuff.
And if I do wanna use previews, what I've ended
up doing at this point is like I use the preview in a new app that's a test
app.
Right.
And be like, okay, I want it to look like this.
And then copy that over to
Ben Scheirman (guest): Yeah.
I, so I, I am of the opinion that like component and then every list
of that component or whatever like should have a preview that contains
all the states and mode, light mode, dynamic type or whatever.
Empty states, error states, you know, like if you were to look at a design
library from, you know, a web, like a, like for instance like Facebook
or, or Twitter or whatever Airbnb.
I'm just trying to think of like, large organizations are gonna have like a.
Like a style guide, like basically, you can go in and
be like, here's typography.
Here's all the different things you can do, And here's when you should use them.
And these are live examples they render right there.
And this is easy to do in the browser because you're
already in the browser, right?
Like if these things are in HDML and CSS and JavaScript, well
they can just run it right there.
And so here are all our buttons, here's how you can use how they
respond to hover and clicked and disabled states and all that stuff.
like the playgrounds, not playgrounds the previews are our way of doing
that in the best way possible so that, so that we can see something
that, see how it works, we can
interact with it.
And I would say 90% of my work for that collection view component, I, I talked
about 90% of that was done iterating on a preview in a
Leo Dion (host): And now the last couple years, they're
agnostic as far as whether use Swift UI or UI codes So that's a
Ben Scheirman (guest): They always
were.
Leo Dion (host): They always
Ben Scheirman (guest): you just wrap it your UIV controller
representable and you're done.
Leo Dion (host): Oh
Ben Scheirman (guest): It just now does this for you.
So
Leo Dion (host): to object, right?
And then are you using Combine underneath
Ben Scheirman (guest): So we use combine where it makes sense
and we use async await for,
Where it makes sense.
And, and I, I've talked about this before where I, I, I think, Johnson
Dell's podcast, we talked about mixings with do I or sorry, mixing async
await and And like when to use one.
Should we ditch, combine, combines days?
Our guests are numbered.
But I how hard it is to deprecate a framework in Apple land and it go away.
There are just certain things that I just feel like combined
is just, it's just easier to read and write and, async, await
make some make things way easier.
And so so we're still writing new
code that uses combine.
We're still mixing that sometimes with async weight.
I still don't really think in async So there's very few of that type of
async stream type of I like a a a loop that just runs forever seems
weird to
me.
Leo Dion (host): it does seem weird.
Ben Scheirman (guest): 100%
Leo Dion (host): I just wrapped my, I just created my first
Async stream and it's it made sense in that case, but what I've found is
anything that's one of those built in publishers, like a timer or like
a notification or even key value stuff, key value observing, it's just
so much easier to do and combine.
And like you said, it's just easier to think and combine
as opposed to this weird
Ben Scheirman (guest): glad Asy is a thing now, continues.
So like debounce, which I was how would you even write that?
That to me, that I was trying to think of like, you know, how it,
how it would be written, and that's just a different style than, than
writing operators in, in Combine.
But I will say that this is probably my own just experience
and comfort level with Combine.
I was a holdout on all the programming I found it to be confusing.
and then
I really dug into it and I
then I was like,
I need to make a course about this.
So that's where the Combined Swift course came
from.
And so now I feel very, very comfortable in combined.
So of the reason why I'm like not afraid to keep using it.
Leo Dion (host): I have a new app and I still, I have a couple of and
then everything else is observable basically and that's I feel like
observable was a thing that's okay, now I don't need to combine.
Even though I love it like so, yeah.
I totally agree
Ben Scheirman (guest): Yeah.
So the, so the data piece our app is mostly read only.
So that is, you know, when you have an app that is taking in
data you know, I, I have,
Leo Dion (host): would an
order?
Would
Ben Scheirman (guest): can't, yeah.
But that's, from my perspective, whole thing, right?
So Like so yes, you know, we could write that, but that's, you know,
luckily it's, it's not the e-commerce part of it is not our responsibility.
But like, say tonal therapy, this is like the easiest example I
could, I could, come up with, because it's like the only app
that is like kind of standalone.
It doesn't take data from the internet and display it.
Like 90% of the apps this you you enter in a frequency of like a tinnitus
frequency that you can hear, and then this will like, play a pattern.
And so, this is essentially a slider that's connected to a text box, so that,
And which is connected to the model.
And so whether or not you adjust the slider or type in box, they both
end up sort generate a new sequence
Leo Dion (host): right.
Ben Scheirman (guest): and so yeah, that two way binding, it
definitely, you know, still works.
And then if you need to marry that with an existing architecture
that wasn't built with these tools you I, feel like I.
Having bindings for the model so that you know when it changed and then
glue that to however else you would've updated your own internal model.
And I think it's, it's okay to not ha to like break your part, your model
up into smaller pieces so that that has to serve both roles, but you
can have like some glue that you pass a Swift UI to make the Swift
UI call site really nice and clean and then you glue those two things
together with to the value using Combine or asy CO eight observation
framework.
Leo Dion (host): Is there anything else you wanna talk about when it comes to
interfacing between UIKit and Swift UI
Ben Scheirman (guest): There's one thing that so I mentioned that
we started on this process of.
Sort of changing out our lists.
So I had to create this collection view component.
And, though, one of the early things we did to try to get some stuff
working in Swift UI was wrap some existing UIKit components in Swift UI,
sorry, UIKit components in Swift UI.
So, so using NS or UI view controller representable to wrap an
existing component is essentially a button, but underneath that is
tons and tons of valuable logic that we don't wanna mess up, right?
And so just wrap that in Swift UI Now the call site is really easy.
It's, we can use it in our Swift UI views directly.
That happened to be a component that needed to be used inside of
a cell and UI hosting controller
that I
mentioned was really nice that you could just plop in a Swift UI view.
That one will give you a fat warning if you do this, if you have a
so we're, so we're going from UIKit collection view
Leo Dion (host): Is this a runtime Warning, I
assume
is
Ben Scheirman (guest): Runtime warning, you're going from a UI which
is a collection view Swift UI, which is the hosting configuration view.
inside of that view you have a UI view controller representable.
It will fail, right?
It'll runtime, give you a warning.
This is an unsupported configuration and it will not render
Leo Dion (host): Okay
Ben Scheirman (guest): Because view controllers have to, they have a, an
in variant that you have to satisfy, which is that they have a parent
view controller or they're part of the view controller hierarchy.
And that's how things like safe area and sets and trait changes and you
know, sizing changes and stuff like that viewed it, a fear viewed will disappear.
All the, all those things flow through the parent child view
controller by putting a Swift UI
Wrapper, a round of view controller inside of a Swift UI view, and
then putting UI view controller Now you've broken that like that
little component doesn't have a reference to a parent anywhere.
And so I I was running full speed with this collection thing and the hit a
brick wall with this one and I and and it ended up process and think like,
well, how did Apple implement UI hosting controller because it's, or sorry, UI
hosting configuration 'cause it's fast.
That was the other thing fast worried about is like the UI hosting
view has a generic of a root view UI hosting controller, sorry,
has a generic of that root view.
And if you, and it's mutable so you can swap out that view for another one.
And that's what UI hosting cell.
So it's just, it's keeping that same space reserved.
There's only one UI view in there, so you're not like constantly
creating new UI views and then de and allocating them as you scroll, right?
It's one of those, but then you swap, swap in and out the, the Swift
UI content and that is really fast.
So I went that embeds a UI hosting controller of a known view type.
And then that one has a method on it where I
can set its parent So
that I know I have a way to set the parent view controller
of that UI hosting controller.
This is kind of hard to say on podcast form, but
Leo Dion (host): So
Ben Scheirman (guest): so, I sort of
like, how, how did Apple implement UI hosting configuration?
Like they're, they're using UI collection view cell, so like
they're probably using UI hosting
controller.
So I went that route and did it manually and I was able to set that parent view
controller manually and it wasn't,
it was probably a dozen lines of code to get this done.
And so it
Leo Dion (host): that is something people
should watch out
for, the hierarchy.
Yeah.
You're, it's not
gonna
Ben Scheirman (guest): yeah.
And it like, when I out, I'm like, oh we're going UIKit oh
UI to UIKit to kit to Swift UI to UIKit like, and it does work.
But you gotta be aware of all these layers because, the way that
Swift UI does sizing and layout is different from the UIKit does and
and those Swift UI doesn't care about your auto layout constraints.
it cares about your.
Yeah, yeah.
This has taken me a to to internalize.
But I will say like the, the little tidbit that has helped is if you have
an intrinsic content size for a view or a preferred content size for a view
controller if you save fixed size on the Swift UI wrapper, it will adhere to that
size as if it were the that component.
And that a bunch because I was like, how do to know how big the And the answer
is intrinsic content size for views, preferred content size for controllers,
and then use the dot fixed size,
Modifier on the Swift UI site.
Leo Dion (host): We had one question from Swift Dev when using built in
views, for example, a CN contact view controller or an EK event view
controller in Swift UI is there a way to have the toolbar showing
without wrapping set controller in a UI navigation I know the easiest
solution is to put it in a sheet, which is then, which isn't, which.
Which then just a UI navigation controller without
a ui, Swift UI navigation.
But I'm wondering if there's a way to do it without using a sheet.
If you wrap it a UI view CONT navigation controller, it's already
in Swift UI navigation stack.
It will show two navigation bars.
If you don't wrap it in a UI navigation controller, it
won't show the edit button.
Do you know what this Do
Ben Scheirman (guest): situation is
bar.
Obviously we I guess the question is, is the component, is Apple's
component coming with its own navigation controller, or does it expect you to
right
your And,
right two that were mentioned were the contact picker
and what was the other one?
Leo Dion (host): The event view controller for event
Ben Scheirman (guest): for like calendar.
Okay.
Yeah, I mean I would these are both, these, both predate Swift
UI, the contact one by a lot.
Yeah
I would
I
would not, I I would just try to like make that controller happy in
whatever way made sense for that controller, which probably means
playing UIKit navigation controller in a sheet.
If you, I also think that, that those things are generally modal in behavior
anyway.
You like, you go there to a thing then you
dismiss it and now you're
Leo Dion (host): It your it should be like a little
I
Ben Scheirman (guest): I, I push this on your own navigation stack.
oh, I fill out some details and now I click next, and now like, next hierarchy
is Apple's UI for picking a contact.
That me.
Leo Dion (host): Yeah 100% I agree.
Yeah.
I had one other topic I wanted to cover.
Now that you're here we talked about Swift Package Manager.
What is that, I guess at Nike?
Ben Scheirman (guest): There's probably too many internal details to
to discuss.
Large companies move slowly, right?
We have a
Leo Dion (host): of
Ben Scheirman (guest): lot projects.
of
yeah, it's, it's it's.
Leo Dion (host): Is it on the goal
post
Is
Ben Scheirman (guest): yeah, yeah, yeah.
We actually hit a blocker.
We, we were gonna do it last year and we hit a major blocker and have engaged
Apple in trying to out But yeah, it's, know, like big companies do things in
unique ways, I think sometimes, and sometimes that match the ideal path
that most people would encounter.
So I don't think most people would even be that we run into.
So
Leo Dion (host): yeah.
Yeah.
that makes sense.
So.
One thing that you helped me on was introducing me to sub
re and that was a big benefit.
I'm right now in the middle of a rewrite of one of my packages.
but do you think the situation has improved with developing simultaneous
package development when you have like dependencies and stuff?
Ben Scheirman (guest): I Do
no, I don't think it's improved at all.
So, so maybe some context for the listeners.
You monorepo, which is everything that your company develops, all
everything or in your own repo.
You can still do third party stuff that comes in externally, but if you
want to iterate on those components while you're building a thing, which
is what we most, most of the time we do, then, then having them in one
repo is actually kind of nice and it,
It, it's not even my preference.
I just
think that there are benefits, right?
So like the, the, the
alternative is like every component that you have
has a separate
GitHub repo or GI Git repository somewhere maybe on
Leo Dion (host): in either a
Ben Scheirman (guest): I'm specifically
Leo Dion (host): ta
either I was just gonna say, I'm specifically
talking
about like a swift, like an open source project you wanted to publish
Ben Scheirman (guest): But it,
has other packages that are part of that.
Leo Dion (host): Yeah like third, park, like you want a,
different plugin for instance
Ben Scheirman (guest): Yeah.
And are
hosted in the same repo or, or in separate repos.
Leo Dion (host): Right, right.
But it's put But
Ben Scheirman (guest): If you put
'em in
Leo Dion (host): put
But it's hard harder to publish it, like as
a mono repo.
So, for instance, in my case I have a, I'm working on sublimation, which is
my package for allowing people to auto, like if you have a iPhone, you want
it to auto detect your vapor server.
It, you could either advertise it via ngrok and some sort of key value
pair on the cloud, or you could use Bonjour and advertise it that way.
So there's separate packages for that.
That's the current example that I'm running into right now.
So right it's actually a mono repo, and then I'm gonna split
them off into in development, like not extra not advertised
yet, but like it's in a mono repo.
And then the plan is to take those directories and put
'em out into separate repos.
Once I know that everything works
Ben Scheirman (guest): Yeah.
I think that that.
So like if you wanted to iterate on all those things, but keep
them in separate repos, then you could do a local checkout.
You could tell your package manager the Swift package manager, that I have a
local package instead of a remote one.
Leo Dion (host): Yep.
That's what
Ben Scheirman (guest): what I'm doing
that way.
In the CocoaPods way, if anything in your pod file reference
to Local up under development dependencies and symlinked to those
folders in your Xcode project.
So when, could you could edit them directly you when done, you push
it, you tag it, you change your pod file reference to point to
the tag version and you're done.
It was actually pretty nice story in, in swift Package a little bit
more cumbersome to do that, I think.
And I, I haven't, like, I use Swift Package Manager on basically every
project I do, but it's, all of those are tiny in comparison to what, to
what I'm working on at, at Nike.
But, there are certain things that I have heard have been problematic on
larger projects like of creating a local version of a transit of dependency.
So say I have dependency A, but a a which I want to work on.
And so pulling in dependency B locally, when you resolve A, you need Swift
package manager to also as a local package so that, so that it all I
don't know if that's solved yet.
I then there's the the other problem of like, X code decides to resolve
packages when it wants to, again, I know this is but if you've got a
bunch of packages and then you get on a plane and open up a project.
Like, up your editor while it's it's to packages.
And I, I kind of of of CocoaPods where you're like manually saying,
I'm ready to pod install here.
And at that point you've got a copy of the, the code Twist is
actually a, a project that I'm really interested in.
Leo Dion (host): Yeah.
I've had Pedro
on here
talking about tourist and I feel
Ben Scheirman (guest): They do the, they do
They do
I
does amazing
you have a command to resolve the packages.
It does it with Swift Package Manager, checkout and then when
you integrate with Twist, it
uses
that local version.
Leo Dion (host): Yeah.
Yeah.
Completely.
Anything else Ben, you wanna talk about
before we close out
Ben Scheirman (guest): Oh, I could talk about this stuff all day
Leo Dion (host): How much time do you did you still wanna chat
about this wonderful studio that I'm about to tear down I.
wonderful
Ben Scheirman (guest): you want to.
Sure.
to tear
Leo Dion (host): Okay, well end it
far the podcast episode, and record a separate thing and I'll post a
link to that in the show notes.
Ben, thank you
was
Ben Scheirman (guest): Yeah.
it really great conversation.
Appreciate it.
Leo Dion (host): Where could people find you online
Ben Scheirman (guest): I
You can find website@benScheirman.com
That will have links to n and combine Swift and some of the other apps
I work and I'm on Mastodon at ben
s@mastodon.xyz.
Leo Dion (host): Awesome.
People can find me on Twitter at Leo
Dion.
At Leo g Dion at am on Mastodon.
If you wanna come on let me know.
I'd love to have you on as a guest.
If you're watching this on YouTube, please and subscribe.
I greatly