All Episodes

July 13, 2025 22 mins

Peter and Geoff dive into their favorite WWDC25 APIs. Peter explores the new attributed text editing features in SwiftUI, while Geoff breaks down interactive snippets and updates to App Intents. A dev-focused episode packed with practical insights and examples.


AttributedString Code Snippet

Button(

    action: {

        resumeContent.transformAttributes( in: &selectedText ) { container in

            let currentFont = container.font ?? .default

            let resolved = currentFont.resolve(in: fontResolutionContext)

            container.font = currentFont.bold(!resolved.isBold)

        }

    },

    label: {

        Text("B")

            .foregroundColor(Color.white)

            .bold()

    }

)


Links

Code-Along: Cook up a rich text experience in SwiftUI with AttributedString

Explore new advances in app Intents

Podcast Episode on App Intents

https://cocoatype.com

https://peterwitham.com

Share your thoughts with us
https://compileswift.com/contact

Become a Patreon member and help this Podcast survive
https://www.patreon.com/compileswift

Follow us on Mastodon
https://iosdev.space/@Compileswift

Thanks to our monthly supporters
  • flanker
  • Jay Wilson
  • Adam Wulf
  • bitSpectre
★ Support this podcast on Patreon ★
Mark as Played
Transcript

Episode Transcript

Available transcripts are automatically generated. Complete accuracy is not guaranteed.
Geoff (00:00):
Yes. You do. You did a whole stream about it, and
everybody thought it was cool,and you built an app.

Peter (00:07):
What's up, folks? Welcome to the CompileSwift podcast. In
this episode, we are gonna betalking about some code things.
In particular, we have pickedsome some of the APIs, I guess
you would say, of interest fromdub dub d c twenty five this
year. I'm gonna kick things offhere with my first one.
But first of all, Gfoff, how aredoing, buddy?

Geoff (00:26):
I'm doing just great, Peter. Things have been going
well pretty recently. How aboutyou?

Peter (00:31):
Yeah. Pretty good. The the bonus effect here is not
only did I have to do myhomework for this, but I got to
add a feature to my Job Findertracker app that actually needed
this API. So I got a two for onedeal out of this. So I'm really
happy this week.

Geoff (00:49):
Yeah. Perfect. Let's hop into it. What'd you what'd you
discover?

Peter (00:52):
So one of the ones that I wanted to look at this year that
got my attention way back in dubdub d c '25 was the attributed
string and how we can now usethat in an editor in SwiftUI. So
what am I talking about here?Well, for a few versions now, I
think it was iOS 15, where youcan display, you know, text. If

(01:13):
you're SwiftUI, you'll befamiliar with this. Right?
Put on text. Put put a string init, and it will happily show you
attributed text. Think of thingslike rich text. Right? However,
jump through a few hoops to beable to edit it.
And in my case, I was using athird party library to enable me

(01:34):
to do this and then, you know,use the attributed string from
there. Whereas this year, we nowhave it built into the text
editor in SwiftUI. So this issomething that I went into in
great detail, and I'm going totalk about it here. And I'm
really impressed. All right?
So basically, what happens is,if you are not familiar with

(01:56):
attributed text, the way itworks is this. Okay? Think of
your normal text string.Alright? And then if you make it
the color red or you pick aparticular word and make it
bold, those are attributes orattributes, depending on how you
pronounce it.
Now, it renders just fine, likewe say, when you are looking at
this on the screen. But to editthis and store it as a string

(02:19):
got a little interesting. Sothis year they made it simple.

And the way it works is this: So, you've got your SwiftUI text (02:22):
undefined
editor. You've got twoparameters that you can put in
there, right?
One of which, of course, is yourtext string, as usual. And the
other one that we have is aselection. And we'll dive into
these. Now, the best part aboutthis is if you don't want to do
anything fancy, Apple has madethis very easy for you. If you

(02:45):
have some text, regardless ofwhether it's plain text or
whatever, in this text editoralready, they you can just
select the piece that you want.
You're gonna get the veryfamiliar pop up bar with lots of
options on there. Now you getall the things you can imagine.
Right? Stand what I call sort ofstandard text editing. You could

(03:07):
do bold.
You know, you can strikethrough, italic. You can change
the colors, the fonts, and thefont size. You don't have to do
anything. You get that out ofthe box.

Geoff (03:18):
Awesome. So it sounds like like with a lot of SwiftUI
stuff, you're kinda just gettinga lot of it for free. You're
providing, it sounds like, somekind of binding to an attributed
string, probably an attributedstring state somewhere. You're
putting that in a text editorand then you get a lot of the UI
for free that you're gettingthat little menu with the bold,

