Under the Radar

177: Operating in a Hostile Environment


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 we are in the tail end of, I guess, big update season,

00:00:15   and it's a time of year where one of the things--

00:00:18   we've talked about many aspects of what this looks like

00:00:20   and of the changes that come and how to manage new APIs

00:00:24   and adopting things and dealing with backwards compatibility with old devices,

00:00:29   but I think an area that I think is useful for us to kind of talk about

00:00:33   is the ways in which sometimes our apps are changing underneath of us,

00:00:39   or there are updates or things that are changed inside of iOS or WatchOS

00:00:44   or whatever operating system you're working on

00:00:46   that can then cause problems for application

00:00:49   where ostensibly code that hasn't changed, unrunning things,

00:00:53   can potentially be turned around in iOS updates and cause lots of problems.

00:00:58   And it can manifest itself in a lot of different areas that we'll kind of talk through.

00:01:02   But I think it's an area that, like this year in particular,

00:01:06   I think there was a lot of this where iOS 13, WatchOS 6 had a lot of--

00:01:12   there were a lot of changes in some of the lower-level parts of the system

00:01:17   that, at least for my applications and I think for yours as well,

00:01:20   there's been just issues.

00:01:22   And some of these are user-facing.

00:01:24   Some of these are things that are indirectly user-facing.

00:01:27   There's been a lot of changes in the way that when your app is backgrounded

00:01:32   how likely it is that it will remain in the background

00:01:34   versus being terminated and then relaunched,

00:01:37   which is sort of user-facing and sort of not.

00:01:40   In your case, if someone's listening to audio and they get killed,

00:01:44   the user would be aware.

00:01:46   But even just otherwise, if the user has to, when they tap on your app icon,

00:01:51   if it relaunches with a full relaunch versus just immediately restoring,

00:01:56   it makes the app feel more responsive.

00:01:58   It makes it feel good.

00:02:00   But being aware even that your app is being killed in the background

00:02:02   is something that is sometimes awkward to notice

00:02:05   or something that's hard to see.

00:02:07   I mean, especially a lot of these behaviors are really tricky

00:02:10   when they don't really happen when you're connected via Xcode

00:02:13   to your application because your app is rarely killed in the background

00:02:17   while it's in an active debug session.

00:02:19   I imagine the app is kind of given a different level of priority

00:02:25   in that context than it would if it was just running

00:02:28   and then you go off and do other stuff.

00:02:30   And so these are often kind of tricky to do.

00:02:32   So I think there's an interesting thing to just kind of talk about,

00:02:34   A, identifying these things.

00:02:36   What are some of the kind of pitfalls that are likely to cause problems

00:02:40   when things change in iOSes?

00:02:42   And then just kind of some of our experiences and then some of the tools.

00:02:46   I think Apple has increased dramatically some of the tools

00:02:49   that we have at our disposal, and the organizer especially,

00:02:52   to identify these kind of behaviors

00:02:54   and then so we can kind of respond to them accordingly.

00:02:57   - Yeah, exactly.

00:02:58   I mean, and I've been facing so many issues like this.

00:03:01   And the thing with issues like this where the system is terminating your app

00:03:05   for some reason or just because it wants the memory back for its own purposes,

00:03:10   many of these issues are mostly out of your hands.

00:03:14   Many of these issues are not your fault, but many of them are.

00:03:18   And it's often hard to know the difference.

00:03:21   And it's hard to necessarily even know that you're having these problems in your apps.

00:03:25   Because for the longest time, there was either minimal reporting on this

00:03:30   or it wasn't being reported at all.

00:03:33   And even if you use a third-party crash reporter framework,

00:03:38   I think those still mostly don't get things like energy log terminations

00:03:42   and stuff like that.

00:03:43   So you really have to look in the organizer in Xcode

00:03:46   and look at the crash logs there and the energy logs there

00:03:50   to really have an idea of how bad of a problem do you have with these things

00:03:54   and why and when are you getting killed.

00:03:58   And unfortunately, like, you know, iOS since the very beginning

00:04:02   has had, as part of the public API, has had these low memory warnings

