Under the Radar

180: Shortcuts & Harnesses


00:00:00   Welcome to Under the Radar, a show about independent iOS app development.

00:00:04   I'm Marco Arment.

00:00:05   And I'm David Smith.

00:00:06   Under the Radar is never longer than 30 minutes, so let's get started.

00:00:10   So today's episode is going to be kind of in the...

00:00:15   If we were a news website, this would be the article with the title like "Seven Crazy Hacks

00:00:21   That You Won't Believe."

00:00:23   Or more practically, this is the...

00:00:26   I've been thinking a lot about kind of weird or interesting workarounds or approaches I've

00:00:30   been taking to work around either limitations in the platform or just things that I do on

00:00:36   a regular basis to make my development process more efficient, more straightforward, and

00:00:42   ultimately in a lot of ways just more sane.

00:00:45   That these are little things or tweaks or things that I've done that I've just found

00:00:49   make my life a little bit easier.

00:00:50   And I think that it's like whenever I find these things, I feel like they're useful and

00:00:53   worthwhile sharing because maybe they can make...

00:00:56   Maybe they're very specific to my situation, but my situation is probably somewhat similar

00:01:01   to at least some other developers out there, so it seems worth sharing.

00:01:06   So the first one of these, and just to get the flavor of the kind of thing I'm talking

00:01:09   about is...

00:01:10   So developing for the Apple Watch is something that is the actual on-device testing and working

00:01:17   with that is something that I find very cumbersome is probably the kind way to say that.

00:01:22   That's an understatement of the year right there.

00:01:25   So it is like actually getting your app to transfer over to the watch, have it launched,

00:01:31   have it debug correctly and successfully.

00:01:33   All of those things are just...

00:01:36   It's just cumbersome.

00:01:37   And that's just sort of in some ways inherent in it being a wireless debugging session and

00:01:41   there's lots of complexity around that.

00:01:43   It's going via your phone and it's getting better, but it's still not great.

00:01:47   But I find that the nature of watch development requires a certain degree of on-device testing

00:01:56   to really be checking and looking at things, because it's such a small screen that if I

00:02:02   spend too much time just in the simulator on my Mac, I don't get a great sense of how

00:02:07   things would actually work in practice, how big a button would be, how legible some text

00:02:12   would be in practice.

00:02:13   And this is sort of magnified by dealing with the fact that you have even small and relatively

00:02:21   large Apple Watch screen sizes going from the 44mm series 4 and 5 to the 38mm series

00:02:27   3.

00:02:28   There's a pretty wide range in size there.

00:02:31   And this was something that was causing me a lot of difficulty, and so I kind of cast

00:02:33   around trying to come up with a reasonable solution.

00:02:36   And what I ended up with was something that I thought was kind of interesting.

00:02:39   So the screen resolution, or the screen DPI, pixel density of the Apple Watch is 326 DPI.

00:02:48   This is an OLED screen and it's rendered at 2x, which turns out to be very similar to

00:02:54   the iPhone XR and 11, which are also 326 DPI, 2x, their LCD rather than OLED.

00:03:02   So there's certainly a difference there.

00:03:04   Which has then led me to a place where I now, for a lot of my visual development for Apple

00:03:10   Watch, have built these kind of weird test harnesses where I take my UI as I expect to

00:03:18   render it for the Apple Watch and render it instead on a XR that I have kicking around.

00:03:25   And I can get a great sense of how things appear visually, how they work on different

00:03:29   screen sizes, how anything other than probably color, because color is going to be a bit

00:03:34   tricky, either most different between those two technologies.

00:03:37   But general physical size and legibility are more similar.

00:03:40   And I found this to be a great tool for this.

00:03:42   And I use a XR rather than the older, there's several older iPhones that also had 326 DPI,

00:03:47   2x screens.

00:03:48   I think all of them from the iPhone 4 forward?

00:03:51   Probably.

00:03:52   But the great thing about the XR is its screen is large enough that you can actually fit

00:03:56   all four of the Apple Watch screen sizes on a XR screen.