(03:40):
italics, all the common stuff,right?

Peter (03:43):
Yep. That that is all built in, ready for you to use.
You don't have to do anything.

Geoff (03:48):
Awesome. So it sounds like oh, go ahead.

Peter (03:50):
No. No. Go

Geoff (03:51):
on. I was gonna say, so it sounds like you get kind of a
lot of the basic standard systembehavior for free. I know you
mentioned the selection argumentas well. I'm assuming that
that's kind of getting more intothe advanced stuff, where if you
want to provide some of thisfunctionality yourself?

Peter (04:06):
Yes. And the way this works I'll I'll dive into that
now, because the the beauty iswith this interface. Right? And
and once users get used to iOS26, and I should stress this
only works with iOS 26 and up.So

Geoff (04:20):
Of course.

Peter (04:20):
If you're if you're gonna use it, right, that's your
problem right there. But, let'stalk about this part here, so
this this selection. So in mycase, I have, you know, a
variable, a state variable,right, selected text of type
attributed text selection.That's important. What this does

(04:40):
is it tells the editor, okay.
This is a state theme. Right? Soanytime a user is doing
something, they're selecting thetext or interacting with it, you
know, double tapping it toselect it. All that kind of fun
stuff. It tracks that for you.
So you don't have to go find,like, you know, the range from,

(05:01):
you know, a to b or whatever.It's just gonna say the text
you've selected. Where this getsinteresting is if you want to
offer, say, your own customtoolbar. And I'm gonna give you
an example of this, a reallysimple one. Right?
But this is a really nice,obviously laid out API to use.
So let's say that you add abutton, right? And I'm not going

(05:23):
to go into detail here too much.If you know how to do a button,
you know you've got a label andan action. Okay?
So we're just gonna go withmaking something bold. Let's
just do that. Okay?

Geoff (05:36):
Yeah. No. If you've seen the list of attributes that you
can change on an attributedstring, it's ridiculous. They've
got like four or five differentblocks of them. You've got the
Swift UI, the UI kit, thefoundation, the whatever.
And then each of those has adozen or more different
attributes. So there's a lot ofthings that you can change on an
attributed string.

Peter (05:55):
Yeah. The it's a great list. I mean, I think it's got
everything in there you'reyou're likely to want to use. I
I admit I haven't you know,didn't try building my own
because I just didn't need to.Everything was there, right, for
standard text editing.
So you've got your button.Right? So let's talk about the
action. This is the part thatmatters here. Right?
So in my case here, I, I've gotmy attributed string, which is

(06:18):
resume content. So, you know, todive into the the code here,
resume content and then just dottransform attributes, and then
it's gonna expect a range. Thisis where they've done the
homework for you, because youcan just say in whatever the
name of your attributed textselection is. So in my case,

(06:40):
selected text. And it's gonnafigure all of that out for you.
So then you've just got to putthe body, which in this case
goes along these lines. Okay? Socontainer in. And then the
reason we do this is we want toget a reference to the text that
we've got here. So, for example,in my case here, let current

(07:01):
font equal container.
Font. Right? Or default, if itdoesn't have any. So now that
I've got that set up, I can takethat. I'm going to apply some
new stuff to it.
Right? So in this case, we'regoing with bold as the example.
So I've got, again, anothervariable here, let resolved

(07:21):
equal the current font, dotresolve, and then in
fontResolutionContext. And thenonce we've got that set up, all
I got to do is say container dotfont equals current font dot
whatever attribute we want toapply. In this case, bold.
And then we're just gonna say,hey, if it's not bold, make it

(07:44):
bold. Right? And if you want touse it as like a toggle button
between bold and, you know, backto normal, it's gonna take care
of for you. I know that sounds alittle bit complicated. I'll put
a code example in the shownotes.
But, basically, that is allyou've gotta do to essentially
tap in to the API to takeadvantage of making your own

(08:07):
custom toolbars. Geoff, doesthat make sense? Any questions?

Geoff (08:11):
No. That sounds like it's got a pretty powerful set of
tools that's available for you.It sounds like you can kinda get
in there, get the selection, getthe attributes for your
selection, find out a bunch ofinformation about the text that
you have there, and then be ableto manipulate it. So, I don't
know. I think that's very coolsounding.

Peter (08:29):
Yeah. Yeah. And that is all there is to it. You know,
let's say that you wanted tochange what I've just described
here to italic, for example. Allyou have to do is change the
part that matters.
So, where I said container dotfont equals current font dot
bold, all I would have to do iscontainer dot font equals