00:04:07   where on every view controller you get that method that's like,

00:04:11   you get notified if the system's on memory

00:04:13   and then you have a chance to release some memory.

00:04:16   And if you don't release enough memory, your app's probably going to get killed.

00:04:19   There is no equivalent to that for tons of other conditions

00:04:26   that can get your app killed.

00:04:28   And it seems like in every major version of iOS,

00:04:32   they seem to be adding more of these.

00:04:34   And watchOS also, as you are very well aware,

00:04:37   you know, watchOS from the very beginning has had a lot of, like,

00:04:39   super tight restrictions on things like how much CPU time your app can use,

00:04:43   how many seconds it has to, before it has to, like, you know,

00:04:47   draw its snapshot or whatever.

00:04:49   There's all these different conditions like that where not only are most of these restrictions

00:04:54   undocumented and changed between OS releases,

00:04:56   normally in the direction of getting more strict and having more restrictions,

00:04:59   but also there is no public API, there's no notification,

00:05:03   there's no callback, there's nothing that serves as a warning signal to your app

00:05:08   so that you can, like, change what it's doing before it just gets killed by the system.

00:05:13   So you really have to dig through these logs to even find out that you are getting killed for this reason.

00:05:18   And a lot of times the logs will reveal what the limit is,

00:05:23   but sometimes they won't really reveal, like, how you hit that limit or why or what your app was doing.

00:05:28   They try to have stack traces on some of them, but they're often not very helpful

00:05:33   because it isn't, like, an actual crash.

00:05:36   All they can do is, like, sample, like, what it happened to be doing at the moment it decided to terminate the app,

00:05:41   but that oftentimes is not related to why it was terminating the app.

00:05:45   And so it's very, very hard to figure some of these things out.

00:05:49   And the tooling, in some ways, like the Xcode organizer,

00:05:54   especially in the new, in Xcode 11, there's this new metrics tab,

00:05:59   and this is super interesting.

00:06:01   Like, if you haven't taken a look at the organizer in a while,

00:06:03   open up Xcode 11, go to the metrics tab,

00:06:06   and it reports all sorts of great, useful information about the versions of your app

00:06:12   that have been submitted to the App Store,

00:06:14   and over time, how things like battery usage and memory usage and launch time,

00:06:19   how those have changed over each release.

00:06:21   So you can see, like, for instance, one of the metrics here is disk writes.

00:06:26   If your app writes too much to the disk, as of iOS 13, it gets killed.

00:06:31   I believe that's even new to iOS 13.2 or 13.1.

00:06:35   But if you just write too much to the disk in a certain period,

00:06:38   again, these limits, I don't think, are documented anywhere,

00:06:40   which is a common problem with Apple these days,

00:06:42   but I don't think there's any likelihood of doing this,

00:06:45   but if you write too much to the disk, you get killed.

00:06:47   And I was having this issue with a couple versions ago.

00:06:51   I was updating the search index to Overcast too frequently,

00:06:56   and it was causing a lot of disk writes,

00:06:58   and I started getting killed during the early 13.2 betas,

00:07:01   or whatever this was, 13.1,

00:07:04   and I had to figure out, okay, well, how do I write to the disk? Less.

00:07:09   And it's kind of hard when someone's downloading a bunch of,

00:07:12   when they're downloading a bunch of stuff to their phone,

00:07:15   it's kind of hard to avoid writing to the disk to the things they're downloading.

00:07:18   But I could look at things like search indexing and say,

00:07:20   all right, well, that's something I have control over,

00:07:22   so I can at least reduce that.

00:07:25   And so I submitted new versions that reduced search indexing,

00:07:28   and sure enough, they did.

00:07:30   I could see right in the graph on the metrics tab in the organizer,

00:07:33   I can see the disk writes went way down after that update,

00:07:37   and hopefully down to a point where I'm getting killed less.

00:07:40   And so there's all sorts of tooling here, you know,

00:07:43   some of which is helpful, some of which is not.

00:07:46   Man, I sure wish that we would have more of this information accessible

00:07:51   in the app at runtime before getting killed.