00:04:01   That's awesome.

00:04:02   Currently.

00:04:03   So you have all the watch sizes on a phone at the exact right physical sizes so you can

00:04:09   test the interactivity and whether the stuff is too small and everything?

00:04:13   Roughly, yeah.

00:04:14   That's awesome.

00:04:15   That is basically what you can do.

00:04:16   Because the XR screen is actually pretty big.

00:04:18   It's sort of in between the 11 and the max kind of size.

00:04:24   And so it's a pretty big screen.

00:04:27   And you can fit them all in and you can do this great testing.

00:04:30   And it's just a little bit crazy.

00:04:32   And obviously it requires some nice clean separation of your view hierarchy and your

00:04:37   model and you have to be clever with it.

00:04:40   And this is something that you can most use in kind of the early development prototyping

00:04:46   kind of phase where you're developing controls or visualizations or whatever those types

00:04:52   of components that you're going to display ultimately to the user.

00:04:56   This doesn't work great when you're in the final stages of testing.

00:05:00   That gets a bit more tricky there, I'd say.

00:05:01   But this is something that is a tool that I found that is useful.

00:05:04   And if you happen to have an iPhone XR kicking around or an iPhone 11 kicking around, this

00:05:09   is a great little tool for kind of speeding up that initial iteration speed with initial

00:05:15   iPhone development.

00:05:17   Because the build and run cycle connecting to an iPhone is something that is very reliable,

00:05:22   very well tested, and is done over a cable, which I think makes that process even more

00:05:27   straightforward.

00:05:28   It's a pro-tip work around if you find yourself frustrated with on-device testing for the

00:05:33   Apple Watch.

00:05:34   That is awesome.

00:05:35   But I mean, so obviously you can't do watch kit stuff on there.

00:05:39   What kind of views are you testing here?

00:05:41   Just like custom rendered ones?

00:05:43   So a lot of my rendering is custom rendering.

00:05:47   So there's many controls that I have or things that I'm rendering.

00:05:50   An example of this is complications, for example.

00:05:53   Like a lot of the complications that I do, I've at this point, I've essentially re-implemented

00:05:56   Clock Kit.

00:05:58   I have my own version of Clock Kit that I use for development, which I also need for

00:06:04   on the iPhone side of my apps where I'm doing configuration where you say, "Oh, I wanted

00:06:10   to use this font or this color or whatever."

00:06:12   If I make configuration options available, I need a way of previewing that on the iPhone,

00:06:18   which meant I had to write a Clock Kit proxy that essentially simulates the rendering that

00:06:23   you would see in Clock Kit on the device because I have to simulate that in the iPhone app

00:06:28   anyway.

00:06:29   So if I've taken a lot of that code and then just moved it over into ways that I can preview

00:06:33   that, and you also get the advantage with that of things like I have one of my complication

00:06:37   testing systems where I have the complication setups for each of the different watch sizes,

00:06:42   and then at the bottom I can have a slider that moves back and forth in time, for example.

00:06:48   And so if I'm doing a complication that's supposed to change during the day, I can ask

00:06:52   it to give me what the complication should look like at noon, at 1 p.m., at 2 p.m., and

00:06:58   I can just slide the slider back and forth and have it keep updating its rendering dynamically

00:07:03   through that.

00:07:04   And so that's a great way to kind of quickly sanity check, make sure it's working correctly,

00:07:08   dealing with are there weird edge cases or bugs that I need to deal with where if some

00:07:14   of my complications involve shrinking things down to make it fit.

00:07:19   Say like you have a weather complication that displays the temperature.

00:07:23   If the temperature could be one digit, it's three degrees, or it could be 125 degrees.

00:07:30   And given the size of complication controls, like making sure that it works well between

00:07:36   those two, it can sometimes be difficult.

00:07:38   So having, in the same way I can have the iPhone app cycle through all the possible

00:07:42   temperatures or all those types of things, and it's done on doing it on sort of an iPhone

00:07:46   test harness makes this process a lot more efficient for me.

