Transcript
>> Madhuwanti Vaidya: Hello and welcome everybody.
And we're here to help you understand
crash reports on the iPhone OS.
As a short introduction, we welcome the iPhone Data
Analysis team, and we're are responsible to collect,
process, and analyze customer crash logs.
So when a customer is using your device--
using our device, and they see a crash,
and then they agree to send this
diagnostic information to Apple,
we are responsible for collection
the crash logs and analyzing them.
And in this process, we've learned a lot about crash
logs, and we want to share this information with you.
Let me begin by saying that nobody or
no customer likes an app that crashes.
Let's look at some customer reviews on the iTunes Store.
Here's one that says that this app would have been 4
or 5 stars, but it's not because it's very unstable.
Here's another one that says this is the only
application which is unstable on the iPhone.
Here's one that says keep your buggy garbage.
Here's another one, and another one, another one,
and another one that says the app will not launch.
So you, as app developers, will dread to see such
kind of reviews for your application on the store,
because we know that one bad review leads to another bad
review which leads to lower sales for your application.
So more customer-- more crashes leads to
bad customer reviews lead to lower sales.
And we're to help to help you kind of avoid
these situations, so they look more like this.
Which is fewer crashers, better customer
reviews, and higher sales for your application.
As a short outline of what I'm going
to be talking about today, first,
I'll tell you about what crash
reports are and how they look.
Then I'll talk about the different types
of crash reports we see on the iPhone OS.
Then I'll tell you how to get this crash report
from your device, from your friends' devices
and customer devices onto your host machines.
Sorry. Next, I'll tell you about how to symbolicate these
crash reports so that you can understand them better.
And finally, I'll talk about the common crashes that
we've see when we've analyzed customer crash logs.
So what are crash reports?
How many here have actually seen a crash report?
Wow, that's a fair number of people.
So I'm not the only one who writes code with bugs in it.
So what happens?
So when an application crashes, the iPhone OS writes this
crash report which contains some diagnostic information
that will help you debug your application, rather than
trying to make a guess as to what could have gone wrong.
It will find you to the exact line in your
code that could have caused the crash.
Let's look at an example crash report.
This is what a crash report looks like.
I'll go through this section by section,
and within each section, line by line.
Let's look at the first section of a crash report.
This will give you some basic information about the crash.
The first line is the Incident Identifier.
This is unique for each crash report.
The next line is the CrashReporter Key.
This uniquely identifies a device.
But remember that when we see this, we cannot
exactly pinpoint, oh, this came from your device.
It's anonymized.
The way we use this information is that if we see a
thousand crashes all coming from a single CrashReporter Key,
then we know that this problem is not really
widespread, and it's contained to this single device.
So the way you can use this information
is normalize your data.
If you see a hundred crash reports from customers
all coming from only one or two CrashReporter Keys,
which is one or two devices, you can kind
of make a guess that it's not as widespread.
It's only limited to these two devices.
Whereas, if it came from hundred
different CrashReporter Keys,
then you know you crash is like,
affecting a hundred different users.
Let's go to the next line which is the Hardware Model.
This can be any of the iPhones,
the iPod touches or the iPad.
Again, the way to use this information is if you
see all your crashes coming only from the iPad,
then you'll know it narrows down your
search space to iPad specific code.
You can look at only that code and see what
could have caused the crash only on iPads.
In this case, it's iPod 3,1.
The next line will tell you the Process, which in
your case will be the name of your application.
And the number in square brackets is the process
ID of the process at the time of the crash.
The next four to five lines, you don't have to worry about
as much because they'll be consistent across crash reports.
Let's look at the next section of the crash report.
This gives you some basic information about the crash.
It will tell you the Date and the Time of the
crash, and it will tell you the OS Version
that the device was running at the time of the crash.
So the way to use this information is if you'll see a lot
of crashes coming from iPhone 3.1.2, and none from 3.1.1,
you can make a guess as to there could have been
some change in the API or the way the code--
your code interacts with these new
API's, which is causing this crash.
Let's look at the next section which is the
most important section of a crash report.
This is the Exception section of the crash report.
It will tell you the Exception Type,
which in this case is EXC_BAD_ACCESS.
This means that your program or your
application was trying to access memory,
which wasn't available-- sorry--
available to it at that time.
It will tell you the Exception Code and it will tell you
the Crashed Thread, which in this case, is thread number 6.
The iPhone OS is a multithreaded platform.
So there is more than one thread running at a given time.
So in this case, if you see that the crash thread is
thread number 6, you look at the backtrace of that thread.
The backtrace is in the next section.
So you concentrate on the backtrace of the crash thread
and debug your application using Thread Backtrace,
and concentrate only on the crash thread section.
So let's actually go to thread
number 6 and look at its backtrace.
What is a backtrace?
A backtrace lists all the active
frames at the point of the crash.
So it will give you a necessary list of function
calls that we'll meet when this crash occurred.
It is divided into four columns.
The first column will give you the frame number.
The second column will give the name of
the binary, in this case, its Foundation.
The third column will give you the
address of the function that was called.
The fourth column divides this
address into a base and an offset.
Later on in the talk, I'll tell you how to convert these
addresses into symbol names which are essentially file names
and line numbers, so that they point exactly to the
line in your code which could have caused this crash.
Let's go to the next section.
This section will give the values and
the registers at the time of the crash.
Don't worry about the section too
much, because in most cases,
the backtrace gives you all the information
you need to debug your application.
Finally, the last section which just lists out all the
binaries that were loaded at the time of the crash.
So I showed you an example crash report.
Let's talk about the different types
of crashes that we see on iPhone OS.
We make sure that we have a high quality of user
experience for the user when they interact with our device.
To do this, we need to ensure certain policies.
And these policies can terminate your applications
if your application doesn't respect them.
And because of this termination,
the crash report is written out.
The first kind of crash report is
a Watchdog timeout crash report.
This happens when your application fails to launch,
resume, suspend, or quit in a given timeframe.
So if the user is interacting with your device, and the
application doesn't launch within a given timeframe,
the application will be terminated
and a crash report is written out.
The second type of crash reports
we see are User force-quite.
A user will force-quit your application if
your application is not responsive enough,
and this will cause the crash report to be written out.
So the third type of crash reports we see
are the Low Memory termination crash reports.
The iPhone OS is not exactly like the Desktop OS, because
it has only a limited amount of memory to play with.
And if the OS realizes that it doesn't have enough
memory to continue with interaction with the user,
it will send out this low memory
notification to applications.
If your application respects this low memory
notifications, and it freeze up memory,
and the OS realizes that it's gotten enough memory
to continue running smoothly, things will run fine.
But if there isn't enough memory and if
the application doesn't free up memory,
then your application will be terminated,
and a low memory log will be written out.
Finally, the fourth type of logs that we see
are Application crashes due to bugs in the code.
Let's look at each of these types of crash logs.
Here is an example of a Watchdog timeout crash log.
Remember, I said that the exception section
is the most important section of a crash log.
So if you concentrate on this section, in this case,
you will see that the Exception Code is 0x8badf00d.
If you see this as an exception code, you should immediately
realize that this is a crash log from a Watchdog timeout.
The next section will tell you what your
application was trying to do at the time.
In this case, it says that your
application failed to resume in time.
And the number one cause of these crash supports
that we seen is when your application is trying
to make a synchronous request to a URL to get data.
There are API's to do asynchronous
request, and try to use those.
And don't block the main thread
for more time than necessary.
Bill will actually show you a demo of a how--
of a crash report, or a Watchdog crash report.
>> Bill Dirks: So one thing San Francisco
is famous for is having earthquakes.
So for our demo today, we've decided to
use an app called SeismicXML which isn't--
which I downloaded from the developer website,
and so can you, and it's an earthquake themed app.
What this app does is it makes a URL request
to the United States Geological Survey website,
pulls down data about earthquakes, and then
displays it to the user in a table view.
So I'm just going to show you the
app working properly at first.
[ Pause ]
So I'm just going to launch the app, and if I can--
the network connection works, then we'll see this
table view being populated with earthquake data.
So if it doesn't work, then we'll
see a Watchdog timeout right now.
So--
[ Laughter ]
So either way, it will be good.
OK. Alright.
We're just going to give it one more second, and then--
so that basically, this is exactly why you don't want
to be calling synchronous requests on the main thread,
because like right now, at least you see the title bar
and the table view is responsive,
even though there's nothing in it.
But if you were doing this in your
application, you're calling on the main thread
that blocks all the user interaction with your application.
So your not going to-- so the user's going to
launch your app, and then they're not going
to be having a very good time, because
they like, "Oh, what's going on here?
It's not doing anything."
And here, they can just blame the network.
But if your app just totally-- and
this was not on the main thread.
So it didn't Watchdog.
But I have a version that will Watchdog.
Because SeismicXML is written to call-- to
ask for the URL asynchronously, which is good.
So therefore, the app didn't die, and
it gave me a meaningful warning message.
But like, Siesmicdog app, which is a version of the
SeismicXML app, is one where I'm just-- I changed the code.
So I'm just requesting the URL in the main thread.
And so, I'm going to switch to-- this is just
going to hang here for a while like it did before.
But in this case, it's just going to die.
So the user would not-- you don't see title bar,
you can't interact with the page, and it just dies.
So now that we've seen what a crash looks
like, I'm going to show you how to debug
that crash and get information using Xcode.
If you have such a crash on your device, you
can debug it immediately by plugging your device
into your host, and then opening up Xcode.
From Xcode, you can open up the organizer
which is in the window pull down menu.
And-- alright.
So once you open up the organizer,
you can click on your device,
which is on the left side here, and
then click on the device logs tab.
Clicking on the device logs tab will make Xcode pull your
device and pull down any crash logs that are on the device.
And here, we see the Seismicdog-- maybe I should zoom in.
[ Pause ]
The Seismicdog app that we just generated at 9:14.
So as Madhu mentioned, the first thing
you-- one of the most important sections
of a crash report is the exception section.
So we'll go there first.
And here, we are at the exception section.
We see these 0x8badf00d exception code, and this
means that the Watchdog timeout came in to play.
So the Watchdog timeout comes in to play when you have
failed to launch, resume, suspend, or quit an app in time,
and this is to ensure a good user experience.
So the two other things to notice here are-- the
highlighted thread is 0, which is the main thread,
and that if you look at the applications
specific section immediately below,
it's says Seismicdog failed to launch in time.
So this already gives us a clue on what went wrong
with our app and where we should go look to debug it.
So now that we see highlighted thread is
0, we can go and look at that backtrace.
So how you read a backtrace is you
can start at the bottom, or it's--
in this case, it says start, and
that's the application starting up,
and then you see it called the main UIApplication.
So you just read from the bottom up and
that's the recursive list of function calls.
Eventually, you'll see calls made by your application.
And the one you want to look at is the highest
one in the stack trace, which in this is stacks--
stack frame 3, we see it's from Seismicdog, and
then we're going to look at the symbol information.
So we know that application died,
in applicationDidFinishLaunching
in the file SeismicXMLAppDelegate.m line 133.
So from there, it gives you actual information
where you can go look at the crash log and then,
"Oh, that's where the bug is in my code."
So we can look there now.
You can also look higher up in the stack
frame stack to see what's going on.
In this case, there's-- I actually had it sleep in that
function because you can't control the network connection,
so I want to make sure that this one would die.
So now, I'm going to open up our
code in Xcode and go to line 133.
And here, I have a # define
that says make synchronous URL request.
And I just want to remind everyone that as Madhu said,
the number one cause of Watchdog timeout is making
a synchronous URL request on the main thread.
And we have appropriate API's that you can call
to prevent this from ever happening to your app.
So I encourage you to use them.
Thank you.
>> Madhuwanti Vaidya,: So just a summary.
If you see this exception code 0x8badf00d,
immediately know that it's a Watchdog timeout.
When this happens, try not to block the main thread, perform
task which take longer than required on a background thread,
and make-- and use these API's for asynchronous URL request.
There were these two sessions, Network Apps for
iPhone OS part one and part two, on Wednesday.
I would recommend that you go back and watch these videos.
They talk more in detail about how to use
these API's for asynchronous URL request.
Alright. Let's look at the next section-- next type of
crash report which are user force-quit crash reports.
Again, concentrate on the exception section.
In this case, it's 0xdeadfall, and
it tells you that highlighted thread.
So if you look at the highlighted thread, you will
find out what your application was trying to do
which caused the user to force-quit your application.
In most cases, your application become unresponsive
which is why the user will use this force-quit
action, and this crash log will be written out.
Let's look at the third type of crash
logs which are low Mmemory crash logs.
These look a little different from the other types that
we've seen because they need to tell you more information
about the memory situation of the
device at the time of the crash.
So let's look at this section by section.
The first section is similar.
It will tell you the Incident Identifier,
the CrashReporter Key, the Hardware Model,
the OS Version, and the Date and time of the crash.
The next section is more specific to low memory logs.
It will tell you how many free pages
there were at the time of the crash.
One page is 4 kilobytes.
So in this case there were 581
pages free, which is around 2 MB3.
The next line will tell you how many pages
were wired, how many of them were purgeable,
and what was the largest process in terms of memory.
In our case, it's SeismicXML memory, which
is the application that Bill is demoing.
The next section will tell you-- will give you a list of all
the processes and how much memory each of them was using.
It will tell you the name of the process, the unique
identifier of the process, and the number of pages
that that process was using at the time of the crash.
As you can see here, the first line, which is SeismicXML,
was using 38,000 pages, which is a lot of pages.
So if you see this type of crashes, what you need
to figure out is why your application is using
so much memory, and free up memory when required.
This crash log also tells you which
processes were jettisoned or terminated,
and it tells you which process was active.
In this case, SeismicXML was a
front-most app, and it was active.
So the user was actually interacting with
your application, and the application crashed.
The iPhone OS, when it reaches its low memory situation,
first tries to terminate applications
which are in the background.
As you can see here, MobileSafari is
jettisoned, MobileMusicPlayer is jettisoned.
So it will try to free up memory and terminate
applications which are in the background.
If it still does not get enough memory, it will
terminate the front-most application, which is active.
You can see that third last line,
which is SpringBoard, is also active.
These are the processes that interacts with the
user, and it will always be active in these reports.
So don't get confused when you
see that as the after process.
Bill will show you a demo of a low memory log.
>> Bill Dirks: Hi again.
So since we don't have good-- I don't have a good network
connection here, I'm not going to show you the app crashing,
but it looks exactly like it did
before, comes up and then it dies.
But the really interesting thing
is to look at the crash log itself,
and see how we can use that to help debug our applications.
So once again, if you get-- if you're using any device and
it crashes, or you-- or you've got some crash logs somehow,
but let's say your device has crashed, you plug it
into your host and then open up Xcode, and once again,
go to the window pull down and open up the organizer.
If you don't see your crash log immediately pop
up here, you might need to, as I did earlier,
toggle between tabs to get Xcode to poll your
device and pull down the appropriate crash log.
So in this view, the low memory crash logs say,
low memory in type, and they often have more
than one application in in the application section.
This is because many applications
can be jettisoned at one time.
So what can you get from looking at a low memory crash log?
Unlike the other crash logs, there's not actual information
as in oh this is the line number that I need to go look at.
What you need to look at here is, one,
you're getting them, and so, that's no good.
And-- because the iOS tries really hard not to jettison
the front most app-- so the user that's using your app,
we try as hard as we can not to jettison it,
because that's what the user wants to do.
But sometimes, if the application does use
a lot of memory, it will be jettisoned.
But before the iOS jettisons the
application, it will send a low memory warning.
So as Madhu mentioned, if you listen for this notifications
and respond by bringing up any available memory
that you can, this will prevent-- help prevent
your application from being jettisoned.
In the-- and then the other thing to notice,
which goes along with that is that in this case,
our app was the active app, and it was the jettisoned app.
That means the user was actively using your app.
So that's a situation that you want to avoid.
Other things you can do in terms of-- you can do beforehand
to try to prevent these crash logs from happening,
is there's some tools and instruments such as the leaks
tool and the alloc tool which there's other sessions
that Madhu will point out, that
you can watch the videos for.
And also, you can use-- you can build and analyze
to help you try to find any memory leaks also.
So in summary, you basically-- there isn't
direct actual information in these logs,
but these logs mean that the user is having
not a good experience with your application.
So you should try to work on fixing this.
Thanks.
>> Madhuwanti Vaidya: Just to summarize again, so iOS
will send out low memory notification when it realizes
that there isn't enough memory to run smoothly,
respect these low memory notifications.
When you get this notification in your application,
release objects that can be reconstructed.
Also, release objects that are cached so that the
iOS does not have to terminate your application.
There are at least two sessions that had been
mentioned, Advanced Memory Analysis with Instruments,
that was yesterday, and Performance Optimization
on iPhone OS, which is again, yesterday.
So go back and watch these videos.
Alright. So I talked about the different types
of crash reports that you'll see on the iOS.
How do go about actually getting this crash
reports from your device onto your host machine?
First thing is, you want to build and
test your application on a device.
So-- because the iPhone simulator simulates
most aspects of the iOS, but not all of them.
So, low memory situation, Watchdog time
out, are not simulated by the simulator.
So build and test your application on your device.
If you see crashes on your device, as Bill showed you,
just sync up your device to your host and open up Xcode,
Xcode will automatically pull the crash logs
from the device on to your host machine.
And if you go back to the organizer window in the device log
section, you will see a list of all crashes on your device.
The next stage in building and testing your application is
when you build your application, and if you give it to a few
of your friends who are willing to test it out for you,
what do they do when they see crashes on their devices.
Again, they sync up their device to their host machine,
and depending on the OS that their host is running,
the crash logs will be copied to these
three different-- to this location.
They need to go to this location
and e-mail the crash logs to you.
Finally, when your application is live on the App Store,
we also provide you a way of getting customer crash logs.
So if you log into your iTunes Connect account, there is
this section which is crash reports, if you click on that,
it will show you this nice-- not nice--
it'll show you this list of crash report--
[ Laughter ]
divided it into those four different
types that we spoke about.
So it will show you crashes due to bugs in your application,
it'll show you these timeout reports,
and these low memory logs.
So go look at them, understand them, and try to fix bugs
in your application which is causing these crash logs.
There is a session which talks more in detail about
iTunes Connect-- Publishing with iTunes Connect.
It happened yesterday, so go back
and watch the videos for that.
The example crash log that I showed
had addresses in the thread backtrace.
So you need to be able to go from this
address information to symbol names,
so that we can understand these crash logs better, and
then we can actually go and look in the code of a--
in the line of code that caused this crash.
This process is called symbolication, and I'll
tell you how to symbolicate these crash logs.
So here's a nonsymbolicated-- unsymbolicated crash log.
As you can see, there are addresses in the thread backtrace.
We don't know what to do with these
addresses, since we're not computers.
Here's a symbolicated back log-- symbolicated crash log.
Let's look at one line.
So this address is actually now
converted to this function name
with this applicationDidFinishLaunching,
and the file name and line number.
So how do you do this?
How do you go from address to symbol information?
Well, Xcode does it for you.
So if you drag and drop your crash logs into the
Xcode organizer window in the device log section,
it'll automatically symbolicate your log for you,
so that you can see this file name and line number.
In order to be able to do this, Xcode needs to have access--
or Spotlight needs to have access to the
binary and .dSYM for your application.
And remember, you need to store your
binary and .dSYM for each version
of your application that you upload to the App Store.
You can not go back and rebuild your application,
and hope the crash logs will be symbolicated.
So, Xcode 3.2.2 or later, will actually have this option
of Build and Archive which builds your application
and stores the binary and .dSYM in a safe location so that
you can symbolicate crash logs, because not all crash logs
that you get from customers will be symbolicated.
And you need to do this for each
version of your application.
I cannot stress the fact more now.
Finally, let's talk about the most common crashes that
we've seen when we've analyzed customer crash logs.
These are the three most common crashes
that we've seen from customer crash logs.
All of them relate to memory management on the iPhone OS.
Memory management in-- on Objective-C requires you
to understand the Retain/Release Model
model that Objective-C works with.
And you need to understand this and
apply it consistently across all code.
The first most common crash that we've is
seen is crashes due to over-released objects.
The second is due to null pointer dereferences.
And the third is when you try to insert a
nil object into an array or a dictionary.
If you try to do that, your application will hang or
it will crash, and a crash report will be written out.
Bill will show you a demo of these types of crashes.
I think Bill is the only person on stage
who wants that application to crash.
>> Bill Dirks: Thanks, Madhu.
Yes, I'm going to walk through crash logs from each of these
three types of crashes, so you can look at the backtrace
and use that information to help you debug your application.
I think crash logs that point to bugs in your code
are actually the most compelling type of crash log
because that gives you information, and you can use that
information to find real bugs in your code that's live
in the real world, fix it, and then the user
will have a better experience in the future.
So first, I'm going to show you
an over released object crash log.
So once again, you can open up your organizer window
which is in the window pull down, and here it is.
And before the session this morning, I launched
my app and crashed it in every way I could.
So I-- there's a version of the
application called SeismicOR,
or Seismic Over Release, which
has an over release error in it.
And let me zoom in.
So once again, when you get a crash log, one of the first
sections you want to go look at is the exception section.
And here, we see the exception type is EXC_BAD_ACCESS.
And what EXC_BAD_ACCESS means is that you're
trying to access memory that you don't own.
So you already know from looking at that,
that this is some type of memory issue.
It also shows that the crashed thread is thread number 7.
So now, we go look at thread number 7 in the backtrace.
And once again, you can start at the bottom, you see the
thread spinning up, but the line that you're most interested
in is the line where you see your app
name that's highest up in the call stack.
And here, we see it was in the SeismicXML app
delegate parse earthquake data function, and--
which is in SeismicXMLAppDelegate.m line 234.
So right there, we already know where we can
start to look for the bug in the-- in this code.
And we can look at-- we all look at this code.
So I'm going to go open up SeismicXMLAppDelegate line 234.
[ Pause ]
And here, we see pool release.
So, this-- and pool here is our Autorelease pool.
So right now, we know that we're
releasing some object and we shouldn't be.
And so, that-- that's the cause of our bug.
In fact, if you looked at the crash log, just point it up--
which I didn't point out earlier, and you look at the line
above where your application has crashed.
This shows you that there's an
NSAutoreleasePool release is the next frame up.
So from the crash log itself, you
know that it's some Autorelease error.
So this gives you a starting point
to look for your bug, and here,
since I made the bug, it's pretty
easy for me to discover it.
But we instantiate this parser object which we added to
the AutoreleasePool, and then we used it to parse the data
that came from the website, and then
we're done with this, so we released it.
But since it was in the pool, it got
released again when we did a pool release.
So that's the type of process that you'd go through when you
get a crash log and they're hunting down bugs in your code.
OK. Next, I'm going to show you a crash log from our second
most common type of crash, which is dereferencing null.
So this crash log is very similar, and you use
the same process to the over release crash.
After your app crashes, you can open up the
device that log in Xcode and have it symbolicated,
you look at the exception section, again,
EXC_BAD_ACCESS, so we know it's a memory-related issue.
Here, the crashing thread is 0.
[ Pause ]
So we can look at the backtrace of the crashing thread and
we find that the highest frame that our app is making--
that appears in this thread is
the-- in RootViewController line 76.
Now, the like-- next line up here isn't quite as
useful because it's an obviously message send,
which is a little more opaque for us as the developer.
But we do have the line of code that we can go look for.
So I'm going to open up this piece of code also.
[ Pause ]
So this is just a classic dereferencing null error.
But-- and your code will be much more complicated than this.
I just wanted to show you that it gives me a starting
point in this case right here, to go debug my application,
and then you can go, I'm dereferencing row
height, so what could be the problem there?
And then you'd have to look at what-- you
thought row height existed, but no longer exists.
Or in this case, it never existed because I declared it but
never malloced any memory for it, and then I'm using it.
So that's the second most common type of error we see.
And now, the third most common type of error,
and this one is a little trickier to debug,
but the process is very similar to the
other two, and that's inserting nil
into a collection, such as in array or dictionary.
Once again, if your app crashes,
open up Xcode, go to the organizer.
That's the first thing you do.
In here, I made a version called Seismic
Insert, which I crashed this morning.
So I have the log.
Alright. So the exception type here is this
SIGABRT as opposed to the SIGSEGV we saw earlier.
So SIGABRT's are a little bit--
of a different type of exception.
Because here, what's going on is your
application has asked the kernel to kill it,
and then the kernel comes back and kills your app.
And this happens when something like you
thrown an exception and it gets caught,
and the kernel comes in and kills your app.
So it says here that the crashing thread is
0, but if we look at thread 0, things look OK.
So that's why this type of error
is a little bit trickier to debug.
Because here, we-- on this thread, we
just see Seismic Insert, it's starting,
it launches main, the run is being setup, and it looks OK.
But with the SIGABRT, what you have to do is you--
then you have to start looking at the other threads.
If you don't see the error, in the thread that it is
blamed, you have to start looking at the other threads.
And with SIGABRT, you want to look for
an abort being called in the thread.
So if we look through all these threads and go to
thread 6, we see this line that says abort in it.
And this is actually the backtrace of interest.
This is the backtrace that will show
you where the offending code is.
And here, it was-- because of this
Objective-C exception being thrown.
So that's-- this is a common scenario where the
blame thread isn't the correct blame thread,
and you have to go looking at other threads.
So you want to look for the abort line, and then
often it's because of an exception being thrown.
So-- but once you find this thread,
there's a lot of things bad in this thread.
It says kill, terminate, not good words.
You want to do the same thing you did before.
Go look for the highest frame, that's your app,
in this case-- this app is called Seismic Insert,
and look at the line of code, which is
in the AppDelegate.m again, line 234.
[ Pause ]
There we go.
[ Pause ]
Alright. So on line 234, we're going to see that I'm
adding this new earthquake to the earthquake list.
But in fact, it was nil.
And you know, your code of course, again,
will be more complicated than this.
But this shows you the starting point to look at, and
for some reason, some object that has not existed,
no longer exists, so then you have to hunt down and figure
out why did it go away and how do I go about fixing this?
But the crash logs contain information of crashes that
are happening in the real world that you can go then use
to debug your application and make a better
user experience and hopefully, some more apps.
Thanks.
>> Madhuwanti Vaidya: So just in short,
understand the Retain/Release model
and apply it consistently across all your code.
There is a session which is right after
this, at 11:30, Advanced Objective-C
and Garbage Collection, which talks
more in detail about this.
There was also a session on Wednesday
which you can go back and watch videos for.
Just to summarize, nobody likes an app that crashes.
And most of all, people at the App Store don't like it.
If you got-- if you got a chance to watch the Keynote,
Steve mentioned that the third most common reason
that apps are rejected from the App
Store is because the app crashes.
So you need to build and test your application on
devices that you want your application to run on.
I talked about the different types of crash reports.
I told you about how to get these crash reports from your
device, from your friend's devices on to your host machine.
We also provide you a way of getting customer
crash reports through iTunes Connect.
Remember to store the binary and .dSYM
for each version of your application.
Xcode Build and Archive does this for you.
And finally, we showed you the three most
common crashes that we've seen from customers.
So try to avoid these common mistakes, and hopefully,
your application will have a better user experience.
Thank you for attending this session.
Here are the related sessions.
And for more information, please
feel free to contact Michael.