00:07:54   And there actually is,

00:07:56   there was a good article on NS Hipster this past week,

00:07:59   there actually is a metrics kit, I believe it's called,

00:08:02   that gives you access to some of this stuff at runtime,

00:08:04   but it doesn't give you, as far as I can tell,

00:08:06   it doesn't give you things like the warnings about, like,

00:08:09   hey, you're going to get killed in a few seconds

00:08:11   for using too much CPU time.

00:08:13   Like, that's something, like,

00:08:14   I would love to have a notification for that

00:08:17   so I could do things like, hey, you know what,

00:08:18   if I'm currently doing something optional that's burning CPU,

00:08:21   just stop doing it, you know, stuff like that,

00:08:23   stuff like, you know, watch trans codes and search indexing

00:08:25   and stuff like that.

00:08:26   Like, I do all sorts of crazy stuff,

00:08:28   like if I think you're plugged into power

00:08:29   and can afford the hit, but if you don't pay attention

00:08:34   to this kind of stuff, you'll get reports from people

00:08:37   just basically saying, like, hey, your app crashed

00:08:39   while I was using it,

00:08:40   or your app keeps crashing in the background

00:08:42   and I don't know why.

00:08:44   And there's plenty of reasons your app can be killed

00:08:48   in the background that Apple doesn't really tell you

00:08:49   much about, that at least the ones they will tell us about,

00:08:52   we can at least do something about that

00:08:53   and pay attention to these metrics

00:08:54   and start looking at the logs and try to do something

00:08:57   that might help this out.

00:08:59   - Yeah, 'cause I think the thing that is,

00:09:00   other than previously, ultimately,

00:09:02   which I feel I found like I would have to do before,

00:09:05   without having access to this kind of metrics,

00:09:07   there's a little bit of just you are getting

00:09:10   the sort of the hearsay reports version of this,

00:09:13   which is just someone is reaching out

00:09:16   via customer support or whatever

00:09:17   and you're just kind of noticing a trend,

00:09:19   'cause often these things aren't immediately obvious.

00:09:21   Like, there are some that just are.

00:09:23   Like, I recently, especially with working with SwiftUI,

00:09:26   there's a bunch of things where like,

00:09:27   between watchOS 6 and 6.1,

00:09:29   there were some like dramatic changes

00:09:31   in how SwiftUI rendered.

00:09:33   And like, all of a sudden my UI was just broken,

00:09:36   you know, on 6.1.

00:09:38   So I had to like rewrite it and change it.

00:09:40   And like, those kinds of things are great in some ways.

00:09:43   Like, while I'm not excited that SwiftUI is still young

00:09:48   and constantly changing, it is nice that like,

00:09:51   here's this very definitive thing that a user will write in

00:09:53   and say like, you know, this label is truncated.

00:09:57   And like, on 6.0 it wasn't, on 6.1 it is.

00:10:00   And like, it's the same code running.

00:10:02   Like, great, that is a nice, easy to identify problem

00:10:04   that is like, you know, I can deal with that.

00:10:07   What was often tricky with a lot of these kinds of issues

00:10:10   is where they're so amorphous that you're just kind of

00:10:14   looking for these kind of general trends.

00:10:16   Like, is, you know, say you have some operation

00:10:20   that only happens on app launch.

00:10:22   Like, there's a certain server call, say,

00:10:24   that only happens on app launch,

00:10:25   or typically happens on app launch,

00:10:26   and you're seeing more of those calls to your server

00:10:30   after an iOS update than maybe there's something to do

00:10:33   with the app being launched in the background,

00:10:35   or things like, I remember doing this kind of detective work before,

00:10:39   but it's nice to have increased visibility into this.

00:10:42   And one thing I will say too that I love about

00:10:45   the new metrics that we have here

00:10:47   is that it breaks down by like different device types.

00:10:51   You can, as well as by like app version,

00:10:55   so you can also see, like, I tried to make a change

00:10:57   and, you know, to affect, you know,

00:10:59   it should improve something.

00:11:00   How does it affect it on a relatively new like 10s phone

00:11:04   versus how does it detect it on a 5s phone?