(08:50):
current font dot italic. Right?So that's where that list is
gonna work beautifully for you.If you wanna create a whole,
like, row of keys row of buttonsfor this on each one, you're
you're basically gonna do thesame thing over and over, but
just changing the attribute typeyou wanna affect. Now, I do

(09:11):
wanna talk about an extra parthere, but, basically, that is
all you need to do to use theAPI.
There's always a however or abut. And the however or and the
but on this is, if you are gonnawant to work with this as a
persistent storage, and I'mgonna guess that the likelihood

(09:32):
is you are, that's when thingsget a little interesting. And I
I gotta give a shout out to mymate, Geoff, here, who we worked
through this together. So I'musing a CoreData backend, and my
my entity for this is set todata. And there are reasons for
that.
But, Geoff, I'm gonna let youtalk about that. Tell us why we
need to use the data type forthis. So the different types

(09:56):
that you can have as fields on aCore Data entity, there's a
bunch of the primitive typeones. You've got string, you've
got booleans, you've

Geoff (10:04):
got your ints and your floats and your doubles. You've
got some slightly morecomplicated ones like dates and
UUIDs and URLs, I think, canalso go in there.

Peter (10:12):
Yep.

Geoff (10:13):
And then kind of your remaining catch all there is
data conforms to Swift data orObjective C NS data. And the
reason you want to use that hereis because you've got a pretty
easy way to turn attributedstring into data, which is
attributed string conforms toCodable. So at the very least,

(10:33):
you have the real dumb simpleanswer of you can convert it to
JSON, and you can toss that JSONdata into your data field. Now
that's probably not the mostcompact representation of it
that you can have, but it islike, here is the extremely
simple way of we just need topersist a attributed string, and

(10:54):
that that's how we're gonna doit. The more complicated way,
the probably slightly betterway, but the little bit more
finicky way, is that attributedstrings have a method on them
called exported, and you canprovide a UTI, a universal type
identifier, to them, and theycan export to a couple different
types as well there.
I think the most obvious one forthat is to use RTF, which just

(11:19):
saves it as the rich textformat. And then you can stick
that into a data field on CoreData as well. Or do whatever
else it is that you're doing,you know, if you're storing that
in SQLite or you're storing thaton just a disk as an RTF file.
All of those are options.

Peter (11:37):
Okay. So, yeah, that is using this attributed string in
the text editor in SwiftUI. I'mreally enjoying using it. It is
significantly less code thandoing it with the third party
that I was using, and with lessproblems, plus the bonus of all
the built in goodness that Applegives you. Right?

(11:59):
So, that's what I've beenlooking at here, this API. And
like I say, it solved a bigproblem for a feature for me.
Now I just gotta wait for themto release the OS so I can
release my update. So, let melet me throw it across the fence
here. Geoff, go for it.
Hey, folks. If you like whatyou're hearing in this podcast
and you wanna help this podcastto continue going forward and

(12:20):
having great guests and greatconversations, I invite you to
become a Patreon supporter. Youcan go to
patreon.com/compileswift, whereyou will get ad free versions of
the podcast along with othercontent.

Geoff (12:34):
So what I've been looking into, I haven't yet been able to
build a project with. I Ihaven't really done too much yet
that is iOS 26 only so far. I'mabout to start that with Black
Eyeliner very soon. But so I'mnot gonna be able to get as
in-depth with my experience withit so far, but let me talk
through kinds of the things thatwe have available. And what I've

(12:57):
been digging into is theimprovements to AppIntense.
This is all of your integrationwith shortcuts, but also
integration with different partsof iOS and, well, all of the OSs
themselves. And I think thereally cool big new one that I'm
really, like, hunting for aplace to use is interactive

(13:18):
snippets. And what that is iswhen you run a shortcut,
especially if you're running ashortcut in the background, it
gives you the ability to put upa view, almost like a micro view
of your app. And it's nowinteractive in iOS 26, where you
can actually have a user tap abutton or take an action, and

(13:41):
that action actually doessomething. Now, it's a little
bit limited in the UI.
If you're familiar at all withbuilding interactive widgets,
which I think we've been able todo for about two years now, it
uses a lot of the samelimitations as that, which is
that you can basically say, oh,there's a button here and
hitting this button performsthis action. And the fun part is

(14:03):
this is app intents all the waydown, which is that your button
actions inside of an app intentsnippet are themselves
triggering other app intents.

Peter (14:13):
So does that imply that you can sort of chain these
things together?