00:07:49   - That's really interesting.

00:07:50   I mean, and I think there's a lot of value in kind of like, in test harnesses that take

00:07:56   some kind of critical code out of the kind of locked down or cumbersome environment it

00:08:03   usually runs in, like whether it's iPhone or watch or whatever else.

00:08:06   Like I think most people listening to the show are iOS developers, obviously.

00:08:10   But it can really help to take things out and put them on the Mac, for instance.

00:08:13   So this is one area that I have been, that helped me a lot, is whenever I'm developing

00:08:20   a new audio thing for Overcast in recent years, I always make a command line version of it

00:08:26   for the Mac that I can test, as long as it doesn't use iOS specific frameworks, which

00:08:31   all my new stuff mostly doesn't.

00:08:33   And so, like Voice Boost 2, again, I've been working on Voice Boost 2 for a long time,

00:08:38   and it's basically audio processing algorithms.

00:08:41   And they're all written in code that is available on the Mac as well.

00:08:44   Like the only, they don't do almost anything with the audio APIs on the Apple platforms.

00:08:50   They're really only doing the accelerate functions, which are available on both.

00:08:54   And so I have this whole Voice Boost test harness program, and as I'm developing it,

00:08:59   I'm tweaking things, and I'm able to, not only does it help for the shortening the cycle,

00:09:04   like the build and run cycle, 'cause I mean, you think it's good going from the watch to

00:09:08   the phone.

00:09:09   Try going directly to your Mac.

00:09:11   It's like another order of magnitude better when it's just build and run, and it makes

00:09:16   a binary, and you have terminal in there, you can just run it right there, and run it

00:09:19   on a whole bunch of files automatically.

00:09:21   So like, I have a different script that checks the Overcast database for the thousand most

00:09:28   popular podcasts, and just downloads their most recent episodes with their ID numbers.

00:09:33   And then I can then have this great sample of very popular podcasts across a pretty wide

00:09:40   range, and I can then run this on all of them to see, like for instance, will this crash?

00:09:45   Will the algorithm have any crashes or memory problems on any particular popular podcast?

00:09:51   And it's good to know that.

00:09:53   And by having this be a Mac command line thing, even though I'm probably never gonna release

00:09:58   the command line utility, it's mostly just a test harness for my iOS app, it still really

00:10:04   helps to have that just for both, for rapid development cycling, and then also in this

00:10:11   context, I'm doing audio processing, it really helps to take the audio input, process it

00:10:17   through Voice Boost 2, and then open up the output that Voice Boost 2 generated in an

00:10:22   audio editor, like Adobe Audition, which is what I use for this.

00:10:24   And then I can analyze what it did to the waveforms, and I can generate graphs, and

00:10:28   I can generate images, and stuff like that, that's just way more, that would be way too

00:10:33   cumbersome to do in an iOS app, even in a simulator.

00:10:37   Like, it's so much easier to have that just be like a Mac command line thing that I can

00:10:41   run.

00:10:42   And then I can run it on those thousand podcasts, and every time I change something about how

00:10:46   memory works, I can make sure I'm not generating a crash by doing like a huge parallel test

00:10:52   run of all this stuff.

00:10:53   I know this is getting a little bit close to test-driven development, I'm sorry, but

00:10:56   I know I'm just kind of like approximating it poorly instead of doing it right.

00:11:01   You're doing a very imperative, practical version of test-driven development.

00:11:05   Yeah.

00:11:06   It's like, you just run your code on lots and lots of things, and see what happens.

00:11:12   I very strongly believe in that kind of like test harness philosophy.

00:11:15   It's hard for a lot of things.

00:11:17   If you are writing WatchKit UI code, for instance, that's going to be pretty hard to take out

00:11:23   of WatchOS, and to try to simulate elsewhere.

00:11:27   I mean, knowing you, you probably could implement WatchKit.

00:11:29   There's only like 10 or 12 controls.

00:11:33   How hard could it be?

00:11:34   That's true.

00:11:35   How hard could it be?