00:11:07   And like you can get a sense of how the impact is

00:11:10   between those things, and also just I kind of love that,

00:11:12   it's like, I think my favorite one of these new metrics

00:11:15   is launch time, which isn't particularly what we're talking about

00:11:18   in terms of like changes to iOS,

00:11:20   but just is a new metric that came as part of these

00:11:22   new things that are useful for other things,

00:11:24   is like getting an actual real world sense

00:11:26   of what the launch time is in seconds

00:11:28   for a typical user on average for different devices

00:11:31   is tremendously useful, because launch time, I think,

00:11:35   is one of those things that is so hard to quantify yourself,

00:11:40   because it's so dependent often on user,

00:11:43   the actual user's data and their device

00:11:47   and what else they're using,

00:11:48   and there's lots of things that can go into launch time

00:11:51   that you don't have control of or that are hard to simulate,

00:11:54   and so it's really cool to know that, you know,

00:11:56   like for on a 5s, my launch time is three or four seconds,

00:11:59   but on a 10s, it's half a second,

00:12:01   and like that's really cool to know.

00:12:03   But it is interesting to play this detective game,

00:12:06   I will say, that you kind of are often kind of looking for

00:12:08   what is this trend, what is this thing that's happened,

00:12:11   and obviously sometimes you'll know that there are obviously

00:12:14   announced changes that are coming in iOS,

00:12:16   but often there aren't,

00:12:17   and you just kind of have to play this game of looking at it

00:12:19   and be like, huh, between this and this version,

00:12:22   what's changed and how is this,

00:12:25   how is my system responding to it

00:12:27   and what are some things that I'm doing

00:12:29   that could be questionable, because often,

00:12:32   I mean, it's like you said,

00:12:33   sometimes this is the system's fault

00:12:35   and sometimes it's our fault, like sometimes I feel like

00:12:37   we can get away with things that maybe we shouldn't be,

00:12:40   but, you know, we're relying on either a bug in the OS

00:12:44   or just something that it is not enforcing.

00:12:47   I think for a long time there was a bunch of things where,

00:12:50   I think we've started to see a couple where there's calls

00:12:53   that if you didn't make them on the main thread,

00:12:55   you would see a log in Xcode that says,

00:12:58   you're making this call not on the main thread,

00:13:02   this behavior is not supported,

00:13:04   in future versions this will fail,

00:13:06   which is a really interesting thing to see

00:13:08   when you see it, it's like I like when I see

00:13:11   those kinds of messages, that it's like,

00:13:12   I'm doing something that does technically work right now,

00:13:15   but shouldn't work, and so it's like,

00:13:18   I can be proactive and take advantage of those,

00:13:21   and any time I see, like, I mean, I loved in,

00:13:24   see in Core Data there's a thing where you can set it

00:13:26   to be like thread-aware, and if you make any calls

00:13:31   to things that are on the wrong thread,

00:13:33   like, you know, your manage object context

00:13:36   is being accessed from the wrong thread,

00:13:38   you can have the debugger sort of essentially

00:13:41   catch it and you'll hit a break point and say like,

00:13:44   you're doing something bad here,

00:13:45   I think there's a similar thing that you can do

00:13:47   for accessing UIKit, not from the main thread,

00:13:50   that you can, it can sort of prop up,

00:13:52   essentially act as an exception in those cases,

00:13:55   'cause I think those are often those kinds of edge case

00:13:57   things that will work differently between versions of iOS,

00:14:02   where you'll suddenly get caught out,

00:14:04   that you were doing something that you weren't aware

00:14:06   was problematic, but was problematic,

00:14:08   but then, you know, it's like, it used to work,

00:14:11   but suddenly it doesn't, like, I think I had one of these

00:14:13   with iOS 13 where I was presenting a modal view controller,

00:14:17   I think, and in certain circumstances it could be presented

00:14:20   from a background thread if it was coming from a notification

00:14:24   and that notification happened to come from a background thread,

00:14:26   like, there was, you know, this sort of chain of events

00:14:28   that could have happened where this was happening,