Geoff (14:16):
Yeah. You could have an app intent that displays a
snippet that has a button thatthen displays another snippet.
So I believe that that it is ispossible to do that. So you can
kind of build these actions thathave this multi step UI to them.
Alternatively, another thingthat you could do that that
actually works and probably is abetter user experience is that

(14:37):
you can actually have the buttonor the action that you call
inside your snippet update thecurrent snippet.
So you can have some kind oflike semi interactive UI in
there. It's all very static. Youcan't have like sliders, for
example, that act on acompletely user interactive
basis, but you can have a buttonthat favorited a video, for

(15:00):
example, and then it updates andyou've got a little heart symbol
on that video. You can do stufflike that where it's actually
updating the snippet in realtime, but it's still kind of
just a limited peek into yourapp.

Peter (15:14):
Right. Because, I mean, I I would think, you know, you
don't wanna make these thingsoverly complex either. Right? So
I don't know. I don't knowApple's intent here.
I'm sorry. That was not anintentional pun. It I I promise
you

Geoff (15:27):
Not intentional?

Peter (15:28):
Not intentional. Yeah. Exactly. But what I was gonna
say was maybe their intentionwas to force you to keep them
simple by putting theserestrictions in place.

Geoff (15:38):
I I think it's it's somewhat keeping it simple and
somewhat and maybe even moresomewhat keeping it not very
resource intensive in verysimilar to the ways that
interactive widgets are, whichis that you don't wanna be
booting up a whole process. It'sjust kind of rendering a SwiftUI
hierarchy for you.

Peter (15:57):
Gotcha. Yeah. And and you want like you said, you know,
the idea here is the these arequick actions. Right? These are
quick things.
Yeah. Yeah. You're not like, oh,I'm gonna spend a lot of time
working with this. Right? Andand it's certainly for me, when
I think of, like, you know,widgets and intents and all
those kind of stuff, it's a veryquick, like, purpose driven
thing and I'm moving on.

(16:18):
Right? I'm not gonna live withthis thing for for a long time.

Geoff (16:21):
This is not an app that I've built for myself. This was
more of a shortcut that I builtfor myself a while back. It
requires me to enter data intothe shortcut that is displayed.
And I can imagine that if I hadan app for that, that that would
be something that I would beable to do there, which is just
very quickly kind of say, oh,I'm displaying a view from my

(16:41):
app, and I want to enter somedata, and then hit submit, for
example, and that that doessomething. Now the way that this
is done, the way that youactually interact with this is
by just returning a differenttype from your standard intent.
And so if you've got an appintent, if you ever built
anything with app intentsbefore, you know that the

(17:02):
perform action, you return aresult, and that result starts
with some intent result. Andthen you can stick a bunch of
other protocols on the end ofthat. A common one that you have
is returns value, which allowsyou to, you know, actually pass
forward another value in, like,shortcuts or something. It kinda
passes it on to the next action.You've also had for a long time

(17:24):
open intent, I believe is whatit's called, which will actually
just straight up launch yourapp.
So if you run something inshortcuts and then you're like,
oh, but I actually want this tonow, like, edit something in my
app, that's the open intent, andand it'll open your app. The one
that they're providing for thisis shows snippet. And what that
means is when you're doneperforming your action of your

(17:46):
built in original intent, yousay show snippet, and you return
the snippet type that you wantto present. And that kinda
renders, populates, puts in allyour data, all of that, and then
displays that view to the user.And so that's the way the
snippets have actually workedfor a while.
But the new thing that you'vegot in this year is that you can
have buttons that take as aparameter an action, and that

(18:10):
action is itself another intent,which works very similar to the
way that interactive widgets do.And so when the user sees that
snippet and they tap thatbutton, it then performs that
action and can do something inresponse. And if you need it to
rerender your snippet becauseyou've changed something, then
you just call a simple reloadmethod. And that causes your

(18:32):
snippet to reload with whatevernew data you have available. And
so snippets is kind of the bigone.
We did get a couple additionalthings with AppIntense this
year. They gave it some littledeveloper improvements that make
it easier for you to, like,decide what data that you have
in an intent. They added aundoable intent, which allows

(18:55):
you to, like, do something withthe user. And then if the user
goes, wait, wait, wait, hold on.There's a standard UI for having
an actual undo method.
Previously, you had the abilityto ask for confirmation and it
could say yes and no. Now youcan actually provide like
multiple choice. Lot of cool,fun, intense stuff this year.
And intense is eventually, if weever actually get it, supposed