00:11:36   It certainly seems like there aren't a lot of people working on an Apple.

00:11:40   But yeah, so obviously in certain contexts, it's harder than others.

00:11:44   But where possible, where you have something that's isolatable and that you can bring out

00:11:48   into a test harness that makes your job easier, that's a pretty solid thing to do.

00:11:52   Yeah.

00:11:53   And in this case, it's like finding sort of hardware that can simulate something that

00:11:58   you're trying to do, which in your case, like a Mac can do this just fine, or in my case,

00:12:02   finding the right iPhone to use for this is like a great place to sort of run your harnesses

00:12:06   to get a good sense of things.

00:12:08   Exactly.

00:12:09   We are sponsored this week by Linode.

00:12:11   With Linode, you can instantly deploy and manage an SSD server in the Linode cloud.

00:12:15   Actually, I could even run this.

00:12:17   Oh no, I can't do it on Linux, but I could.

00:12:19   I wonder if anybody has the accelerate function.

00:12:22   Anyway, you can instantly deploy and manage an SSD server with Linode in the Linode cloud.

00:12:26   You can get a server running in just seconds with your choice of Linux distro resources

00:12:29   and node location.

00:12:30   I got a bunch of Linode servers and I just love them.

00:12:33   They're so good.

00:12:34   It's such a great host to be with.

00:12:36   It's so easy.

00:12:37   It's such a great value.

00:12:38   I've been with them forever, since long before they were a sponsor because they're just really

00:12:41   good.

00:12:42   They have hundreds of thousands of other customers, so I know I'm not just crazy.

00:12:46   All of us are looked after by their incredible 24/7 support team.

00:12:49   If you ever have any problems, just email them or call them or chat over IRC in the

00:12:53   Linode community if that's easier for you, whatever suits you best.

00:12:56   They have also amazing guides and support documentation, so if you need to quickly look

00:13:01   something up or if you're new to a certain area of Linux system administration, their

00:13:04   documentation is fantastic.

00:13:06   You don't even have to be a customer to see it, but it's just amazing working with Linode.

00:13:11   They also now have a new management panel, cloud.linode.com.

00:13:15   It's a single page app built using the cutting edge ReactJS stack and is backed entirely

00:13:19   by their public API and it's open source too.

00:13:23   So anything you can do in the control panel, you can also do with their API if you want

00:13:26   to script things or automate things.

00:13:28   They also have two-factor authentication to keep you and all your data safe and secure.

00:13:32   So check it out today.

00:13:33   They have pricing options to suit everyone, starting at plans with just one gig of RAM

00:13:37   for just $5 a month.

00:13:39   You can do a lot with a one gig of RAM server and five bucks a month.

00:13:42   I mean, that's basically nothing.

00:13:44   And they also have, of course, all sorts of things above and beyond that for whatever

00:13:47   you need.

00:13:48   And I have been, again, I've been a customer for theirs for almost a decade.

00:13:50   They're always the best value in the business.

00:13:52   I've never found anybody that consistently beats them.

00:13:55   And you can also get $20 towards any Linode plan by going to linode.com/radar and using

00:14:01   promo code radar2019.

00:14:04   So 20 bucks, that could be four months on that one gig plan.

00:14:06   And with a seven-day money-back guarantee, you have nothing to lose.

00:14:09   So give them a try today.

00:14:11   Linode.com/radar, promo code radar2019.

00:14:15   Sign up there and make the most of that $20 credit.

00:14:17   Our thanks to Linode for their support of this show and all of Relay FM.

00:14:21   So another kind of fun work around, I don't know, hack thing that I've used recently and

00:14:27   I think is a useful tool to keep in the back of your mind when you're especially prototyping,

00:14:30   but even just for actual production work as well, is just how far you can get with just

00:14:37   basic UI views, doing basic UI view animation, and some of the basic kind of core graphics

00:14:44   operations that you can do with UI views.

00:14:46   So for example, in the most recent version of Sleepless Plus and Sleepless Plus 4, I