00:14:30   and it worked on iOS 12, like, it would present

00:14:33   and I never noticed, but on iOS 13 it would fail and crash,

00:14:36   and, like, that was just one of those things that I was,

00:14:39   I wasn't, you know, doing, I wasn't doing the appropriate call

00:14:42   to send it, you know, to dispatch it back to the main thread,

00:14:45   but, you know, now in 13 I was very aware of that

00:14:50   and had to fix it.

00:14:51   - Yeah, I've had, I've been bitten by a few of these things,

00:14:54   I know about a year ago, or maybe a little more,

00:14:56   I had a problem where if you, I had, you know,

00:15:01   I had extensions running for my app and I had my main app

00:15:04   and so I thought, hey, why don't I put the SQLite database file

00:15:08   in the shared app container, that way the extensions

00:15:11   and the main app can all be reading from the same database file

00:15:14   and write into it and everything, and SQLite is good about,

00:15:16   like, cross process, you know, synchronize access,

00:15:19   so I knew that would be okay, so I thought, great,

00:15:21   this should be fine, and I was getting all these weird crash reports

00:15:26   and what turned out to be the reason was that if you are holding on to a,

00:15:31   I believe a writable file handle in a shared app container,

00:15:36   when your extension or main app gets suspended or terminated

00:15:41   in the background, iOS will kill the app and make a crash log saying,

00:15:46   hey, you actually crashed, like, as opposed to just a regular termination,

00:15:49   and it took me forever to figure out why because that thing about, like,

00:15:54   not having writable handles open in a shared app container,

00:15:57   I don't think that was documented anyway, and it took me, I think,

00:16:02   weeks to figure that one out and eventually ship an app update

00:16:04   that just doesn't have the SQLite file there anymore

00:16:06   and just communicates through other methods.

00:16:08   For lots of reasons, don't put your SQLite file in the shared app container

00:16:12   between extensions and your app, and so that one bit me pretty hard.

00:16:17   I've also gotten hit in more recent times.

00:16:21   Recent OSes, I believe they started with 12,

00:16:24   but at least it's certainly present in 13, are very aggressive about

00:16:28   if you open a background task and you don't close it,

00:16:33   or if they call your expiration handler and you don't end the task

00:16:37   in the expiration handler, they will kill the app with a crash,

00:16:41   and that's especially coming up for a lot of people now with iOS 13

00:16:45   because iOS 13 significantly reduced the amount of background time you have.

00:16:49   It used to be about three minutes, and now I believe it's 30 seconds,

00:16:53   something like that, and so the background task API

00:16:57   is dramatically more aggressive in iOS 13,

00:17:00   so we're seeing a lot of crashes from that,

00:17:02   to the point where now, I did this a few months back.

00:17:05   I actually changed all of my begin background task calls

00:17:08   to use my own custom wrapper library that automatically will close the task

00:17:14   if the calling code doesn't, just because there's nothing about my app

00:17:19   that will break horribly if it gets suspended unexpectedly,

00:17:23   so it's no big deal if the system suspends it,

00:17:26   and I didn't cancel the background task,

00:17:29   so now I had to actually make this wrapper class just to ensure that I can't do that.

00:17:35   And of course, I audited all the ways I was using it too,

00:17:37   and I hope I never actually need that fallback,

00:17:39   but it's always good to have something like that.

00:17:41   All sorts of stuff like that where the system is getting more and more strict

00:17:45   over time, and a combination of Apple's engineering strictness,

00:17:50   basically of throwing the problem back in our face,

00:17:53   and their extreme lack of documentation on any of these things,

00:17:58   and the fact that the conditions always change,

00:18:00   make it so that we really have to be on our toes,

00:18:02   and I don't think things necessarily should be this way,

00:18:05   but they are, and we really have to be on our toes all the time,

00:18:08   and every OS release, even a dot release,

00:18:12   like even going from iOS 13.1 to 13.2, say,

00:18:15   even dot releases change these requirements,

00:18:18   and add more strict checking on things and everything.

00:18:21   You never know when an OS release is going to all of a sudden

