Demystifying iOS Application Crash Logs
http://www.raywenderlich.com/23704/demystifying-ios-application-crash-logs
This is a blog post by Soheil Moayedi Azarpour, an independent iOS developer. You can also find him on Google+.
Have you ever had the following experience as an app developer?
Before you submit your app, you perform a lot of testing to make sure your app runs flawlessly. It works fine on your device, but after the app is in the App Store, some users report crashes!
If you’re anything like me, you want your app to be A+. So you go back to your code to fix the crashes… but where do you look?
This is when iOS crash logs come in handy. In most cases, you’ll get very detailed and useful information about the cause of the crash, like feedback from a good teacher.
In this tutorial, you’ll learn about some common crash log scenarios, as well as how to acquire crash logs from development devices and iTunes Connect. You will learn about symbolication, and tracing back from log to code. You will also debug an application that can crash in certain situations.
OK, let’s get crashing!
What Is A Crash Log, and Where Do I Get One?
When an application crashes on an iOS device, the operating system creates a crash report or a crash log. The report is stored on the device.
You can find a lot of useful information in a crash log, including the conditions under which the application terminated. Usually, there is a complete stack trace of each executing thread, so you can see what was happening in every thread at the time of the crash, and identify the thread where the crash occurred.
There are many ways to get a crash log from a device.
A device that is synced with iTunes stores its crash logs on the machine. Depending on the OS, here are the locations where you can find them:
Mac OS X:
~/Library/Logs/CrashReporter/MobileDevice/<DEVICE_NAME> |
Windows XP:
C:\Documents and Settings\<USERNAME>\Application Data\Apple Computer\Logs\CrashReporter\MobileDevice\<DEVICE_NAME> |
Windows Vista or 7:
C:\Users\<USERNAME>\AppData\Roaming\Apple Computer\Logs\CrashReporter\MobileDevice\<DEVICE_NAME> |
When your users experience a crash, you can instruct them to sync their device with iTunes, go to one of the above locations (depending on their OS), download the crash logs and email them to you.
You want any crash logs your users generate. The more crash logs you have, the better equipped you are to find and diagnose weaknesses in your app!
Also, you can easily get the crash reports for your devices via Xcode, if you have it installed. To do this, connect the iOS device to your computer and open Xcode. From the menu bar, select Window, then Organizer (the shortcut is Shift-CMD-2).
In the Organizer window, go to the Devices tab. On the left-hand side navigation pane, look for Device Logs, as shown in the image below:
As you can see in the screenshot, there are multiple Device Logs items. The Device Logs under LIBRARY contain all the logs from all devices you own (or have connected to Xcode). The Device Logs entries under each device are for that particular device.
Once your app is submitted, you can also get crash logs from your users using iTunes Connect. To do this, simply sign in to your iTunes Connect account, navigate to Manage Your Applications, click on the app you want crash logs for, click on the View Details button below the icon, and click on Crash Reports in the right-hand side pane in the Links section.
If there are no crash logs, try clicking on the Refresh button. If you haven’t sold many copies of your app, or if it has been available only for a short time, chances are that you don’t have any crash logs in your iTunes Connect account.
If you did have any crash logs in iTunes Connect, you would see something like this:
Sometimes you won’t see anything in here despite your users reporting a crash. In that case, it’s best to ask them to send you the crash logs if possible.
What Generates a Crash Log?
There are two main situations that can result in a crash log:
- Your app violates OS policies.
- There are bugs in your app.
iOS policy violations include things such as watchdog timeout at the time of launch, resume, suspend and quit; user force-quit; and low memory termination. Let’s go over these in more detail.
Watchdog Timeout
As you’re probably aware, since iOS 4.x, most of the time when you quit an iOS app, the app isn’t terminated – instead, it’s sent to the background.
However, there are times when the OS will terminate your app and generate a crash log if the app didn’t respond fast enough. These events correspond with the implementation of the following UIApplicationDelegate methods:
- application:didFinishLaunchingWithOptions:
- applicationWillResignActive:
- applicationDidEnterBackground:
- applicationWillEnterForeground:
- applicationDidBecomeActive:
- applicationWillTerminate:
In all of the above methods, the app gets a limited amount of time to finish its processing. If the app takes too long, the OS will terminate the app.
Note: This can easily happen to you if you aren’t performing long running operations (like network access) on background threads. For information on how to avoid this, check out our Grand Central Dispatch andNSOperations tutorials.
User Force-Quit
iOS 4.x supports multitasking. If an app blocks the UI and stops responding, the user can double-tap the Home button from the Home screen and terminate the app. In this case, the OS generates a crash log.
Note: You may have noticed that when you double-tap the Home button, you also get a list of all the applications you’ve run in the past. Those apps are not necessarily running, nor are they necessarily suspended.
Usually an app gets about 10 minutes to stay in the background once the user hits the Home button, and then it gets terminated automatically by the OS. So the list of apps that you see by double-tapping the Home button is only a list of past app runs. Deleting the icons for those apps does not generate any crash logs.
Low Memory Termination
When subclassing UIViewController, you may have noticed the didReceiveMemoryWarning method.
Any app that is running in the foreground has the highest priority in terms of accessing and using memory. However, that does not mean the app gets all the available memory on the device – each app gets a portion of the available memory.
When total memory consumption hits a certain level, the OS sends out aUIApplicationDidReceiveMemoryWarningNotification notification. At the same time,didReceiveMemoryWarning is invoked for the app.
At this point, so that your app continues to run properly, the OS begins terminating apps in the background to free some memory. Once all background apps are terminated, if your app still needs more memory, the OS terminates your app and generates a crash log.
The OS does not generate a crash log for the background apps that were terminated under this circumstance.
Note: Per Apple documentation, Xcode does not add low memory logs automatically. You have to obtain them manually, as described above. However, in my personal experience using Xcode 4.5.2, low memory crash logs were imported automatically with “Process” and “Type” listed as unknown.
It is also worth mentioning that allocating a big chunk of memory in a very short period of time puts a strain on the system memory — even if for a fraction of a second. This, too, can result in memory warning notifications.
Bugs in the Application
As you can imagine, these cause the majority of app crashes, and hence, are behind the generation of most crash logs. Bugs come in seemingly endless varieties.
Later on in this tutorial, you will confront some actual crash logs from a buggy application, and use your powers of deduction to find the culprits and apply some fixes!
A Sample Crash Log
Let’s start by taking a look at a sample crash log, so that you have an idea of what to expect before tackling some real scenarios.
Without further ado, meet your new friend:
// 1: Process Information |
There is a lot of mysterious stuff in this report. :] Let’s go through it section-by-section:
(1) Process Information
This first section gives you some information about the process that crashed.
- Incident Identifier is a unique identifier for the crash report.
- CrashReporter Key is also a unique key that is mapped to the device identifier. Although it is anonymized, it gives you a very useful piece of information: if you see 100 crash logs from the same CrashReporter Key or a few CrashReporter Keys, it means that the issue might not be a widespread problem, limited to only one or a few devices.
- The Hardware Model identifies the device type. If you get a lot of crashes from the same device model, it might mean that your app is not working properly on a specific model. In the log above, the device is an iPhone 4s.
- Process is the name of the application. The number in the brackets is the process ID of the application at the time of crash.
- The next few lines should be self-explanatory.
(2) Basic Information
This section gives you some basic information about the date and time of the crash, and the version of iOS running on the device. If you have a lot of crash logs coming from iOS 6.0, it might mean that your problem is specific to iOS 6.
(3) Exception
In this section, you can see the type of exception that was thrown at the time of the crash. You also get the exception code and the thread that threw the exception. Depending on the type of crash report, you may get some extra information in this section as well.
(4) Threads backtraces
This section provides the backtrace log for all threads in the app. Backtrace is a list of all active frames at the time of the crash. It gives you a list of function calls when the crash happened. Consider the line below:
2 XYZLib 0x34648e88 0x83000 + 8740 |
It is basically four columns:
- The frame number – in this case, 2.
- The name of the binary – in this case, XYZLib.
- The address of the function that was called – in this case, 0x34648e88.
- The fourth column is divided into two sub-columns, a base address and an offset. Here it is 0x83000 + 8740, where the first number points to the file, and the second points to the line of code in that file.
(5) Thread state
This section gives you the values in the registers at the time of crash. You don’t usually need this section, because the backtrace has already given you the information you need to find your problem.
(6) Binary images
This section lists all the binaries that were loaded at the time of the crash.
Demystification with Symbolication
When you first look at the backtrace in a crash log, it doesn’t make sense. You’re used to working with function names and line numbers, not a cryptic location like this:
6 Rage Masters 0x0001625c 0x2a000 + 30034 |
The process of converting from these hexidecimal addresses in the executable code to method names and line numbers is called symbolification.
When you get crash logs off of a device through Xcode’s Organizer window, they are automatically symbolicated after a few seconds. The symbolicated version of the above line is this:
6 Rage Masters 0x0001625c -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35) |
For Xcode to symbolicate a crash log, it needs to have access to the matching application binary that was uploaded to the App Store, and the .dSYM file that was generated when that binary was built. This must be an exact match; otherwise, the report cannot be fully symbolicated.
So, it is essential that you keep each build distributed to users. When you archive your app before submission, Xcode stores your binary. You can find all of your archived applications in the Xcode Organizer under the Archivestab.
Xcode will automatically symbolicate all crash reports that it encounters, if it has the matching .dSYM and application binary that produced the crash report. If you are switching computers or creating a new account, make sure you move over all of those binaries and put them in the right place, where Xcode can find them.
Note: You must keep both the application binary and the .dSYM file to be able to fully symbolicate crash reports. You should archive these files for every build that you submit to iTunes Connect.
The .dSYM and application binary are specifically tied together on a per-build-basis, and subsequent builds, even from the same source files, will not interoperate with files from other builds.
If you use the Build and Archive command, the files will be placed in a suitable location automatically. Otherwise, any location searchable by Spotlight (such as your home directory) is fine.
Low Memory Crashes
Since low memory crash logs are slightly different than normal crash logs, this tutorial will address them separately. :]
When a low memory condition is detected on an iOS device, the virtual memory system sends out notifications asking applications to release memory. These notifications are sent to all running applications and processes, in an effort to reduce the total amount of memory in use.
If memory usage remains high, the system may terminate background processes to ease memory pressure. If enough memory can be freed, your application will continue to run and no crash report will be generated. Otherwise, your app will be terminated by iOS, and a low memory report will be generated.
In low memory crash logs, there are no stack traces for the application threads. Instead, the memory usage of each process is reported in terms of the number of memory pages. (At the time of writing, a memory page was 4KB in size.)
You will see jettisoned next to the name of any process terminated by iOS to free up memory. If you see it next to your application’s name, it means the application was terminated for using too much memory.
A low memory crash log looks something like this:
Incident Identifier: 30E46451-53FD-4965-896A-457FC11AD05F |
When you experience a low memory crash in your app, you should investigate memory usage patterns and how your app responds to low memory warnings. You can use the Allocations and Leaks Instruments to discover memory allocation issues and leaks. If you don’t know how to use Instruments to check for memory issues, you might want to check out this tutorial as a starting point.
And don’t forget virtual memory! The Leaks and Allocations Instruments do not track graphics memory. You need to run your application with the VM Tracker Instrument to see your graphics memory usage.
VM Tracker is disabled by default. To profile your application with VM Tracker, click the Instrument, and check theAutomatic Snapshotting flag or press the Snapshot Now button manually.
You will investigate a low memory crash log later on in this tutorial.
Exception Codes
Before you dive into some real-life crash scenarios, there’s one more bit about crash log content that warrants a brief introduction: those funny exception codes.
You can find the exception code in the Exception section of the report – section #3 in the above example. There are a few well-known exception codes that you might encounter often.
Usually, an exception code starts with some text, followed by one or more hexadecimal values, which are processor-specific codes that may give you more information on the nature of the crash. From these codes, you can tell if the application crashed due to a programming error, a bad memory access, or if the application was terminated for some other reason.
Here are some of the more common exception codes:
- 0x8badf00d: Reads as “ate bad food”! (If you squint your eyes and replace the digits with alphabetic characters. :p) This code indicates that an application was terminated by iOS because a watchdog timeout occurred. Basically, the application took too long to launch, terminate, or respond to system events.
- 0xbad22222: This code indicates that a VoIP application was terminated by iOS because it resumed too frequently.
- 0xdead10cc: Read this one as “dead lock”! It indicates that an application was terminated by iOS because it held onto a system resource, like the address book database, while running in the background.
- 0xdeadfa11: Another cute code – read it as “dead fall”! It indicates that an application was force-quit by the user. Per Apple, force quits happen when the user holds down the On/Off button until “slide to power off” appears, then holds down the Home button. As per Apple Documentation, a force quit event results in a 0xdeadfa11 exception code, presumably because the app became unresponsive.
Note: Remember that terminating a suspended app by removing it from the background task list does not generate a crash log. Once an app is suspended, it is eligible for termination by iOS at any time. So no crash log will be generated.
Swimming Time!
All right! You’ve got all the basic background information you need to dive and swim in the pool of crash logs, and fix some nasty bugs! Here is the basic scenario:
You have just started a new job at Rage-O-Rage LLC. The company has a top-selling app in the App Store, Rage Masters.
Your boss, Andy, comes to you and says that to get you started, he has decided to give you a list of different scenarios under which users have claimed the app crashes. Your job is to go through the scenarios and the symbolicated crash logs provided by users, find the bugs in the app, and fix them.
You can download the source code for the app from here.
Note: If you want to regenerate the crash reports for yourself, follow these instructions:
- Download the code and open the project file in Xcode.
- Connect an authorized iOS device with the correct provisioning profile.
- Select the iOS device as the target from the Xcode toolbar – not the Simulator – and build the app.
- As soon as you see the default screen (the full-screen image of the app) on the device, hit the stop button in Xcode.
- Close Xcode.
- Open the app directly on the device.
- Test the scenarios, and after you are finished, connect the device and get the crash logs via Xcode.
Scenario 1: Bad Code for Breakfast
From a user email: “Man, your app is a piece of junk! I downloaded it on my iPod Touch, iPhone and my son’s iPod Touch. On all devices, it crashed before running on the first try…”
Another email says, “I downloaded your app and it crashed. Very unhappy…”
Another email is more specific: “I can’t get your app to run. I downloaded it on all of my devices and on my wife’s. On all of them, it crashed on the first launch…”
OK, don’t take this lying down! Do any of these comments give you a hint? Take a look at the crash log:
Incident Identifier: 85833DBA-3DF7-43EE-AF80-4E5C51091F42 |
Did you find the problem? The exception code is 0x000000008badf00d, and right after that, the report says:
Application Specific Information: |
This means that the app failed to launch in time, and the iOS watchdog terminated the app. Cool! You found the reason, but why (and more importantly, where) is it happening?
Look further down in the log. The convention is to read the backtrace log from the bottom up. The lowest frame (frame 25: libdyld.dylib) is the first call, then frame 24, Rage Masters, main (main.m:16) is called from there, and so on.
You are interested in frames that are related to your app’s code. So ignore system libraries and frameworks. The next line relevant to your code is:
8 Rage Masters 0x0009f244 -[RMAppDelegate application:didFinishLaunchingWithOptions:] (RMAppDelegate.m:35) |
The app failed in application:didFinishLaunchingWithOptions:, on line 35 in RMAppDelegate (RMAppDelegate.m:35). Open Xcode and take a look at that line:
NSData *directoryData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; |
Yep, there it is! A synchronous call to a web service?! On the main thread?! Inapplication:didFinishLaunchingWithOptions:?!! Who wrote this code?!
Network calls on the main thread makes kittens sad.
Anyway, it’s your job to fix it. This call should be asynchronous and, even better, executed from another part of the application, after application:didFinishLaunchingWithOptions: has returned YES.
It might require more extensive changes to move the call elsewhere. So for the moment, just take care of the code so that it doesn’t crash. You can always go back and implement a better design later. Replace the line of offending code from above (and the three lines following it) with an asynchronous version:
[NSURLConnection sendAsynchronousRequest:request |
Scenario 2: Button FUBAR
A user writes: “I can’t bookmark a rage master as my favorite. When I try to, the app crashes…”
Another user says, “Bookmarking doesn’t work… I go to detail info, tap on bookmark button and BOOM!”
The above complaints don’t say much, and there could be any number of causes for the issue they’ve identified. Take a look at the crash log:
Incident Identifier: 3AAA63CC-3088-41CC-84D9-82FE03F9F354 |
The exception code is a SIGABRT. Usually, a SIGABRT exception is raised when an object receives an unimplemented message. Or to put it in simpler terms, there’s a call for a nonexistent method on an object.
Usually this won’t happen, since if you call method “foo” on object “bar”, the compiler will throw an error if the method “foo” doesn’t exist. But when you indirectly call a method using a selector, the compiler might not be able to determine whether or not the method exists on the object.
Back to the crash log. It indicates that the crashed thread is 0. This means that you’re probably looking at a situation where a method was called on an object on the main thread, where the object did not implement the method.
If you continue reading the backtrace log, you see that the only call related to your code is frame 22, main.m:16. That doesn’t help much. :[
Keep going up the framework calls, and there it is:
That isn’t your code. But at least it confirms that there was a call to an unimplemented method on an object.
Go to RMDetailViewController.m, since that’s where the bookmark button is implemented. Find the code that bookmarks the rage master:
-(IBAction)bookmarkButtonPressed { |
That looks OK, so check the storyboard (XIB file) and make sure that the button is hooked up correctly.
There it is! In MainStoryboard.storyboard, the button refers to bookmarkButtonPressed: instead of bookmarkButtonPressed (note the final colon indicating that the method expects a parameter). To fix this, replace the signature of the method above with this:
-(IBAction)bookmarkButtonPressed:(id)sender { |
Of course, you could also simply remove the incorrect connection in the XIB file and reconnect to the method, so that the method signature is correct in the XIB file. Either way works.
And that’s another crash fixed. You’re getting pretty good at this. :]
Scenario 3: Another Bug On the Table
Another user complains saying, “I can’t delete bookmarked masters from the bookmarks view…” And another email about the same issue reads, “If I try to delete a master in bookmarks, the app crashes…”
By now, you are used to these emails not being very helpful. To the crash logs!
Incident Identifier: 5B62D681-D8FE-41FE-8D52-AB7E6D6B2AC7 |
This looks very similar to the previous crash log. It’s another SIGABRT exception. Perhaps you wonder if it’s the same issue: sending a message to an object that has not implemented the method?
Let’s traverse through the backlog and see what methods were called. Start from the bottom. The last call to your code in Rage Masters is at frame 6:
6 Rage Masters 0x00088c66 -[RMBookmarksViewController tableView:commitEditingStyle:forRowAtIndexPath:] (RMBookmarksViewController.m:68) |
Well, this is a UITableViewDataSource method. Huh?! You are pretty sure Apple has implemented this method – you can override it, but it is not like it hasn’t been implemented. Plus, it is an optional delegate method. So the problem isn’t a call to an unimplemented method.
Take a look at the frames after that call:
3 Foundation 0x346812aa -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 86 |
In frame 5, UITableView is calling another method of its own, deleteRowsAtIndexPaths:withRowAnimation: and then _endCellAnimationsWithContext: is called, which looks like an internal Apple method. Then the Foundation framework raises an exception, handleFailureInMethod:object:file:lineNumber:description:.
Putting the above together with the user complaints, it looks as if you are dealing with a buggy deletion procedure in UITableView. Go to Xcode. Do you know where to go? Can you tell from the crash log? It’s line 68 inRMBookmarksViewController.m:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { |
Can you tell where the problem is? I’ll wait while you take a look.
You got it! How about the data source? The code deletes a row in the table view, but doesn’t change the data source behind it. To fix this, replace the above method with the following one:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { |
That should do it! Take that, you nasty bug!! BIFF!!! BANG!!!! CRASH!!!!!
Scenario 4: Leggo Those Licks!
The email says, “My app crashes when a rage master is licking a lollipop…” Another user writes, “I tell the rage master to lick the lollipop few times, and then the app crashes!”
Here’s the crash log:
Incident Identifier: 081E58F5-95A8-404D-947B-5E104B6BC1B1 |
This log is very different from what you’ve seen so far!
This is a low memory crash log from iOS 6. As discussed earlier, low memory crash logs are different from other types of crash logs because they don’t point to a specific file or line of code. Instead, they paint a picture of the memory situation on the device at the time of the crash.
The header, at least, is similar to that of other crash logs: it provides the Incident Identifier, CrashReporter Key, Hardware Model, OS Version, and some other information.
The next section is specific to low memory crash logs:
- Free pages refers to available memory. Each page is approximately 4KB, so in the log above, available memory is about 3,872 KB (or 3.9 MB).
- Purgeable pages are those parts of memory that can be purged and reused. In the log above, it is 0KB.
- Largest process refers to the application that was using most of the memory at the time of the crash, which in this case is your app!
- Processes gives you a list of processes, along with their memory usage at the time of the crash. You are given the name of the process (first column), the unique identifier of the process (second column), and the number of pages being used by the process (third column). In the last column, State, you can see the state of each app. Usually, the app that caused the crash is the app with the frontmost state. Here it is Rage Masters, which was using 28591 pages (or 114.364 MB) – that’s a lot of memory!
Usually, the largest process and the frontmost app are the same, and are also the process that has caused the low memory crash. But you may see some instances where the largest process and the frontmost app are not the same. For example, if the largest process is SpringBoard, ignore it, because SpringBoard is the process that shows the apps on the home screen, the popups that appear when you double tap the home button, etc. and is always active.
When low memory situations happen, iOS sends a low memory warning to the active application and terminates background processes. If the frontmost app still continues to grow in memory, iOS jettisons it.
To find the reason for the low memory issues, you need to profile your app using Instruments. You won’t be doing that here, since we already have a tutorial for that. :] Instead, you’ll take a shortcut and just respond to the low memory warning notification that the app receives to solve this particular crash.
Switch to Xcode and go to RMLollipopLicker.m. This is where the lollipop licker view controller is implemented. Take a look at the source code:
#import "RMLollipopLicker.h" |
When the user taps the run button, the app starts a background operation, calls lickLollipop a number of times, and then updates the UI to reflect the number of licks. lickLollipop reads a big NSString from a property list (PLIST) and adds it to an array. This data is not crucial, and can be recreated without affecting the user experience.
It’s a good habit to take advantage of every situation where you can purge data and recreate it without adversely affecting the user experience. This frees up memory, making low memory warnings less likely.
So how can you improve the code here? Implement didReceiveMemoryWarning and get rid of the data in lollipops as follows:
-(void)didReceiveMemoryWarning { |
That should be it!
Where to Go From Here?
Hooray, you made it through all four crash scenarios! Your app works much better and you learned some important debugging skills along the way. :]
You can download the improved project here.
How did you like demystifying iOS crash logs? I encourage you to continue your learning by trying this out in your own apps – and hopefully solving the crashes and making your apps more robust!
If you have any questions or comments on this tutorial or crash logs in general, please join the forum discussion below!
This is a blog post by Soheil Moayedi Azarpour, an independent iOS developer. You can also find him on Google+.
Soheil Moayedi Azarpour is an independent iOS developer. He’s worked on iOS applications for clients as well as his own personal apps. You can find him on Twitter, GitHub, Stack Overflow and connect on LinkedIn.
Demystifying iOS Application Crash Logs的更多相关文章
- Understanding and Analyzing Application Crash Reports
Introduction When an application crashes, a crash report is created and stored on the device. Crash ...
- IOS Application Security Testing Cheat Sheet
IOS Application Security Testing Cheat Sheet [hide] 1 DRAFT CHEAT SHEET - WORK IN PROGRESS 2 Int ...
- iOS解析crash日志:
iOS解析crash日志:我们在ios开发中会碰到的很多crash问题,如果Debug调试模式的话,我们可以往往很容易的根据log的输出定位到导致crash的原因,但对于已经上线的应用,或者是rele ...
- [转]Running JavaScript in an iOS application with JavaScriptCore
原文:https://www.infinum.co/the-capsized-eight/articles/running-javascript-in-an-ios-application-with- ...
- iOS 调试 crash breakpoint EXC_BAD_ACCESS SIGABRT
原文地址:iOS 调试 crash breakpoint EXC_BAD_ACCESS SIGABRT作者:流年若离殇 在调试程序的时候,总是碰到crash的bug,而且一追踪就是一些汇编的代码,让人 ...
- iOS 苹果官方 Crash文件分析方法 (iOS系统Crash文件分析方法)
时间2013-08-20 12:49:20 GoWhich原文 http://www.gowhich.com/blog/view/id/343 苹果官方 Crash文件分析方法 (iOS系统Cras ...
- iOS Application Project与OS X Application Project对于plist使用的区别
前几天因为在开源中国看到一个求源代码的问题: 模拟一个动物园系统MyZoo 1.动物园里面有三种动物:Panda,Elephant,Kangaroo 2.三种动物都有一定的数量(不止一只) 3.动物有 ...
- Persisting iOS Application Data in SQLite Database Using FMDB
In previous articles we have utilized NSUserDefaults and .NET web services to persist iPhone data. N ...
- iOS Application Security
文章分A,B,C,D 4个部分. A) iOS Application Security 下面介绍iOS应用安全,如何分析和动态修改app. 1)iOS Application security Pa ...
随机推荐
- B1086 就不告诉你 (15分)
B1086 就不告诉你 (15分) 做作业的时候,邻座的小盆友问你:"五乘以七等于多少?"你应该不失礼貌地围笑着告诉他:"五十三."本题就要求你,对任何一对给定 ...
- 17-比赛2 F - Fox And Two Dots (dfs)
Fox And Two Dots CodeForces - 510B ================================================================= ...
- 笔记-git-.gitignore
笔记-git-.gitignore 1. git忽略文件 有的文件不需要提交到公共仓库中,为此git提供了三种实现方式. gitignore文件 在项目的设置中指定排除文件 定义全局.git ...
- 笔记-scrapy-Request/Response
笔记-scrapy-Request/Response 1. 简介 Scrapy使用Request和Response来爬取网站. 2. request class scrapy.http ...
- 如何使用Idea导入jar包
技术交流群: 233513714 1.在idea底部找到Terminal,然后进入输入框,如下图所示 2.在输入框中输入 mvn install:install-file -D file=C:\Use ...
- oracle(sql)基础篇系列(二)——多表连接查询、子查询、视图
多表连接查询 内连接(inner join) 目的:将多张表中能通过链接谓词或者链接运算符连接起来的数据查询出来. 等值连接(join...on(...=...)) --选出雇员的名字和雇员所在的部门 ...
- 常用正则表达式 -- 费元星 java大神
正则表达式用于字符串处理.表单验证等场合,实用高效.现将一些常用的表达式收集于此,以备不时之需. 匹配中文字符的正则表达式: [\u4e00-\u9fa5]评注:匹配中文还真是个头疼的事,有了这个表达 ...
- 我给女朋友讲编程CSS系列(4) CSS盒子模型
什么是CSS盒子模型?如何学习CSS的盒子模型? 这篇文章,以 [分享 + 结论] 的方式来写. 1, 看w3school的[CSS 框模型概述] 网址为: http://www.w3school ...
- CSS UNIT 详解以及最佳实践
分类 ■ 绝对长度(Absolute units):cm,mm,in,pt,pc 绝对单位之间的换算:1in = 2.54cm=25.4mm=72pt=6pc 绝对长度在css中的表现和其他地方 ...
- centos7系列问题
一.CentOS7.1查看ip route有两条路由规则 1.metric值是指到达目的地需要的跳数,是表达该条路由连接质量的指标.当有多条到达相同目的地的路由记录时,路由器会采用metric值小的那 ...