00:14:52   have a whole bunch of graphs and the really cool sort of data visualizations for how you've

00:14:56   been sleeping.

00:14:58   And I wanted to make these kind of fun and interactive.

00:15:00   And one of them shows you your sort of typical bedtime and typical wakeup time for different

00:15:05   days of the week.

00:15:06   So you can say, you know, when do I typically go to bed on Monday night, Tuesday night,

00:15:09   Wednesday night, et cetera.

00:15:11   And what I wanted was a kind of a nice, fluid, interesting way to transition between the

00:15:16   different displays that I show there.

00:15:19   And what I ended up doing is the graph is, you know, it's a series of bar graphs basically

00:15:23   that are, I guess it's a histogram?

00:15:26   I don't know.

00:15:28   It's a nice graph.

00:15:29   Go look at it and go get Sleepless Plus.

00:15:31   It's a nice graph.

00:15:32   All apologies to Dr. Dering.

00:15:34   But what it, to make it animate fluidly between them, I just make each of the bars a UI view

00:15:39   inside of a parent UI view.

00:15:41   And when you change the data, it just moves the bars from one, it's like from one graph,

00:15:49   from one day to the other.

00:15:50   Like it just does the UI view basic animation and it's just changing the frame of each of

00:15:54   the different bars and it just reuses them so that they animate fluidly between them.

00:15:59   And you get this beautiful, really nice effect of like this nice, rich, smooth, super performant

00:16:05   animation that under the hood is just some UI views with some color.

00:16:09   And if I wanted to do this with like, you know, a lower level API using core graphics

00:16:14   and using CA display links that I could update my animation on a regular basis, like it would

00:16:18   be a lot of pain and suffering.

00:16:20   It turns out you can just, you can just use UI views for your, you know, for your graphical

00:16:26   elements and then just do a, you know, UI view animate with duration, you know, 0.25.

00:16:33   You get the great effect, super straightforward and is really sort of easy to debug and take

00:16:38   a look at because they're just UI views.

00:16:40   They're not, you know, this, this, this sort of opaque representation.

00:16:43   If I was rendering this into an image and then animating it that way or using some kind

00:16:46   of third party graphing framework or charting framework, you know, I'm bringing in a dependency

00:16:51   and some that does a lot more than I probably would want.

00:16:54   Like this is the, the entire graph and sort of the graphing system is a relatively simple,

00:16:59   you know, class, maybe a few hundred lines of code, very performant and straightforward.

00:17:04   So like you can go a long way with UI view animation.

00:17:06   And I think it's a great place to start anytime you wanted to do some kind of rich animation

00:17:11   inside of your applications.

00:17:13   Yeah, I would go even further with that and say like, you know, in general, like try things

00:17:18   that you assume would be too slow, try it first because you'd be surprised what modern

00:17:26   hardware is capable of.

00:17:28   Like again, this is something I've run into constantly with voice boost to development

00:17:31   is like, I kept thinking I would make an assumption like, oh, there's a certain type of processing

00:17:37   that that's pretty sophisticated.

00:17:39   It requires like something like a lot of math for every audio sample.

00:17:43   And you know, you're playing 44,100 samples per second, possibly in two channels.

00:17:48   So two sets of those.

00:17:49   And so like that's, that's a lot of math, you know, possibly having to do like significant

00:17:54   operations on 88,200 samples per second total and trying to do that in a power envelope

00:18:01   that is not going to kill people's battery lives or make their phones hot or get your

00:18:04   app killed.

00:18:05   And ideally, possibly in the future, run on the Apple Watch as well.

00:18:09   And so I would often assume, well, there's a certain kind of processing that I am not

00:18:14   going to be able to do.

00:18:15   You know, like I would write it because I also use voice boost that the aforementioned

00:18:20   command line utility.

00:18:21   I also use it myself for pre-processing my podcast files, just to save myself some time.

00:18:25   And that's why I might someday release it, but it's not on my front of mind, honestly.

00:18:30   For reasons we've talked about on the show before.