00:18:24   start killing your app for a transgression that you weren't even aware of,

00:18:28   or that used to not be a problem, and now is a problem.

00:18:32   We are sponsored this week by Linode.

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

00:18:39   You can get a server running in just seconds,

00:18:42   with your choice of Linux distro, resources, and node location.

00:18:45   It doesn't matter if you're working on your first server,

00:18:48   or deploying a huge complex system, Linode is where to go.

00:18:52   They have the fastest hardware network,

00:18:54   with outstanding customer support if you ever need help,

00:18:56   and it's super easy to launch a Linode cloud server.

00:18:59   They now have block storage available in Newark, Fremont, Dallas, Atlanta,

00:19:02   Frankfurt, London, and Singapore, soon to be released in Tokyo.

00:19:05   Version 4 of Linode's REST API is out of beta,

00:19:08   and includes an officially supported Python CLI.

00:19:11   It's such a great host.

00:19:12   I've got to say, Dave and I have been there forever,

00:19:15   and I've been there for something like eight or nine years.

00:19:17   All of Overcast is hosted there.

00:19:19   I just absolutely love working with Linode.

00:19:21   It's been a rock-solid host the entire time I've been there,

00:19:23   and it's been the best value that I've been able to find in the market as well.

00:19:27   So check it out.

00:19:29   And also right now, Linode is hiring.

00:19:31   If you want to learn more about that, go to linode.com/careers.

00:19:34   Otherwise, for everyone else, check out their pricing options.

00:19:36   They have options to suit everyone.

00:19:38   Plans start at one gig of RAM for just $5 a month,

00:19:42   and they have all sorts of other plans above that for various needs,

00:19:44   including high-memory plans.

00:19:46   And Linode has a special offer for you.

00:19:49   Listeners of this show can go to linode.com/radar

00:19:52   and use promo code radar2019 to get $20 towards any Linode plan.

00:19:57   So on the one gig of RAM plan, that could be four months free.

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

00:20:03   So give Linode a try today.

00:20:05   That's linode.com/radar and promo code radar2019.

00:20:09   To learn more, sign up and make the most of that $20 credit.

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

00:20:17   Something that I found kind of interesting in this general topic too recently,

00:20:21   I feel like Apple is increasingly using the crash termination

00:20:26   as a way to enforce policy.

00:20:29   That there was a term early in my career I'm working on iOS,

00:20:34   I feel like crashes were usually directly my fault.

00:20:39   I did something that was bad.

00:20:42   Or in a more modern case, you could imagine in Swift,

00:20:45   where if you use -- any time you use the exclamation point operator,

00:20:49   you're asking for a crash because inevitably somehow that optional

00:20:54   is going to turn out to be nil and it's going to crash.

00:20:56   That was just your fault. That's just bad programming.

00:20:59   But there weren't as many of these kind of situations

00:21:03   where things are being -- policy is being enforced with a crash.

00:21:06   But it's now, for example, if you make any privacy-related call

00:21:11   inside your application and you don't include the appropriate

00:21:16   P list entry with the privacy description text,

00:21:20   your app will just immediately terminate.

00:21:23   In some ways you could think, "Well, why doesn't the call just fail?"

00:21:26   or something like that. It's like, no, Apple enforces that by a crash,

00:21:30   by this hard, very aggressive version of that.

00:21:34   And many of these resource constraints are enforced in the same way,

00:21:39   that there is this very harsh, strong --

00:21:43   you do something incorrect, your app is terminated,

00:21:47   rather than just getting a not-authorized message

00:21:52   or dealing with -- you can imagine softer versions of this.

00:21:56   And in some ways, I will say, as a developer,

00:21:58   there are parts of me that really like it, in the sense that

00:22:01   if I'm doing something that I shouldn't be,

00:22:04   often it is for lack of understanding about how to use something correctly,

00:22:09   or I don't realize that I'm making a call that will actually

00:22:13   deal with any of the privacy APIs.

00:22:15   There are situations where things like that can happen.

00:22:18   And in some ways it's nice to very strongly get my attention,

00:22:22   because nothing gets your attention quite so strongly

