Empower Apps

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 - @leogdion

LinkedIn
BrightDigit

Leo

Patreon - brightdigit

Credits

Music from https://filmmusic.io
"Blippy Trance" by Kevin MacLeod (https://incompetech.com)
License: CC BY (http://creativecommons.org/licenses/by/4.0/)
  • (00:00) - Who is Ben Scherman
  • (02:38) - Migrating Apps to Swift UI
  • (07:03) - Challenges with Swift UI and iOS Versions
  • (10:24) - Using Introspect for Swift UI
  • (16:44) - Implementing Collection View in Swift UI
  • (25:05) - Exploring iOS 18 Scroll View API
  • (25:30) - SwiftUI vs UIKit: Productivity and Constraints
  • (26:38) - Design and Engineering Collaboration
  • (29:43) - Stages of Migrating to SwiftUI
  • (34:14) - SwiftUI Navigation and Environment Bindings
  • (39:44) - Retain Cycles and Memory Management
Thanks to our monthly supporters
  • Bertram Eber
  • Edward Sanchez
  • Satoshi Mitsumori
  • Danielle Lewis
  • Steven Lipton
ā˜… Support this podcast on Patreon ā˜…

Creators & Guests

Host
Leo Dion
Swift developer for Apple devices and more; Founder of BrightDigit; husband and father of 6 adorable kids
Guest
Ben Scheirman
Lead iOS Engineer for NIKE | Creator of https://t.co/opkAmLxbow, NSScreencast | Frequent dad joker.Moved to https://t.co/7961dq3XO9, follow me there

What is Empower Apps?

An exploration of Apple business news and technology. We talk about how businesses can use new technology to empower their business and employees, from Leo Dion, founder of BrightDigit.

[00:00:00]

[00:00:00] Who is Ben Scherman
---

[00:00:00] Leo Dion (host): Hey folks. As you can here I am slowly setting this studio up here in my new home. Before I go off to Jolly England to talk about Vapor, I want to release the first part of these episodes I did with Ben Scheirman.

[00:00:16] Leo Dion (host): of NSScreencast. I hope you enjoy this one, and the

[00:00:21] Leo Dion (host): second part will be coming out next week.

[00:00:23] Leo Dion (host): If you're on Patreon, you can get both right now as well as a bonus chat I did about setting this whole studio up. So I hope you enjoy and have a good rest of your week.

[00:00:38] Leo Dion (host): Welcome to another episode of Empower Apps. I'm your host, Leo Dion. Today I'm joined with Ben Scheirman. Ben, thank you so much for coming

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

[00:00:50] Leo Dion (host): Obviously a lot of people know you from NSScreencast, but I'll let you go

[00:00:53] Leo Dion (host): ahead and introduce yourself.

[00:00:56] Ben Scheirman (guest): Yeah. It started NA Screencast in 2012. Yeah. So it's been. You know, 12 years of, of doing the screen casting

[00:01:05] Ben Scheirman (guest): thing. And,

[00:01:06] Ben Scheirman (guest): I've also done a course on.

[00:01:08] Ben Scheirman (guest): Combined Swift. We can have links to all this stuff in the, in the show notes later. Yeah. And that's, you know, I, I have a

[00:01:15] Ben Scheirman (guest): couple of

[00:01:16] Ben Scheirman (guest): side apps that I've work

[00:01:18] Ben Scheirman (guest): on independently.

[00:01:20] Ben Scheirman (guest): One of them is side Mirror, which is a Mac app.

[00:01:23] Ben Scheirman (guest): I have another one called Tonal Therapy, which is for tinnitus. And that's on the iPhone. And I am currently working on another independent app because I'm a glutton for punishment, and I just

[00:01:35] Ben Scheirman (guest): can't, I can't get these ideas outta my head unless I try

[00:01:38] Ben Scheirman (guest): to build them.

[00:01:39] Ben Scheirman (guest): But then on top of all that, I, I'm also a lead software engineer at Nike. So that's my full-time gig. And so I'm just constantly, you know changing

[00:01:48] Ben Scheirman (guest): hats into, into different modes.

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

[00:01:53] Leo Dion (host): work on?

[00:01:54] Ben Scheirman (guest): I've worked on the sneakers app, so it's, it's for all of the sort of street wear and sneaker community,

[00:02:00] Ben Scheirman (guest): all of the

[00:02:01] Ben Scheirman (guest): The sort of hot drops. Hot, hot drops.

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

[00:02:07] Ben Scheirman (guest): Yeah.

[00:02:08] Leo Dion (host): temu for

[00:02:09] Ben Scheirman (guest): They literally measure the releases as in terms of heat level. So like, there's like an atomic and a high

[00:02:15] Ben Scheirman (guest): heat. And because, because they have to scale traffic to accommodate the demand, it's, it's,

[00:02:19] Ben Scheirman (guest): You know, not unlike, you know, iPhone, pre-orders or Taylor Swift tickets or whatever.

[00:02:24] Ben Scheirman (guest): I mean,

[00:02:25] Ben Scheirman (guest): you

[00:02:25] Ben Scheirman (guest): know, in a different scale, but same ideas where you have a lot, you have a lot of people who want the thing at that exact

[00:02:31] Ben Scheirman (guest): moment. And so that actually makes some fun design choices that you

[00:02:35] Ben Scheirman (guest): get to make on the backend and on the client.

[00:02:37] Leo Dion (host): That's awesome.

[00:02:38] Migrating Apps to Swift UI
---

[00:02:38] Leo Dion (host): So we're chatting in Chicago. I wanted, I've been wanting to have you on for ages and one of the things you mentioned is like trying, like slowly migrating your apps to swift ey. And that migration is one

[00:02:54] Leo Dion (host): of my favorite topics. It's a little bit boring, but at the end of the day,

[00:02:58] Leo Dion (host): there's good majority of what people do in the real world

[00:03:02] Leo Dion (host): is

[00:03:02] Ben Scheirman (guest): Yeah. How, how often do you do file new projects?

[00:03:04] Leo Dion (host): right, right.

[00:03:05] Leo Dion (host): I did a whole video about migrating from a Objective-C because there's still apps with Objective-C and good luck trying to hire an Objective-C developer. Let's just migrate it to Swift and people will know what to do with it. Or there's

[00:03:17] Leo Dion (host): just stuff you can't do in Objective-C like Swift UI

[00:03:21] Leo Dion (host): for instance, which we'll talk about today. But

[00:03:23] Leo Dion (host): yeah, I think it's like a real world

[00:03:25] Leo Dion (host): topic that a lot of

[00:03:26] Leo Dion (host): people have to deal with is migrating

[00:03:30] Leo Dion (host): from UIKit, in this case, the Swift UI or something like that. When do you think, when is a good point at which you're like, yeah, this is not worth me

[00:03:41] Leo Dion (host): doing another storyboard or another zip or doing

[00:03:44] Leo Dion (host): another programmatic layout.

[00:03:46] Leo Dion (host): Let's

[00:03:46] Leo Dion (host): just migrate this to Swift y.

[00:03:48] Leo Dion (host): At what point do you think that decision needs to be made?

[00:03:51] Ben Scheirman (guest): Certainly is a nuanced question. We have, I mean. I'm gonna say we a lot because I have, you know, in my, alongside my independent apps, I also work on a team. And so,

[00:04:03] Ben Scheirman (guest): you know, I

[00:04:03] Ben Scheirman (guest): have to

[00:04:03] Ben Scheirman (guest): consider that for, for

[00:04:04] Ben Scheirman (guest): my own apps, I'm usually willing to

[00:04:08] Ben Scheirman (guest): adopt the newer thing sooner. I'm willing to

[00:04:11] Ben Scheirman (guest): sort of bite the bullet and you know, procrastinate by exploring some new technology or some new technique.

[00:04:17] Ben Scheirman (guest): And it, it, to me, it, it, like,

[00:04:18] Ben Scheirman (guest): it, it becomes a way for me to explore

[00:04:21] Ben Scheirman (guest): and learn and

[00:04:21] Ben Scheirman (guest): flex the muscles and all that stuff, you know about learning new technologies and those, those I may cover on a, in a screen

[00:04:28] Ben Scheirman (guest): caster, of course. But when you're in a company and you're on a team

[00:04:32] Ben Scheirman (guest): and you're shipping a product some of the things are sort of low risk changes and some of the things are

[00:04:37] Ben Scheirman (guest): high risk changes. So like a setting

[00:04:40] Ben Scheirman (guest): screen is pretty low risk. There, it's something that's not core to the app flow. A user may only go to

[00:04:45] Ben Scheirman (guest): it once ever. And it's also pretty easy to build. So it's like that's an easy

[00:04:50] Ben Scheirman (guest): win. You could just rewrite it in the time it

[00:04:52] Ben Scheirman (guest): takes probably to update a storyboard or update a view controller and add auto layout constraints and, and things like that.

[00:04:58] Ben Scheirman (guest): Where things become a little bit more challenging or when they are in the core flow of your app, or if certain

[00:05:04] Ben Scheirman (guest): experiences are a must have and those may be challenging or missing in swift ey.

[00:05:11] Ben Scheirman (guest): And so for those I think you 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 months while you rewrite the whole app.

[00:05:21] Ben Scheirman (guest): And so the approach is generally gonna be sort of rewrite little pieces as needed. If something doesn't need to be changed you know, don't change it. But in our case, in a lot of cases I've been on, the cost of new features just sort of generally goes up over time because the code base is harder to work in.

[00:05:39] Ben Scheirman (guest): It was never designed to do the thing you're trying to do. And so getting that flexibility means you have to be able to refactor the code. And refactoring the code that was written a decade ago sometimes is a little challenging. You know, this code is probably not written by you, or it's written by people that are no longer at the company.

[00:05:56] Ben Scheirman (guest): And, and so I do mention this with a, with a slight warning that it is sort of a natural programmer tendency to just be like, oh, I didn't write this. I wanna rewrite it.

[00:06:06] Leo Dion (host): Yeah.

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

[00:06:24] Leo Dion (host): Yeah.

[00:06:25] Ben Scheirman (guest): 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,

[00:06:33] Ben Scheirman (guest): You know, I say riskier, but like more important

[00:06:36] Ben Scheirman (guest): screens are being

[00:06:37] Ben Scheirman (guest): migrated. And so we do that so that we can tackle these new

[00:06:41] Ben Scheirman (guest): features and not have to deal with some legacy code that's been there for 10 plus years.

[00:06:46] Ben Scheirman (guest): And and then you risk, you know, breaking something that used to work and nobody ever understood why, you know, things like that. And so that's kind of our, our approach has been,

[00:06:55] Ben Scheirman (guest): To do that just one piece at a time.

[00:06:57] Ben Scheirman (guest): And slowly but surely, like the lar larger and larger parts of the app become Swift UI.

[00:07:03] Challenges with Swift UI and iOS Versions
---

[00:07:03] Leo Dion (host): One of the things you mentioned in your notes is the fact that you still support iOS 16 is how does that

[00:07:13] Leo Dion (host): affect the migration? Are you

[00:07:14] Leo Dion (host): like, eh, we gotta do this really delicately because we still have people on older phones, or like, how does that

[00:07:21] Leo Dion (host): work?

[00:07:21] Ben Scheirman (guest): so if we rewind a year,

[00:07:23] Ben Scheirman (guest): we were supporting iOS 15 and at that time we were like, oh, Swift UIs, rough

[00:07:28] Ben Scheirman (guest): edges are mostly

[00:07:29] Ben Scheirman (guest): sanded over, right? There was some, there was some kind of really

[00:07:32] Ben Scheirman (guest): rough things in I 13 and 14, but by 15,

[00:07:35] Ben Scheirman (guest): I'm trying to think of the

[00:07:36] Ben Scheirman (guest): the flag

[00:07:38] Ben Scheirman (guest): pole features that they had or,

[00:07:39] Ben Scheirman (guest): Was it navigation view?

[00:07:41] Ben Scheirman (guest): No. Navigation view. Was

[00:07:42] Ben Scheirman (guest): there navigation stack or No, a navigation stack is

[00:07:45] Ben Scheirman (guest): 16.

[00:07:46] Leo Dion (host): Okay.

[00:07:47] Leo Dion (host): Okay.

[00:07:47] Ben Scheirman (guest): I'm forgetting Anyway,

[00:07:49] Ben Scheirman (guest): So there. Yeah,

[00:07:51] Ben Scheirman (guest): so we were like, okay, at 15, let's

[00:07:53] Ben Scheirman (guest): start looking at Swift UI.

[00:07:55] Ben Scheirman (guest): And this is, so one year ago, so we're, we're building

[00:07:57] Ben Scheirman (guest): for Iowa 17, but supporting 15. And and so then, you know, we implement a screen and we ended up running into some problems.

[00:08:06] Ben Scheirman (guest): And then Iowa

[00:08:07] Ben Scheirman (guest): 16 comes out, and then that's different behavior again, which is like, okay, this is,

[00:08:13] Ben Scheirman (guest): You know, it's not, it's not nice when you have like a workaround that

[00:08:15] Ben Scheirman (guest): you did for iOS 15, and then Iowa 16 comes out and changes that behavior and that workaround either no longer works or behaves

[00:08:21] Ben Scheirman (guest): differently, and so you end up with

[00:08:23] Ben Scheirman (guest): sort of this conditional code. So it is really challenging actually, if you're not going to,

[00:08:30] Ben Scheirman (guest): Target the latest version or even like n minus one. It, it definitely is challenging. Like Apple released so many nice things in iOS 18, and I'm like, I can't use any of them. So an example of that.

[00:08:44] Ben Scheirman (guest): Is pull to refresh

[00:08:45] Ben Scheirman (guest): behavior. So we have a custom pull to refresh in our app.

[00:08:49] Ben Scheirman (guest): And this is implemented as a sort of taps into the scroll position of a scroll view. Any, any scroll view throughout the app. It does not use the UI refresh control like API because that I think is too limited to do what we're trying to do. Like one of the behaviors of the system, one is that

[00:09:11] Ben Scheirman (guest): if you

[00:09:11] Ben Scheirman (guest): keep pulling, eventually it'll just start refreshing.

[00:09:14] Leo Dion (host): Right,

[00:09:14] Ben Scheirman (guest): But, But, we wanted a like sort of a mid state of like release to refresh, so that way you

[00:09:19] Ben Scheirman (guest): can sort of see what the threshold is. And if you, if you let go after the

[00:09:23] Ben Scheirman (guest): threshold, it refreshes if you move your thumb back up, it

[00:09:26] Ben Scheirman (guest): doesn't.

[00:09:27] Ben Scheirman (guest): And then on top of that, you've got like the progress of that drag so that you could do all kinds of interesting things like animate shapes or whatever, you know, you could get creative with it, whereas apples is kind of

[00:09:37] Ben Scheirman (guest): boring.

[00:09:39] Ben Scheirman (guest): It's a, you know, it's just pulled

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

[00:09:44] Ben Scheirman (guest): originally, yeah. And, and you say you, but I

[00:09:47] Ben Scheirman (guest): didn't do it. It was done long, long ago. Right. So, like,

[00:09:50] Ben Scheirman (guest): you know, again,

[00:09:51] Ben Scheirman (guest): nobody on the team now were there when it was written. And so, so we're like, okay first understand how it works, can we customize it?

[00:10:00] Ben Scheirman (guest): Yada, yada yada. Then we go to start building something in Swift UI and we're like, oh, this screen is really easy. It's just, it's literally a list of things with image And, text, but we needed that pull to refresh view on it. And

[00:10:12] Ben Scheirman (guest): so trying to get that to work was really tricky because we needed access to the collection view underneath,

[00:10:18] Ben Scheirman (guest): or the table view. And so.

[00:10:23] Ben Scheirman (guest): We, you know, looked around a lot.

[00:10:24] Using Introspect for Swift UI
---

[00:10:24] Ben Scheirman (guest): Intro Spec was the option that we went with. And at the time had a, the newer API is definitely better, but the original API for Intro Spec, and for those who don't know, intro Spec is a library that sort of lets you peek under the covers at what Swift UI is doing and access some of the hidden UIKit hierarchy.

[00:10:43] Ben Scheirman (guest): Underneath it is,

[00:10:44] Ben Scheirman (guest): it's a glorious hack, and it's like kind of a last, last,

[00:10:50] Ben Scheirman (guest): It's like your last resort,

[00:10:52] Ben Scheirman (guest): And it, I call it the Swift UI Escape Hatch. And I actually published a video on this,

[00:10:57] Ben Scheirman (guest): Which is, which is a free, it's a free video on, in a Screencast and to show how that technique works.

[00:11:04] Ben Scheirman (guest): And so what, what happens is you create a UIViewRepresentable,

[00:11:11] Ben Scheirman (guest): Which is a way of

[00:11:12] Ben Scheirman (guest): wrapping UIKit views and treat them like Swift UI. So and there's also a view UIViewControllerRepresentable as well. So if you add a UI, view representable as like a background or an overlay, that's just like

[00:11:29] Ben Scheirman (guest): an invisible view. It gets installed in a view hierarchy that has access to

[00:11:34] Ben Scheirman (guest): super view and parent controller and stuff in the case of a

[00:11:38] Ben Scheirman (guest): controller. So at some, at that point you've like created this

[00:11:40] Ben Scheirman (guest): like this little thing that it gets hooked into this environment that now you

[00:11:44] Ben Scheirman (guest): traverse. And so what it would do is it would walk up

[00:11:48] Ben Scheirman (guest): the, walk up the hierarchy until it finds a known parent and then walk back down and look at siblings to see like, oh, is this a scroll view?

[00:11:57] Ben Scheirman (guest): Is this a collection view? Is this a table view? So

[00:12:00] Leo Dion (host): Basically the kind of

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

[00:12:06] Leo Dion (host): if you

[00:12:07] Ben Scheirman (guest): Yeah, so like, if Apple said, if Apple said hey, we have a

[00:12:10] Ben Scheirman (guest): new photo

[00:12:10] Ben Scheirman (guest): picker control and controller,

[00:12:13] Ben Scheirman (guest): and that thing is a UIKit view controller. You could look at his view controllers, you could look at his sub views. Even though those are con considered like private API,

[00:12:21] Ben Scheirman (guest): you could technically go in there and fiddle with things.

[00:12:24] Ben Scheirman (guest): So the

[00:12:26] Ben Scheirman (guest): the thing about Swift UI is it hides all that stuff from you. So if you need access to the underlying the underlying scroll view or, or table view or collection view.

[00:12:35] Ben Scheirman (guest): I say those three separately because it's, that

[00:12:37] Ben Scheirman (guest): distinction becomes important in a minute.

[00:12:39] Ben Scheirman (guest): The, the, at the Swift UI call site, you would just say Intro spec on a Swift UI list.

[00:12:45] Ben Scheirman (guest): You'd say do introspect, and then it, and then the closure that you provide is passed in the scroll view. And so then you can do what you want. You can add a delegate or you can add an observer for the content offset. And so, so it's like, it, it enables you to sort of stitch these two things together.

[00:13:02] Ben Scheirman (guest): Well, so when I was 16 came out, that broke because lists became. Stopped being implemented by a table view and instead is now implemented with collection

[00:13:12] Ben Scheirman (guest): view. So then we had to add a, add a separate one for that. And so this is kind of like the nature of it. You're, you're you know, programming against an API that is not public, that the, it's an implementation detail that Apple decides.

[00:13:23] Ben Scheirman (guest): And one day it may never be based on a UI ki view controller ever. You know, they can do whatever they want under the hood and it's an opaque

[00:13:31] Ben Scheirman (guest): API to us. And so introspective is certainly not a long-term solution. I do like the newer API that it has though, where it codifies the things that are known based on a OS

[00:13:44] Ben Scheirman (guest): version. So you could say, I want to introspect this list on iOS 15, and the value you get

[00:13:50] Ben Scheirman (guest): is a squirrel view. But then you can also say on, I do the same thing, I wanna introspect it on iOS 16,

[00:13:56] Ben Scheirman (guest): the value you get as a collection view. So it sort of codifies what is known at

[00:14:00] Ben Scheirman (guest): that OS version.

[00:14:02] Ben Scheirman (guest): And so then when iOS 18 comes along, you now have a build error and you gotta, you, you have to like figure out what is the current way of doing that thing.

[00:14:11] Ben Scheirman (guest): So it, you, sort of catch it right away as soon as you

[00:14:13] Ben Scheirman (guest): start building with the new

[00:14:15] Leo Dion (host): That's so interesting because like with Bushel, my VM app for the Mac I used, I ended up creating like what do you call it? A MO view modifier so I can then grab the NS window and add a delegate to

[00:14:30] Leo Dion (host): it

[00:14:30] Leo Dion (host): And it's the same

[00:14:31] Leo Dion (host): idea. I would assume they're never going to go away from NSWindow, I would assume,

[00:14:36] Leo Dion (host): you know, anytime soon.

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

[00:14:45] Leo Dion (host): right, right. And I know this year they added a

[00:14:47] Leo Dion (host): bunch of window stuff to Swift UI,

[00:14:50] Leo Dion (host): so maybe a lot of that can be deprecated and things like that. So yeah, that makes total

[00:14:55] Leo Dion (host): sense

[00:14:56] Ben Scheirman (guest): and it's important to know that, like as you find these workarounds or these things I did a series on building a Mastodon app for

[00:15:04] Ben Scheirman (guest): for the Mac with Gui

[00:15:05] Ben Scheirman (guest): Rambo. And I talked to him about this idea of

[00:15:09] Ben Scheirman (guest): like, is it a failing of swift ey if you have to drop

[00:15:13] Ben Scheirman (guest): down to NSViewRepresentable or UIViewRepresentable.

[00:15:17] Ben Scheirman (guest): And, and his, his take on that was,

[00:15:20] Ben Scheirman (guest): it's necessary. It's like you're always

[00:15:22] Ben Scheirman (guest): gonna have to do

[00:15:23] Ben Scheirman (guest): it because Swift UI is still a young framework. They're, they haven't

[00:15:26] Ben Scheirman (guest): implemented every last thing.

[00:15:29] Ben Scheirman (guest): And if you don't want your apps to look and behave exactly like the mail app on, on iOS, right? If you want anything custom, any kind of custom non-standard behavior, which I think the, the industry is moving back towards that things that look nice and feel nice, you know, a little bit of skew amorphism, things like that I think

[00:15:49] Ben Scheirman (guest): should be celebrated.

[00:15:50] Ben Scheirman (guest): A little bit of surprise and delight. You know, like I mentioned with the pull to refresh indicator, the, the stock one is

[00:15:56] Ben Scheirman (guest): super boring.

[00:15:57] Ben Scheirman (guest): And I think that you can get creative with stuff like that and, and,

[00:16:01] Ben Scheirman (guest): if, if Apple doesn't provide it, right? The UI refresh control, sorry, the refresh control modifier in Swift UI

[00:16:08] Ben Scheirman (guest): only gives you the default behavior and you can't customize it at all.

[00:16:14] Ben Scheirman (guest): So sort, sort of going back to that, that example

[00:16:17] Ben Scheirman (guest): I. Of needing to customize that.

[00:16:20] Ben Scheirman (guest): We ended up using intro spec as, yeah, this kind of sucks, but we don't have a better solution. So we, we went with it and I was 15, you know, targeting, I was

[00:16:30] Ben Scheirman (guest): 15, I was 16, ended up having different behaviors, so we had to fix that.

[00:16:34] Ben Scheirman (guest): And then now we actually have a real solution that doesn't require such hacks but is sort of a new beast on its own.

[00:16:44] Implementing Collection View in Swift UI
---

[00:16:44] Ben Scheirman (guest): So I think that I, I mean, I can talk about this, this idea, it's, it's sort of specific to what we are trying to do, 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 want and you have no view modifier that can.

[00:17:08] Ben Scheirman (guest): Make it do the thing you want. The, the tool at your disposal is 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

[00:17:23] Ben Scheirman (guest): a, it's a terrible name, but it's basically a collection view Swift UI view that wraps a UI collection view that uses compositional layout

[00:17:31] Ben Scheirman (guest): under the

[00:17:31] Ben Scheirman (guest): hood.

[00:17:32] Ben Scheirman (guest): And we do that for two reasons. One is performance.

[00:17:36] Ben Scheirman (guest): If you have an infinite list of content, so imagine you're building a Mastodon client and you're just scrolling through stuff that has images and links and text and stuff. The

[00:17:45] Ben Scheirman (guest): lazy

[00:17:45] Ben Scheirman (guest): VST stack

[00:17:46] Ben Scheirman (guest): is just not gonna work and list.

[00:17:49] Leo Dion (host): Do you know what it does underneath That makes it

[00:17:51] Leo Dion (host): so, so much slower.

[00:17:53] Ben Scheirman (guest): so if you can kind of squint and look at the. What Apple was doing

[00:17:58] Ben Scheirman (guest): with collection

[00:17:59] Ben Scheirman (guest): views and table views to make things fast. And, and especially with

[00:18:03] Ben Scheirman (guest): around layout, like knowing how tall a cell is is really important for knowing like how far you are scrolled through the content.

[00:18:12] Ben Scheirman (guest): You know, what does the scroll bar look like?

[00:18:14] Ben Scheirman (guest): How big should the scroll bar view be? Scroll bar B,

[00:18:18] Ben Scheirman (guest): because if that stuff changes dynamically, then you gotta stop and compute, compute

[00:18:22] Ben Scheirman (guest): it. La So we run into problems

[00:18:24] Ben Scheirman (guest): with lazy vs stack because it needs to know sort of the layout of all the different items so it knows like, how many am I showing on this first page?

[00:18:34] Ben Scheirman (guest): So if you, if you look at LazyVStack and you, and you try to chain like a task modifier or a, an appear modifier onto an element, you may be surprised that it gets called right away, even though it's the last item in the

[00:18:46] Leo Dion (host): Okay.

[00:18:47] Ben Scheirman (guest): And so like something like an auto paging to the next page in Pure Swift UI, one way to implement this would be to have your, for each, with all the items in 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, the fetch for the next page of content.

[00:19:09] Ben Scheirman (guest): And so the idea is you get to the bottom, it loads, you get to the bottom, it loads again. So with LazyVStack, because it was trying to like probe to see how many items it could fit on the page, I got my appear modifier right away and I

[00:19:20] Ben Scheirman (guest): loaded the page number two Right, away. And

[00:19:22] Leo Dion (host): Yeah.

[00:19:23] Ben Scheirman (guest): so it was, it was like just kind of frustrating 'cause there, there wasn't a lot that I could do

[00:19:29] Ben Scheirman (guest): to I, I'm sure there's maybe a different approach I could take, but so that was one issue.

[00:19:34] Ben Scheirman (guest): Performance on these lists was not, I. Fantastic when we did just some initial tests of like infinitely scrolling lists. But I still wanted to use Swift UI for the content of the cells. So I was thinking like, let's make a collection view

[00:19:46] Ben Scheirman (guest): driven skeleton, where all, all the, all the meat is Swift UI and and Apple provided UIHostingconfiguration.

[00:19:56] Ben Scheirman (guest): It, and I feel like a lot of people, myself included, just kind of avoided all those modern collection view APIs that were like, here's a sales content configuration. And instead of, instead of like unsetting things in the wheel display cell and then there, there was like prepare for reuse that you could override on a cell subclass.

[00:20:19] Ben Scheirman (guest): You would have to like unset everything that you set before. You know, like if, if, if there was a label, like say a subtitle label.

[00:20:26] Ben Scheirman (guest): And one of the elements didn't have a subtitle and you just skipped over setting it. Well, then if that gets reused, it would just inherit the

[00:20:31] Ben Scheirman (guest): value from the previous one.

[00:20:33] Ben Scheirman (guest): So, you know, like there was stuff like that that, that apple was trying to make better and they, they implemented that cell content configuration and background configuration

[00:20:44] Ben Scheirman (guest): and there's stuff about

[00:20:45] Ben Scheirman (guest): updating the

[00:20:45] Ben Scheirman (guest): state when

[00:20:46] Ben Scheirman (guest): somebody hovers or, or presses and holds or whatever.

[00:20:49] Leo Dion (host): wanna say like of all the things that like Apple has updated on UIKit, it's been collect collection view, you could just see that's still a keynote, or not keynote, but maybe like

[00:20:59] Leo Dion (host): primary piece of UIKit that's constantly being improved. So yeah, I'm not surprised by that.

[00:21:05] Ben Scheirman (guest): yeah. And it's it's complex and

[00:21:08] Ben Scheirman (guest): I,

[00:21:09] Ben Scheirman (guest): I don't love the

[00:21:10] Ben Scheirman (guest): APIs that. Because they just, they don't just

[00:21:13] Ben Scheirman (guest): like come naturally. It's, this is

[00:21:15] Ben Scheirman (guest): a, a component that has been iterated on a bunch, but they

[00:21:18] Ben Scheirman (guest): also have to like have backward compatibility. But so I mentioned the content configuration stuff. They added a UIHostingconfiguration where if your entire content comes from a

[00:21:28] Ben Scheirman (guest): single cell,

[00:21:29] Ben Scheirman (guest): sorry, single Swift UI view,

[00:21:31] Ben Scheirman (guest): then you can set the cells content configuration to a UIHostingconfiguration and give it a Swift UI view.

[00:21:38] Ben Scheirman (guest): And now you've got Swift UI cells inside of a collection view.

[00:21:42] Ben Scheirman (guest): So we implemented that, I, I did it in a test with an infinite list of like just random emoji basically, and gradients and images and stuff. So I could scroll through and 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.

[00:21:59] Ben Scheirman (guest): I never want them to see a loading row at the end.

[00:22:02] Leo Dion (host): Right.

[00:22:02] Ben Scheirman (guest): would like it to be like, if you're scrolling down and you're like certain number of screen lengths from the bottom, like the fetch more content. And I know collection view has a way to like prefetch Prefetch rows or something like that. I'm trying to remember the API for that.

[00:22:17] Ben Scheirman (guest): But anyway, so this lets me do it because now I have access to the collection view because I have access to the collection

[00:22:22] Ben Scheirman (guest): view. I also have access to the raw content, offset content inset.

[00:22:28] Ben Scheirman (guest): And there's another one called

[00:22:30] Ben Scheirman (guest): it's not, is Active.

[00:22:32] Ben Scheirman (guest): It's on scroll view. I can look it up in a minute, but,

[00:22:34] Ben Scheirman (guest): So what it is, is, is so like how do you know if you, let's say you're Swift UI and you have a binding to a content and set property, right, which is a float.

[00:22:43] Ben Scheirman (guest): And you, and you might think that that's all you need to do, pull to refresh, right? Like, if I pull down that content, inset becomes positive,

[00:22:53] Ben Scheirman (guest): right? Because as you scroll through the normal content, the content inset becomes negative, right? There's our content content offset.

[00:22:59] Ben Scheirman (guest): So

[00:22:59] Ben Scheirman (guest): or maybe I have that reverse.

[00:23:00] Ben Scheirman (guest): I, I don't remember. So you pull down

[00:23:04] Ben Scheirman (guest): and the,

[00:23:07] Ben Scheirman (guest): The pulter refresh thing is going 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 then I scroll down really fast. You'll get that bouncing rubber banding behavior when you hit the top, right?

[00:23:22] Ben Scheirman (guest): I don't want that behavior to show the partial pull to refresh

[00:23:27] Ben Scheirman (guest): logic,

[00:23:29] Ben Scheirman (guest): Right, I only want it to, when your fingers down is tracking, sorry, is tracking is the name of the property on scroll view. So scroll views is tracking, tells you if the user's finger is on the scroll

[00:23:40] Ben Scheirman (guest): view. And so this is how you can implement that preventing rubber banding from also showing your pull to refresh logic.

[00:23:47] Ben Scheirman (guest): But also like if you want a release to refresh. Part of the pulter refresh cycle, that's also useful. So you

[00:23:56] Ben Scheirman (guest): can, you can do all that. And so I take all those values, I bundle 'em up into a struct and I send them to Swift U iland, and then all of a sudden my pulter refresh is like mega easy to implement.

[00:24:06] Ben Scheirman (guest): I can, I can customize it however I want. I've got a progress for how far you have to drag, which I use to animate like a little line that spreads across the, the

[00:24:16] Ben Scheirman (guest): header. And when, when that line touches the edges, that's when you're reloading.

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

[00:24:20] Ben Scheirman (guest): 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.

[00:24:29] Ben Scheirman (guest): And I had to do my own like compositional layout, which, you know, I thought maybe I would never have to do that stuff again.

[00:24:35] Ben Scheirman (guest): But turns out it was really important. Now, the benefit of this approach, despite it being a lot more code. Is we, this will never change, right? Like Apple can change their mind on how lists work or whatever, but this is our component.

[00:24:48] Ben Scheirman (guest): We can decide to, you know, ditch it in the future if the apple comes up with something better. But the, like, for instance, the scroll view stuff in iOS 18, it's gonna be two more years before we can use it. So in that time, I need to be able to make some progress on it.

[00:25:05] Exploring iOS 18 Scroll View API
---

[00:25:05] Ben Scheirman (guest): Also, I don't think that

[00:25:07] Ben Scheirman (guest): the is tracking touchdown, you know, logic is part of that new iOS 18 scroll view, API.

[00:25:13] Ben Scheirman (guest): And so you would probably still need to have some sort of UI view

[00:25:16] Ben Scheirman (guest): representable, which was, which was tracking touches

[00:25:19] Ben Scheirman (guest): down, touches began, or whatever.

[00:25:21] Ben Scheirman (guest): Just to know. So I think it would be possible and probably be cleaner, and I always say teen, but still I don't think goes all the

[00:25:26] Ben Scheirman (guest): way that we that to meet our needs.

[00:25:29] Leo Dion (host): Do you like, how do,

[00:25:30] SwiftUI vs UIKit: Productivity and Constraints
---

[00:25:30] Leo Dion (host): you look at a piece of code and figure out so I guess if you have a new view, If it does what you

[00:25:36] Leo Dion (host): want it to do, you would go with swift y pretty much, or try to go to Swift UI as much as possible.

[00:25:42] Ben Scheirman (guest): If I find it to be far more productive

[00:25:45] Ben Scheirman (guest): than, UIKit and especially like, I haven't used storyboards in a long time. I sort of

[00:25:49] Ben Scheirman (guest): saw that, that like w wasn't what I wanted. And, and so I was like, got used to writing constraints by hand and I, I sort of, I can kind of get a sense for what's going on when

[00:26:01] Ben Scheirman (guest): I see

[00:26:01] Ben Scheirman (guest): constraints. But nowadays when I look at 'em, I'm like, this is a lot of code to express something pretty

[00:26:05] Ben Scheirman (guest): simple.

[00:26:06] Ben Scheirman (guest): And,

[00:26:07] Ben Scheirman (guest): And, there's,

[00:26:08] Ben Scheirman (guest): I won't say there's no

[00:26:09] Ben Scheirman (guest): scenario that Swift UI just can't

[00:26:12] Ben Scheirman (guest): handle that constraints can, but there's

[00:26:15] Ben Scheirman (guest): very few,

[00:26:16] Leo Dion (host): right?

[00:26:17] Ben Scheirman (guest): I, I, remember seeing a challenge. Somebody's like, oh, somebody

[00:26:20] Ben Scheirman (guest): implement this in UIKit, and I watched Chris eof do it

[00:26:24] Ben Scheirman (guest): and he couldn't. And so if if Chris eof

[00:26:26] Ben Scheirman (guest): can't do it, then I certainly can't it probably can't be done.

[00:26:30] Leo Dion (host): 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.

[00:26:38] Design and Engineering Collaboration
---

[00:26:38] Leo Dion (host): If your design team comes up with something that's oh my

[00:26:40] Leo Dion (host): gosh, this is do you have any wiggle room to be like, you know what? We could easily do this in Swift UI if we

[00:26:46] Leo Dion (host): don't do this, and this.

[00:26:47] Leo Dion (host): Do you have

[00:26:48] Leo Dion (host): any

[00:26:49] Ben Scheirman (guest): Implementation costs and difficulty and complexity and stuff like that is definitely, it's a definitely

[00:26:54] Ben Scheirman (guest): conversation and we just, sometimes designers aren't aware

[00:26:58] Leo Dion (host): great.

[00:26:59] Ben Scheirman (guest): of, of, like, what are the

[00:27:01] Ben Scheirman (guest): standards on iOS? What, what is

[00:27:02] Ben Scheirman (guest): free and what costs 10 grand? You

[00:27:05] Ben Scheirman (guest): know what I mean? And so like

[00:27:07] Ben Scheirman (guest): if, if that's not important to them or they're like, oh,

[00:27:10] Ben Scheirman (guest): I, you know, I just put that

[00:27:11] Ben Scheirman (guest): in there because it looked good, Or whatever.

[00:27:14] Ben Scheirman (guest): But there are gonna be

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

[00:27:19] Ben Scheirman (guest): And so, but there are gonna be

[00:27:21] Ben Scheirman (guest): things that, that designers will be like,

[00:27:22] Ben Scheirman (guest): no, this is a primary interaction or animation that, that is gonna like, make our app feel more fluid or whatever. And it's

[00:27:29] Ben Scheirman (guest): worth that time to invest it. I feel like the design and engineering

[00:27:32] Ben Scheirman (guest): should always be two way conversation and it

[00:27:34] Ben Scheirman (guest): shouldn't be a

[00:27:35] Ben Scheirman (guest): handoff,

[00:27:36] Ben Scheirman (guest): right?

[00:27:36] Ben Scheirman (guest): Because there are things that come up that you're like, Hey, actually now that I'm in

[00:27:40] Ben Scheirman (guest): it, I realize that this is gonna be really tricky because when you scroll, this other

[00:27:44] Ben Scheirman (guest): thing comes on top. And

[00:27:46] Ben Scheirman (guest): So so you have to

[00:27:47] Ben Scheirman (guest): kind of come up with those solutions and workarounds and trade-offs. And

[00:27:50] Ben Scheirman (guest): I think

[00:27:51] Ben Scheirman (guest): that implementation

[00:27:52] Ben Scheirman (guest): cost is a hundred percent part of

[00:27:53] Ben Scheirman (guest): that conversation.

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

[00:28:15] Leo Dion (host): So there's always gonna be another layer removed from that abstraction to always customize things anyways. Right. So it's it's just a be like you said,

[00:28:23] Leo Dion (host): is it worth the $10,000 to do it like it might be, I don't know. Yeah.

[00:28:30] Ben Scheirman (guest): Yeah. And I think, you know, I'm, I'm just becoming more comfortable with that

[00:28:33] Ben Scheirman (guest): decision of like, it's I used to get frustrated, like there should be a way

[00:28:38] Ben Scheirman (guest): to do this in pure swift ey. And sometimes those

[00:28:40] Ben Scheirman (guest): involve really complicated

[00:28:43] Ben Scheirman (guest): solutions that involve preference keys and geometry readers

[00:28:47] Ben Scheirman (guest): and like.

[00:28:48] Ben Scheirman (guest): You know, to do something simple like I need to know how big

[00:28:51] Ben Scheirman (guest): this frame is so that I can replicate that size in a different place, in a different view hierarchy, right? So like doing preference keys for that.

[00:28:59] Ben Scheirman (guest): I, I still feel like, the preference key system, it's like

[00:29:03] Ben Scheirman (guest): for people who don't watch all the videos and like read all the articles and stuff like that, people who are just sort of doing their job, I don't think people really understand how this works.

[00:29:15] Ben Scheirman (guest): And so

[00:29:16] Ben Scheirman (guest): as soon as you start seeing preference keys,

[00:29:19] Ben Scheirman (guest): like this preference construct and extending environment values or preference

[00:29:23] Ben Scheirman (guest): you know, all those different like Swift UI

[00:29:24] Ben Scheirman (guest): things that are like, what are you trying to do? Oh, I've gotta create these three types I need to extend to this

[00:29:29] Ben Scheirman (guest): thing. I think that kind of gets lost 'cause it is kind of

[00:29:32] Ben Scheirman (guest): complex.

[00:29:33] Ben Scheirman (guest): And so like some of

[00:29:34] Ben Scheirman (guest): the pure Swift UI solutions aren't quite as clean as you would hope they would be anyway.

[00:29:38] Leo Dion (host): I also wanted to chat a bit about stages.

[00:29:43] Stages of Migrating to SwiftUI
---

[00:29:43] Leo Dion (host): Do you, so we talked about if you have a new thing, you'd try to go Swift two eyes as much as possible. Do you have stages from going from a UI view controller to a Swift UI

[00:29:53] Leo Dion (host): view, or is it just kinda like we're just gonna rewrite this as a Swift UI

[00:29:58] Leo Dion (host): view?

[00:29:58] Leo Dion (host): I'll give you an example. For instance,

[00:30:01] Leo Dion (host): like. When it comes to like Objective-C to

[00:30:03] Leo Dion (host): Swift, like the first step is to you know, maybe have ui te U unit tests

[00:30:09] Leo Dion (host): perhaps. It might be adding syntactic sugar to the Objective-C so that you can specify whether something is nil or what generic type it is.

[00:30:19] Leo Dion (host): And then maybe I might create like an NS object class NS object. Even though you'd wanna do a sw, like a struct, at some point you might

[00:30:26] Leo Dion (host): do like a class that derives from NS object, so that way it can be

[00:30:30] Leo Dion (host): taken still ingested from Objective-C while still

[00:30:33] Leo Dion (host): being written in a swift, you know what I mean?

[00:30:35] Leo Dion (host): Are there stages you can split up a

[00:30:38] Leo Dion (host): migration?

[00:30:40] Ben Scheirman (guest): So I think that some of the things I've been talking about are both changing the architecture

[00:30:45] Ben Scheirman (guest): and the UI

[00:30:46] Ben Scheirman (guest): paradigm, right? Because you also have to consider like, how does the data flow into this system? And

[00:30:51] Ben Scheirman (guest): if it's like interactable, how does that data come back out and mutate your

[00:30:54] Ben Scheirman (guest): model? And in UIKit, that's usually very

[00:30:57] Ben Scheirman (guest): different than a Swift

[00:30:58] Ben Scheirman (guest): ui. Bindings can help a lot there

[00:31:01] Ben Scheirman (guest): You know, because you can, you know, pass a mutable reference to a thing, into a binding, and then

[00:31:07] Ben Scheirman (guest): the edit screen, for

[00:31:08] Ben Scheirman (guest): instance, can mutate it. And then when you hit back, when you go back, it's already done.

[00:31:14] Ben Scheirman (guest): That sort of thing.

[00:31:14] Ben Scheirman (guest): But I think, you know, if you're just sort of trying to

[00:31:17] Ben Scheirman (guest): start small and work from from the inside out is probably the best approach if you're not trying to

[00:31:23] Ben Scheirman (guest): also improve the architecture as you go. So so if you imagine like I keep going back to the Mastodon example because I think most people are familiar with like social apps favoring an item, right?

[00:31:34] Ben Scheirman (guest): So like,

[00:31:35] Ben Scheirman (guest): say you tap on the star and it does a little dance,

[00:31:38] Ben Scheirman (guest): I don't know, do that in swifty y and put that in your UI table view cell and that's, you know, one step closer. You know, over time you'll get more confident to take larger leaps. Like maybe the whole cell becomes Swift UI before the, the surrounding screen becomes.

[00:31:57] Leo Dion (host): Yeah, it, that reminds me of the whole thing with like

[00:31:59] Leo Dion (host): navigation too, where it was like yeah, I mean, you want at the outside, you want that app

[00:32:05] Leo Dion (host): delegate

[00:32:06] Leo Dion (host): still, and then you have a hosting controller, and then you could deal with navigation that way as opposed to the other way where it's yeah, you're just gonna have an

[00:32:13] Leo Dion (host): application and then work like, yeah, I think that makes total

[00:32:16] Leo Dion (host): sense.

[00:32:17] Leo Dion (host): You start with the

[00:32:17] Leo Dion (host): smallest piece on the inside and then

[00:32:19] Leo Dion (host): working

[00:32:19] Ben Scheirman (guest): really tricky.

[00:32:21] Leo Dion (host): it is really

[00:32:21] Leo Dion (host): tricky.

[00:32:22] Ben Scheirman (guest): when you're mixing. I, I think it's tricky

[00:32:24] Ben Scheirman (guest): in

[00:32:24] Ben Scheirman (guest): general.

[00:32:25] Ben Scheirman (guest): I am not a fan

[00:32:27] Ben Scheirman (guest): of the,

[00:32:28] Ben Scheirman (guest): the approach

[00:32:29] Ben Scheirman (guest): that

[00:32:29] Ben Scheirman (guest): view controllers know that they need

[00:32:31] Ben Scheirman (guest): to push the next view controller in the chain. Like in a navigation controller,

[00:32:35] Ben Scheirman (guest): Scenario, it means that your view controller knows

[00:32:39] Ben Scheirman (guest): it's embedded

[00:32:40] Ben Scheirman (guest): in a navigation controller,

[00:32:42] Ben Scheirman (guest): which

[00:32:42] Ben Scheirman (guest): it shouldn't shouldn't know.

[00:32:44] Ben Scheirman (guest): Rou, Klu has this

[00:32:45] Ben Scheirman (guest): amazing

[00:32:46] Ben Scheirman (guest): quote,

[00:32:47] Ben Scheirman (guest): I think it was at NS Spain in like,

[00:32:49] Ben Scheirman (guest): I dunno, a long time ago.

[00:32:50] Ben Scheirman (guest): He said

[00:32:52] Ben Scheirman (guest): children

[00:32:52] Ben Scheirman (guest): shouldn't tell their parents what to do.

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

[00:32:56] Ben Scheirman (guest): software and in software,

[00:32:58] Ben Scheirman (guest): he would

[00:32:59] Ben Scheirman (guest): argue That children know shouldn't know

[00:33:01] Ben Scheirman (guest): who their parents are.

[00:33:02] Leo Dion (host): Yeah,

[00:33:03] Leo Dion (host): that is

[00:33:03] Ben Scheirman (guest): And it's like, it's a good

[00:33:06] Ben Scheirman (guest): sort of, I think about this a lot because this

[00:33:08] Ben Scheirman (guest): is kind of where the

[00:33:09] Ben Scheirman (guest): coordinator pattern came out, where you have these view controllers that can be

[00:33:12] Ben Scheirman (guest): embedded

[00:33:14] Ben Scheirman (guest): in different contexts if you needed. But the point is, is they don't know how 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. And what, what That allows you to do is avoid the

[00:33:27] Ben Scheirman (guest): situation where, say you have A, B and C view controllers, and the C

[00:33:32] Ben Scheirman (guest): view controller has a couple

[00:33:34] Ben Scheirman (guest): dependencies. So now A needs to create and push B. B needs to create and push C, but B doesn't have C'S dependencies to pass along. And so you either you. Sort of what I would

[00:33:47] Ben Scheirman (guest): consider anti-patterns, which is like static service

[00:33:50] Ben Scheirman (guest): lookup and where C says, Hey, give me my global dependency for this. I don't know terms of service fetcher or whatever.

[00:33:58] Ben Scheirman (guest): I, I much prefer the dependency injection approach, but B doesn't need that and shouldn't even know it exists, right? So it's a dependency problem where, where I think that these controllers create in creating themselves or creating their siblings is kind of a pattern that I don't like in, in UI kids.

[00:34:14] SwiftUI Navigation and Environment Bindings
---

[00:34:14] Ben Scheirman (guest): So this is why, I mean, that navigation is hard and navigation in Swift UI is, has similar problems, but I think that that can be smoothed over by the fact that you can put things in the environment and then you can go three levels farther and then pull them outta the environment.

[00:34:31] Ben Scheirman (guest): So you don't necessarily have to carry them along each step of the way.

[00:34:34] Ben Scheirman (guest): But the problem that, that I see is that

[00:34:36] Ben Scheirman (guest): like the, the model for Swift UI navigation is. Either a binding to a Boolean of whether or not a thing is presented

[00:34:45] Ben Scheirman (guest): or a binding to a, an array of path elements which identify the items being presented. So like when this path element has a value of the a user, I'm gonna present the user edit

[00:34:56] Ben Scheirman (guest): screen.

[00:34:56] Ben Scheirman (guest): I like that sort of decorative model based approach because then when the user dismisses the screen, that binding gets set back to nil, meaning nothing is presented.

[00:35:07] Ben Scheirman (guest): But in UIKit, you don't have that. You just have push and

[00:35:09] Ben Scheirman (guest): pop and there's no way for you to tell, for instance, if you, if you want model this since if Youi, but then part of this is a UIKit view hierarchy,

[00:35:19] Leo Dion (host): Yeah.

[00:35:19] Ben Scheirman (guest): it becomes difficult.

[00:35:20] Ben Scheirman (guest): Like how do you, how do you present something in UIKit and then bubble up the fact that they dismissed to a Swift UI binding so that it can

[00:35:29] Ben Scheirman (guest): be modeled appropriately in Swift UI. And I found, or I, I was introduced to this idea from the point free video series. They have a recent series on UIKit, sort of building observable models and sort of adapting Swift UI tools to UIKit and it's really, really great series.

[00:35:52] Ben Scheirman (guest): And they implemented a on dnet class that holds onto a closure.

[00:35:59] Ben Scheirman (guest): And then you assign that on dnet handler as an associated

[00:36:04] Ben Scheirman (guest): object. So you're going way back to Objective-C runtime, trickery set that as an associated object on the view controller. And that way you don't have to touch the view controller that you're presenting at all.

[00:36:15] Ben Scheirman (guest): It doesn't need any new

[00:36:16] Ben Scheirman (guest): API, it just has this this extra bit of state that is attached to it by the Objective-C runtime system. And so for folks that aren't aware there is a Objective-C like

[00:36:30] Ben Scheirman (guest): BJC associated value and get associated value,

[00:36:34] Leo Dion (host): you

[00:36:35] Leo Dion (host): can deep dive into the object and do whatever the heck you want with it. Yeah,

[00:36:38] Ben Scheirman (guest): yeah. And so like this is a way to like sort of piggyback some storage onto the, onto the lifecycle of another object. And

[00:36:45] Ben Scheirman (guest): so what, what you would do there is you just assign this on DNA

[00:36:49] Ben Scheirman (guest): helper as an associated object. And then when that view controller goes away, it clears out that on

[00:36:55] Ben Scheirman (guest): dnet object that you just set. And so the idea is that in the, in the Dnet

[00:36:59] Ben Scheirman (guest): of the on Dnet helper, you execute the closure.

[00:37:03] Ben Scheirman (guest): So that gives you

[00:37:04] Ben Scheirman (guest): a hook that you can

[00:37:05] Ben Scheirman (guest): apply to

[00:37:05] Ben Scheirman (guest): any UI

[00:37:06] Ben Scheirman (guest): view controller.

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

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

[00:37:09] Leo Dion (host): ahead.

[00:37:10] Ben Scheirman (guest): So the idea

[00:37:10] Ben Scheirman (guest): there

[00:37:11] Ben Scheirman (guest): is

[00:37:11] Ben Scheirman (guest): that you that's where you

[00:37:12] Ben Scheirman (guest): set the binding back

[00:37:13] Ben Scheirman (guest): to, to is presented false or nailing out the, the presented model whatever your binding

[00:37:19] Ben Scheirman (guest): is.

[00:37:19] Ben Scheirman (guest): There's, there's those two different flavors of one that is just a true false and one that takes like an item.

[00:37:24] Leo Dion (host): I was just thinking back to any work I've done with web development, I've, I still do some like VJS stuff and like some type script and I'm like, how did they do navigation? And then I was like, well, either the

[00:37:37] Leo Dion (host): parent is responsible for it or uses the URL and I'm like, that sounds a lot more like what you were saying about using the path thing,

[00:37:44] Leo Dion (host): right?

[00:37:44] Leo Dion (host): Where you have an enum of the path and you have an environment variable. It's like that's basically what that

[00:37:49] Leo Dion (host): Is

[00:37:50] Ben Scheirman (guest): The url, the ur l can be constructed to say, Hey, I handle all

[00:37:53] Ben Scheirman (guest): slash admin.

[00:37:55] Leo Dion (host): Right?

[00:37:56] Leo Dion (host): Right.

[00:37:56] Ben Scheirman (guest): And from that point onward. And then from inside of admin, you have admin slash users

[00:38:00] Ben Scheirman (guest): or whatever, and that

[00:38:00] Ben Scheirman (guest): can, and then

[00:38:01] Ben Scheirman (guest): that one has a sub route of user slash

[00:38:03] Ben Scheirman (guest): you know,

[00:38:04] Ben Scheirman (guest): 25.

[00:38:04] Leo Dion (host): And you almost. You could kind of do that,

[00:38:07] Leo Dion (host): right? You

[00:38:08] Leo Dion (host): sort of could do that with

[00:38:08] Ben Scheirman (guest): can do

[00:38:09] Ben Scheirman (guest): that in Swift UI.

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

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

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

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

[00:38:22] Leo Dion (host): Yes it

[00:38:22] Leo Dion (host): is.

[00:38:23] Ben Scheirman (guest): but it does work. The,

[00:38:25] Ben Scheirman (guest): But I, I like the

[00:38:26] Ben Scheirman (guest): path element approach that

[00:38:28] Ben Scheirman (guest): navigation stack uses in iOS

[00:38:30] Ben Scheirman (guest): 16.

[00:38:31] Ben Scheirman (guest): So, so the Swift UI binding to that item

[00:38:34] Ben Scheirman (guest): that you can, you can mutate because some other UIKit thing did a D

[00:38:40] Ben Scheirman (guest): in it is really, really helpful And allows us to do things

[00:38:43] Ben Scheirman (guest): like, we have a,

[00:38:45] Ben Scheirman (guest): Flow that you have to go through as like, sort of like

[00:38:48] Ben Scheirman (guest): onboarding. And this has to be checked every time you log in. And we need to make sure that your

[00:38:54] Ben Scheirman (guest): locale is in a supported locale,

[00:38:56] Ben Scheirman (guest): For. For like the markets that we're, that we operate in and that you've agreed to,

[00:39:00] Ben Scheirman (guest): to, or I've, you've confirmed on like a mobile number.

[00:39:03] Ben Scheirman (guest): So there's a bunch of sort of checks and it goes

[00:39:05] Ben Scheirman (guest): through this state machine,

[00:39:07] Leo Dion (host): Yeah.

[00:39:08] Ben Scheirman (guest): to say like, okay, I'm gonna go from here to here, I'm gonna check that and if it's not there, I need to pause here, present some ui, let the user go through that flow and then, and then come back to that spot. And that is a pure swift just model

[00:39:19] Ben Scheirman (guest): of model of the, of the walkthrough the user has to go through.

[00:39:24] Ben Scheirman (guest): So knowing when they're done with a particular flow that is in UIKit and those components are built by another team that we don't influence, that is really handy to be able to, to do

[00:39:35] Ben Scheirman (guest): that sort of thing without having

[00:39:36] Ben Scheirman (guest): to

[00:39:36] Ben Scheirman (guest): wrap in a parent view controller,

[00:39:38] Ben Scheirman (guest): you know, without having to do a PR on that particular component. So,

[00:39:44] Retain Cycles and Memory Management
---

[00:39:44] Ben Scheirman (guest): The other thing though, that's really, really important, I think it's really easy to, I. For or not realize that you have retained cycles in a view

[00:39:51] Ben Scheirman (guest): controller,

[00:39:52] Ben Scheirman (guest): which would lead to that view controller never being deallocated. And then, then your

[00:39:56] Ben Scheirman (guest): on DN net

[00:39:56] Ben Scheirman (guest): would never get called. Yeah. If you're using like,

[00:39:59] Ben Scheirman (guest): Combined subscriptions and you do like dot assigned to inside of a

[00:40:03] Ben Scheirman (guest): view did load which it's just so easy to do, it's so tempting to do that.

[00:40:07] Ben Scheirman (guest): But

[00:40:07] Ben Scheirman (guest): that if, if you if you assign to anything,

[00:40:11] Ben Scheirman (guest): it's basically calling self

[00:40:13] Ben Scheirman (guest): value equals new value and capturing that self. And so if the self is holding onto the subscription and the

[00:40:22] Ben Scheirman (guest): subscription's holding onto

[00:40:22] Ben Scheirman (guest): self, then

[00:40:22] Ben Scheirman (guest): that view controller just never goes away. Right. This is a

[00:40:25] Ben Scheirman (guest): common, common

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

[00:40:30] Leo Dion (host): What can you

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

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

[00:40:33] Ben Scheirman (guest): some way of breaking that. Yeah. And then the, the real answer is usually just

[00:40:38] Ben Scheirman (guest): do a

[00:40:38] Ben Scheirman (guest): sync

[00:40:39] Ben Scheirman (guest): and in the sink closure do weak self, so that way you're

[00:40:42] Ben Scheirman (guest): never capturing

[00:40:42] Ben Scheirman (guest): self. But yeah, I think just knowing what, what, a retain cycle looks like, you should be able to spot it pretty quick with closures, right?

[00:40:50] Ben Scheirman (guest): Like it

[00:40:52] Ben Scheirman (guest): I think with async

[00:40:53] Ben Scheirman (guest): streams, this is also a big problem, that it's not always obvious that you're retaining self,

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

[00:40:58] Ben Scheirman (guest): Especially because tasks have an implicit self.

[00:41:01] Ben Scheirman (guest): So it's like you can just call methods directly. And so I think it can hide,

[00:41:05] Ben Scheirman (guest): Retained cycles. So I would definitely say.

[00:41:08] Ben Scheirman (guest): Use the you know, use a memory graph, debugger. There are some other tools you could use, like

[00:41:13] Ben Scheirman (guest): Christophe Slosky has a tool called Lifetime

[00:41:16] Ben Scheirman (guest): Tracker, which you can say like, Hey, I only ever want one of these screens to be created, ever one of these few

[00:41:23] Ben Scheirman (guest): And so basically it asserts, it creates like a

[00:41:25] Ben Scheirman (guest): global counter and it asserts if you ever get more than your,

[00:41:29] Ben Scheirman (guest): your, so for instance, like user profile

[00:41:32] Ben Scheirman (guest): controller, there should literally only ever be

[00:41:34] Ben Scheirman (guest): one ever. And if there's ever two crash

[00:41:36] Leo Dion (host): Yeah.

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

[00:41:40] Ben Scheirman (guest): things early.

[00:41:42] Leo Dion (host): Yeah, yeah, totally. Yeah, that's Awesome. We'll put links to all that stuff too in the show notes so People can look that up.

[00:41:49] Leo Dion (host): Well Ben, thank you so much for joining me for today's episodes. We'll be talking more in the second part about Swift UI and UIKit and migration, as well as some stuff about Swift packages. So be sure to be on the lookout for that well.

[00:42:03] Leo Dion (host): Ben, where can people find you online?

[00:42:06] Ben Scheirman (guest): You can find me. My

[00:42:07] Ben Scheirman (guest): website is ben Scheirman.com and,

[00:42:10] Ben Scheirman (guest): I'm on Mastodon at ben And yeah, my website will have links to NSScreencast and Combined Swift and some of the other apps I work on. I.

[00:42:19] Leo Dion (host): Awesome. People can find me on Twitter company is Bright Digit. If you're looking for a developer Apple space, please reach out to me. You can find me on Macon at Leo Dion CI am. If you enjoy this episode, watching this on video it's please, and subscribe. I greatly appreciate it.

[00:42:37] Leo Dion (host): And if you're listening to this on a podcast player, gimme a review. Thank you so much. I look forward

[00:42:42] Leo Dion (host): to talking to you in the next half of this episode. Bye everybody.