00:18:34   And so, but you know, I'd have like, you know, the high quality, like mastering quality algorithm.

00:18:40   And then I would write a low quality one as well, figuring I'd run that on the phone.

00:18:43   And then I'd run it on the phone and I would find that the performance difference really

00:18:47   was not very big and that the mastering algorithm runs totally fine and would be like, you know,

00:18:54   0.2% of the CPU usage during playback or something.

00:18:58   Like modern hardware is way faster than you might assume it is.

00:19:03   Way faster.

00:19:04   And especially in an area like UI views, where that is something that like Apple puts a lot

00:19:10   of resources, both software and hardware into making sure that kind of stuff is extremely

00:19:16   fast because everything uses it.

00:19:19   And it matters a lot.

00:19:21   Every app uses views and layers and compositing behind the scenes and everything.

00:19:25   Like that's a pretty significant part of the OS and the frameworks.

00:19:28   And the GPUs accelerate everything.

00:19:30   It's a whole thing.

00:19:31   And so you can do so much with that, that like, you know, you don't need to get into

00:19:36   like manual image rendering or dropping down to the metal APIs or anything like that for

00:19:41   almost any reason.

00:19:42   Like you can make a game out of UI views.

00:19:45   You could have 100 UI views on the screen animating around, like bouncing around as

00:19:49   sprites for a game.

00:19:50   It isn't the most performant way to make a game, but you could do it.

00:19:54   And if that's what you know and you're just trying to get something done quickly or you

00:19:58   wouldn't make it otherwise, just do that.

00:20:01   And it's probably fine.

00:20:02   - I think there's a lot of these things where like you can get, yeah, it's like you can

00:20:06   get the proof of concept at least and probably even potentially better than that, just using

00:20:11   UI views.

00:20:12   And then like, you know, and just finding interesting ways or creative ways to use them.

00:20:14   Like another example of something that I found myself doing several times over my career

00:20:18   is applying CA rotation transforms to views.

00:20:23   So say for example, you wanted to have a graph that scrolled horizontally, say like pedometer

00:20:30   plus plus where it has a bar graph for every day and it scrolls horizontally.

00:20:34   What about if you just take a UI table view and rotate it 90 degrees?

00:20:37   - Oh my God, does that actually work?

00:20:39   - It does.

00:20:40   It works fine.

00:20:41   - I love that you've tried that.

00:20:44   - And you just have to see, you apply a rotation to the view and then you apply a rotation

00:20:47   to the sub views to make them so that they're the right way out again.

00:20:52   But it totally works.

00:20:53   And you can do the same thing with a UI picker.

00:20:56   If you want a horizontal picker to be, picker rather than to be vertical, to be horizontal,

00:21:00   you can use a UI picker to do that and make it horizontal.

00:21:04   And like, it's a little bit crazy and it's like, I've also subsequently moved away from

00:21:09   that in pedometer.

00:21:10   Like I've sort of implemented my own kind of version based on UI scroll view, but it

00:21:14   wasn't because the other version didn't work.

00:21:16   It was because I wanted to do more than UI table view could allow me to do.

00:21:20   - I hope that somewhere there's a UI kit engineer listening to this right now and either fist

00:21:26   pumping because they put in the work to make that work or crying that you're horribly abusing

00:21:33   their API.

00:21:34   - Well, but I think it's like, it is a great, it's like those are the kinds of little tools

00:21:37   that I'm thinking of sometimes where it's like, there's UI kit is such a rich and like,

00:21:44   well like sort of battle tested, well written piece of software that like you can do weird

00:21:49   stuff with it.

00:21:50   It'll probably work like you kind of would hope it would.

00:21:53   And you'll have some weird quirks to work around maybe, but like you can do a lot with

00:21:57   this kind of stuff.

00:21:58   And like many of these kinds of things, like in this case, the right answer is to use a

00:22:02   UI collection view now rather than a UI table view.

00:22:06   But like you can go a long way with just being thoughtful with like, huh, what if I applied