00:22:24   as the app immediately terminating.

00:22:27   That's much more obvious than just the silent failure case.

00:22:33   - It's like warnings versus errors.

00:22:35   If your app crashes when you do something,

00:22:38   you can't just delay fixing that for some future better time

00:22:42   that will never come.

00:22:43   You have to deal with that.

00:22:44   It's forcing you to deal with it.

00:22:46   - And in some ways, that's kind of nice.

00:22:50   It's a little tricky when they happen in the between-the-

00:22:51   It's tricky when they happen in the change in behavior,

00:22:58   like the same code now crashes rather than just silently failing.

00:23:02   That can be awkward when it happens,

00:23:04   and especially when it happens in point updates

00:23:07   or more minor things that are harder,

00:23:09   like we don't have as much time with,

00:23:11   or we don't necessarily look at as much.

00:23:13   Because as much as Apple will usually provide us with a developer beta

00:23:17   most at least of the major point releases,

00:23:21   maybe not the minor point releases, ahead of time.

00:23:24   It's also kind of tricky to necessarily always be running those.

00:23:27   By all means, run any of the major versions.

00:23:29   When iOS 13 came out at WWDC, I have it on a device,

00:23:32   and I'm running my apps on it on day one

00:23:34   and looking out for these kinds of things.

00:23:36   But it's a little tricky for some of the times for the point releases.

00:23:38   But I do kind of see where they're coming from,

00:23:40   and I kind of like that this generally seems to be a new pattern

00:23:44   that they're kind of heading towards,

00:23:46   and if you do something wrong, like you were saying with some of the handlers

00:23:49   and things where you kind of could have gotten away with it before,

00:23:52   and they were a little bit more loosey-goosey about it,

00:23:55   it's a different kind of model that I think ultimately

00:24:00   will probably encourage higher general compliance and code quality.

00:24:05   And as a philosophy, I'm not totally against,

00:24:09   because it kind of necessitates this much more rapid improvement.

00:24:13   But it's just awkward where sometimes they're happening

00:24:17   for things that you don't understand.

00:24:19   And I do kind of like, and in some ways it makes sense,

00:24:21   that by making it a crash, there's the broadest amount of instrumentation

00:24:27   possible for collecting information about that.

00:24:30   Like, crash reporting, collecting crash reports

00:24:33   is something that Apple does, that third-party frameworks do,

00:24:36   that TestFlight does.

00:24:38   By turning it into a crash, there's lots of instrumentation

00:24:42   and kind of workflows around collecting that information

00:24:45   and kind of knowing what happened that is already existing.

00:24:50   And I mean, it's kind of funny in some ways that many of these policies

00:24:53   are then enforced by the weird little paragraph in the middle of the crash report.

00:24:58   Which is like, I don't think was necessarily like that section

00:25:02   is kind of supposed to be this communication mechanism back and forth

00:25:06   between the system and developers.

00:25:08   But it is now.

00:25:10   And there's a lot of information where I'll open up a crash report

00:25:12   and there's this little paragraph in the middle.

00:25:14   It's like, well, the watchdog process found that your application

00:25:18   was using CPU for 2.04 seconds and the limit is this,

00:25:22   and so you were killed after this amount of time.

00:25:24   And we're having this little conversation about why I was killed.

00:25:28   And that's interesting and that's useful.

00:25:30   And I'm okay with it in some ways,

00:25:32   but it is just something that I've noticed recently,

00:25:34   that there's this trend towards you do something wrong

00:25:37   and your app is killed rather than you do something wrong

00:25:39   and it kind of silently fails.

00:25:41   And overall I like it, but it is something that I think definitely to be aware of.

00:25:45   And probably also just kind of something I've had to make peace with in a good way

00:25:50   is for a long time my goal was to always have like zero crashes.

00:25:55   Like if you open the analytics tab in iTunes Connect, say,

00:25:59   in just like the crashes area, for a long time my goal was always to kind of get the crash rate down to zero.

00:26:06   But with a lot of this kind of change, well it used to be in some ways.

00:26:11   I've been over a year zero. I think I have like a thousand a day.