(19:18):
to be the backbone for AppleIntelligence. But I say to
people, like, start looking intothis now because the amount of
things that it can do evenwithout Apple Intelligence being
ready yet is pretty big, andit's it's really a cool thing.
And Apple's obviously pushing itpretty hard. So, definitely look
into the improvements thatthey've made this year, and all
of the stuff that they've hadfor three or four years now.

Peter (19:40):
Well, and I think you make a good point there, right?
Because when you say, like, youknow, Apple's pushing this hard,
we've come to learn over theyears. There's usually if we
don't know now, there's a hiddenreason for it down the road.
Right.

Geoff (19:52):
I was gonna say that the big one this year that really
unlocked, I think, bunch ofstuff and will unlock even with
a lot of the snippets andwhatnot, is the fact that
intents now show up in spotlighton the Mac. So even if it's just
the Apple silicon compatibilitylayer running your iOS app
there, you have the ability tokind of like, a user can just

(20:12):
hit command space, type insomething, and then just use
your app from anywhere in thesystem very quickly. And so, you
know, it's another chance to getyour app in front of users all
over the place. So definitelylook into AppIntents. Snippets
is a cool new feature thatthey've added to it this year,
but there's a lot of cool stuffthat they've always had and will
continue to have.

Peter (20:33):
And we did some episodes on the this very subject. Right?
So, if you are wondering, well,why should I offer this in my
apps? Hey. We we got thatcovered.
Go back and check the archives.We'll tell you why it's
important and how you it'sessentially free marketing for
your app at this point. Right?

Geoff (20:51):
So, yeah, those are our two favorite APIs announced at
WWDC this year. And, obviously,that's not even beginning to
think about scratching thesurface of everything that we
got this year. There are a lotof cool things that, you know,
I've been meaning to look into,that I know Peter's been meaning
to look into, all of the newfoundation model stuff. I'm

(21:11):
particularly excited about theAlarmKit API. There's all kinds
of fun new things that are goingto be available in iOS and macOS
and all of the OS 26.
And so, a, go check outespecially all of the WWC videos
that start with what's new, andlet us know in our Discord or in

(21:33):
podcast review or by contactingus at compileswift.com, what are
your favorite APIs? What are thethings that you saw at WWDC that
you're really excited about? Andhey, maybe we'll talk about
those on a future episode.

Peter (21:46):
Also, on that note, if you've got questions or topics
that you would like to hear ustalk about and we feel like we
are suitably knowledgeable onthem, by all means, reach out
and

Geoff (21:57):
suggest Or can become suitably knowledgeable on them.

Peter (21:59):
Or can become, as we have demonstrated. It is possible for
Peter to learn something betweenrecording episodes. Let us know.
Same methods, writecompilesswift.com and all that
good stuff.

Geoff (22:09):
So, Peter, I think that's it for this episode of the
compiles swift podcast. Wherecan everybody find you?

Peter (22:14):
Yeah. You can find me at peterwitham.com. And, of course,
by now, you know where to findthis podcast. But do we know
where to find Geoff? Let's findout.

Geoff (22:23):
As as always, you can find everything that I do at
cocoatype.com.

Peter (22:26):
We hope this has been helpful, folks. If nothing else,
go what like Geoff said, gowatch the videos. Right? Because
playing with these APIs reallymakes us wanna go and look at
some more of them. It's all thethings you don't necessarily
hear too much about at theconference.
Alright, folks. That's it. Wewill speak to you in the next
episode.
Advertise With Us

Popular Podcasts

Stuff You Should Know
My Favorite Murder with Karen Kilgariff and Georgia Hardstark

My Favorite Murder with Karen Kilgariff and Georgia Hardstark

My Favorite Murder is a true crime comedy podcast hosted by Karen Kilgariff and Georgia Hardstark. Each week, Karen and Georgia share compelling true crimes and hometown stories from friends and listeners. Since MFM launched in January of 2016, Karen and Georgia have shared their lifelong interest in true crime and have covered stories of infamous serial killers like the Night Stalker, mysterious cold cases, captivating cults, incredible survivor stories and important events from history like the Tulsa race massacre of 1921. My Favorite Murder is part of the Exactly Right podcast network that provides a platform for bold, creative voices to bring to life provocative, entertaining and relatable stories for audiences everywhere. The Exactly Right roster of podcasts covers a variety of topics including historic true crime, comedic interviews and news, science, pop culture and more. Podcasts on the network include Buried Bones with Kate Winkler Dawson and Paul Holes, That's Messed Up: An SVU Podcast, This Podcast Will Kill You, Bananas and more.

The Joe Rogan Experience

The Joe Rogan Experience

The official podcast of comedian Joe Rogan.

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

Connect

© 2025 iHeartMedia, Inc.