00:22:11   a, you know, what if I applied a transform to a UI view or just, like you're saying,

00:22:18   create lots of different views or put views inside of views and like UI kit can handle

00:22:24   most of this without a performance issue, without a problem.

00:22:28   And it's the best way that I've found to do that first draft of an app.

00:22:32   And sometimes that first draft becomes the final draft.

00:22:35   But even if it doesn't, it's a really amazing, like the best prototyping tool I found at

00:22:40   this point is UI kit.

00:22:41   Like beyond doing some kind of like prototyping framework, like these things that you, you

00:22:45   know, there's tools that you can do where you are like using some kind of other tool.

00:22:48   It's like, no, just use UI views and it'll be fine.

00:22:50   - Yeah, I mean, like I think a lot of this wisdom comes down to like don't assume something

00:22:55   won't work unless you've actually tried it.

00:22:58   Like something that sounds like it shouldn't work, like rotating a table view 90 degrees

00:23:01   with a transform to make a horizontal table view.

00:23:04   Oh, it's so funny to me.

00:23:06   But like, you know, just try it.

00:23:08   Like, and I think most of us, myself included, wouldn't have thought to ever even try that.

00:23:14   And that's why like people like you who think outside the box, like that's kind of literally

00:23:17   what that means.

00:23:18   Like, you're just like, hey, this crazy hack might work.

00:23:22   Let's see if it does work.

00:23:24   - And like appreciate, I think, come to those types of situations with the humility to say

00:23:29   this is a hack and I need to keep that in mind and not just like, oh, it sort of works.

00:23:33   Like, no, you need to test it.

00:23:34   You need to be a bit more thorough with it, but like try it.

00:23:36   What's it going to hurt?

00:23:37   And like if you can end up with this really, you know, super easy way of doing this and

00:23:42   it's doing all the caching and memory performance and all these huge benefits that you might

00:23:46   be able to get from using one of the pre-built controls just by tweaking it slightly or transforming

00:23:51   it in some way.

00:23:52   Like, you can go a long way with that.

00:23:54   - That's amazing.

00:23:55   - The other kind of interesting thing that I've been doing recently that I just kind

00:23:58   of wanted to mention is the way that some kind of tools and things for localization

00:24:03   of apps.

00:24:05   And so first, the one thing I wanted to point out, and this was something that I only recently

00:24:08   discovered, is in iOS 13, we now have per app language settings as one of the options.

00:24:16   So if you go to the settings app, scroll down to an application, and it supports localization,

00:24:20   you can override the system language for just that application, which is a tremendous tool

00:24:27   for development and debugging and testing because you can now very easily and in a very

00:24:33   lightweight way change the language of just your application.

00:24:36   So I can be like, what does my app look like in German?

00:24:39   What does my app look like in French?

00:24:40   What does my app look like in Spanish?

00:24:42   And I can make those changes very quickly, and it doesn't change the whole system, whereas

00:24:47   previously I would have the rather amusing situation where, especially in the non-Roman

00:24:53   alphabet languages where I would change the system language into Chinese simplified or

00:24:58   Korean or Japanese, and then I have to remember the steps in the settings app that I need

00:25:03   to use to go back to the changed language screen and change it back into English, but

00:25:09   I have to do it just by memory of it's the fourth item down, then it's the second item

00:25:14   down, and then I scroll through this.

00:25:17   It's great to just be able to do it, keep the system language as English, and just change

00:25:21   the language on a per app basis.

00:25:23   So that is a great little tool both for generating screenshots, for helping debug problems with

00:25:28   customers, which is how this actually first came to my attention, was it's like there

00:25:32   were customers who had issues in a particular language or had a problem, and it's like I

00:25:36   can easily, much more easily, get them a screenshot or understand what it is they're seeing by

00:25:41   just changing it for the app.

00:25:42   So pro tip one.

00:25:44   And pro tip two is just something that I, it's like it's one of those things where I'm

00:25:50   not sure this is a recommendation so much as just an observation of something that I've

00:25:54   done in the past.