00:26:14   Yeah, and I think I'm now at peace with that.

00:26:17   Like the point I'm heading towards is that it used to be a reasonable goal.

00:26:20   Now it isn't, and now it's more I think the crash,

00:26:23   like there is telling you things sometimes that you have control over,

00:26:27   sometimes that you don't.

00:26:28   And the crash is more like a feedback mechanism.

00:26:31   And you want overall, like if you see the crash rate going up,

00:26:34   it's probably a bad thing. If you see it going down, it's probably a good thing.

00:26:37   But the goal is not necessarily to get it to zero.

00:26:40   The goal is for it to kind of slowly decrease over time.

00:26:43   And if you see any like abrupt jumps in your crash rate,

00:26:47   there's probably a lot of interesting logs with lots of paragraph text in them

00:26:50   telling you things that you, new policies that you may not have been aware of,

00:26:54   or just things that you need to be, you know, that need your immediate attention

00:26:58   and that the system is telling you, you need to fix this right now.

00:27:01   Yeah. And I think ultimately, I think using crashes this way from Apple's point of view,

00:27:06   it makes sense to use it as like an enforcement mechanism for lots of things.

00:27:12   Especially it makes sense, you know, as you mentioned how the tooling is so good,

00:27:15   it makes a lot of sense for like line by line misuse of something.

00:27:20   So like if you are literally like calling an API wrong or something,

00:27:24   like that makes tons of sense.

00:27:26   Where I think it needs more support around it is when it's about

00:27:30   like general conditions being exceeded.

00:27:32   You know, things like memory, CPU usage, disk rights,

00:27:36   like where there is some limit that the system is enforcing

00:27:39   and your app is just going to slowly approach it until it hits it and then get killed.

00:27:43   That is where a crash report is pretty much useless to you

00:27:48   because who knows where all the memory was going before the one line of code

00:27:52   they happened to sample when they made their report.

00:27:54   And so it's much more useful in cases like that to have a warning API first.

00:28:00   To have something, some callback, some notification, some handler,

00:28:04   something where the system tells you like, "Hey, you've reached 80% of this limit."

00:28:09   Something like that before it kills you.

00:28:12   Because then even if most apps never respond to that, fine,

00:28:16   then it will be like the way it is now for them, although they will eventually get killed.

00:28:20   But for those of us who want to do better, who want to avoid crashes

00:28:23   and who might be doing optional work, please give us the support

00:28:28   to actually respond to these conditions before our apps get killed.

00:28:32   Because when they get killed, for resource usage basically,

00:28:38   it's nearly impossible for us to do anything about that.

00:28:41   Like what are we supposed to do with that information besides,

00:28:43   "Well, I guess we'll try to use less CPU."

00:28:45   How? Where? We don't know.

00:28:47   But if we have a feedback mechanism before we get killed,

00:28:50   we can add our own logging, we can respond to it, we can turn things off.

00:28:54   It's so much better for everyone if we have that.

00:28:57   Yeah, and it's also great when that is something that we can simulate.

00:29:00   Yes.

00:29:01   As well. Like, in the same way that we have the network link conditioner

00:29:04   that can simulate network conditions, like being able to launch the app and say,

00:29:07   "Launch me as though the system is under constraint right now,

00:29:11   and let me see what will happen and how I'll be terminated

00:29:15   and what behaviors I should expect."

00:29:17   And anytime they give those kinds of tools to us,

00:29:20   I find them invaluable to just get a sense of where...

00:29:24   Otherwise you're doing these weird things that you're like,

00:29:27   "Let me launch six other apps while I'm launching my app

00:29:30   and start playing 4K video in the hopes that I'm creating a condition

00:29:33   that will make my app be resource constrained."

00:29:38   Which is not repeatable and is not particularly reliable either.

00:29:42   Yeah, and there's some tooling around that, but it's very minimal.

00:29:45   More would be a lot better.

00:29:47   Anyway, thanks for listening, everybody, and we'll talk to you in two weeks.

00:29:50   Bye.

00:29:51   Bye.

00:29:51   [BLANK_AUDIO]