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: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: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:48
◼
►
I think all of them from the iPhone 4 forward?
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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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: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:47
◼
►
[BLANK_AUDIO]