00:25:56   So often when I'm doing localization, there will be like one line of text that needs to

00:26:00   be updated for the purpose of a update, and it's only one line, and I don't really want

00:26:05   to go through the fuss of doing the, like going through a localization service and getting

00:26:11   it translated and then incorporating it and hoping that the translator understood the

00:26:15   nuance of what I meant in this particular case.

00:26:20   And so something that I've done many times, which I'm not sure is a recommendation, but

00:26:23   it's certainly something to keep in mind, is I think of a string that iOS uses inside

00:26:29   of its own apps.

00:26:32   So the apps that Apple ships or in iOS itself, and I will essentially just copy whatever

00:26:39   it is that they used as their string for a particular localization.

00:26:45   So as an example, when I was implementing the system-wide dark mode in Podometer++,

00:26:50   one of the things that I needed was a string that basically said, "Do you want to use the

00:26:56   setting that you set as an override inside of Podometer, or should it just use the system,

00:27:00   or should it just mirror the system setting?"

00:27:03   Was basically what I needed a toggle switch to have.

00:27:08   Many of us have had this toggle switch implemented in the last few months.

00:27:13   But I remember that in the Watch Companion app, in the Notifications Settings area, one

00:27:19   of the options is "Mirror My iPhone," which is an option that you can have, "Do you want

00:27:26   the notification settings to mirror the iPhone settings, or do you want custom settings?"

00:27:31   And so what I did is I just went through and changed my phone to be in German, in French,

00:27:38   in Spanish, etc., and I just copied down what Apple had translated "Mirror My iPhone" to

00:27:46   into those different languages, which should capture the nuance of what it is I'm trying

00:27:49   to do, because it's the same concept.

00:27:51   I'm not talking about mirror in terms of the glass thing that you look at, and it

00:27:56   reflects back on you.

00:27:57   If I had just used a localization service, you could potentially imagine there's a nuance

00:28:01   that is lost there.

00:28:03   This is a very hard thing to write copy for, even in your own language.

00:28:08   And so I was like, "I'll just copy Apple's."

00:28:10   And there's a few times that I have to go to Google Translate to work out, "I'll put

00:28:14   in the English and then I'll translate into the language and try a few words."

00:28:18   Sometimes it's hard to copy, especially in a language that doesn't use the Roman alphabet,

00:28:25   but I was able to eventually play around with, "Is it mirror?

00:28:29   Is it copy?

00:28:30   Is it whatever?"

00:28:31   You get to try a bunch of different synonyms, and eventually you get the character that

00:28:36   matches the character you're looking for.

00:28:38   And that's what I used.

00:28:39   And like I said, not necessarily recommended, not great in some ways, because obviously

00:28:43   I'm assuming that meaning translates, but so far it's worked.

00:28:48   No, I'm going to say that's great.

00:28:50   I'm going to override you in that and say that is an awesome hack, because copywriting

00:28:55   is something that Apple does very well in the UIs.

00:28:58   And it's one of the hardest things to do in an app, especially if you're trying to outsource

00:29:03   it to a language that you don't know, so you kind of can't check.

00:29:06   So that's actually an awesome hack, because whatever Apple figured for their localizations

00:29:10   is not only saving you time, it's probably better than anything you would have gotten

00:29:13   back.

00:29:14   Yeah.

00:29:15   So anyway, it's just a fun little thing that if you can think of a place or structuring

00:29:19   your copy so that it matches Apple's copy, you can save yourself a lot of time.

00:29:23   And apparently, according to you, it's even better.

00:29:26   So I'll take that and recommend it now as a way to speed up your localization process,

00:29:33   especially for kind of simple things.

00:29:35   And I suppose you could also use it to validate externally produced localizations.

00:29:38   You could take that approach as well if you wanted to go that way.

00:29:40   But either way, fun little trick.

00:29:42   That's awesome.

00:29:43   Thanks for listening, everybody.

00:29:44   And we'll talk to you in two weeks.

00:29:46   Bye.

00:29:47   [BLANK_AUDIO]