Original address: http://www.cocoachina.com/macdev/objc/2011/0219/2661.html
It is not scary to write programs that encounter bugs, most of which are not difficult to find because of simple Log or code analysis. However, when encountering exc_bad_access problems in objective-c programming, it is difficult to find the problem by simple and conventional means. This article gives you a common way to find the root cause of exc_bad_access problems.
First of all, exc_bad_access this error, so to speak, 90% of the source of error is to release an object that has been released. Take a simple example to illustrate, first look at a piece of Java code:
public class test{
public static void Main (string[] args) {
string s = "This is a test string";
s = s.substring (S.indexof ("a"), (S.length ()));
System.out.println (s);
}
}
This type of writing is common in Java and common, and this does not create any problems. But in the objective-c, there will be an accident, consider this procedure:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * Pool = [[NSAutoreleasePool alloc] init];
nsstring* s = [[NSString alloc]initwithstring:@ "This is a test string"];
s = [s substringfromindex:[s rangeofstring:@ "a"].location];//memory leaks
[s release];//error release
[Pool drain];//exc_bad_access
return 0;
}
This example, of course, is easy to see the problem, if the code is contained in a large logic, it is easy to ignore. Objective-c This code has three fatal problems: 1, memory leak, 2, error release, 3, cause exc_bad_access error.
1, nsstring* s = [[NSString alloc]initwithstring:@ "This is a test string"]; A nsstring Object is created, followed by S = [s substringfromindex:[s rangeofstring:@ "a"].location]; After execution, the object reference that was created disappears, causing a memory leak directly.
2, error free. [s release]; One of the reasons for this problem is a logic error, thinking that S is still the NSString object we created originally. The second is because the NSString object returned from Substringfromindex: (Nsuinteger i) does not need us to release it, it is actually an object that is marked as autorelease by the Substringfromindex method. If we forcibly release it, then it will cause exc_bad_access problems.
3, Exc_bad_access. Because the NSString object pointed to by S is marked as autorelease, there is already a record in NSAutoreleasePool. But since we released the object in the wrong way, when [pool drain], NSAutoreleasePool once again called the release method on its recorded S object, but this time S has been released no longer exists, it directly caused the EXC_BAD_AC Cess problem.
Then, knowing the exc_bad_access of one of the causes, how to quickly and efficiently locate the problem.
1: Add the nszombieenabled environment variable to the project runtime and set to Enabled, and when exc_bad_access occurs, XCode's Console prints a description of the problem.
First double-click the executable module under executables in the XCode project,
In the pop-up window, Variables to is set in the environment, add nszombieenabled, and set to YES, click the check box to enable this variable.
In this way, you will see the console output when you run the OBJECTIVE-C: untitled[3646:a0f] * * *-[cfstring release]: message sent to deallocated instance 0x10010d340
This message is a good indication of the location problem. But many times, only this hint is not enough, we need more hints to help locate the problem, then join mallocstacklogging to enable malloc record.
When the error occurs, execute at the terminal:
Malloc_history ${app_pid} ${object_instance_addr}
The corresponding malloc history is obtained, for example, for the previous console output
UNTITLED[3646:A0F] * * *-[cfstring release]: message sent to deallocated instance 0x10010d340
Then we can execute it at the terminal, the result is as follows:
Buick-wongs-macbook-pro:downloads buick$ malloc_history 3646 0x10010d340
Malloc_history Report version:2.0
process:untitled [3646]
Path:/users/buick/desktop/untitled/build/debug/untitled
Load address:0x100000000
Identifier:untitled
Version:??? (???)
Code type:x86-64 (Native)
Parent Process:gdb-i386-apple-darwin [3638]
date/time:2011-02-01 15:07:04.181 +0800
OS version:mac os X 10.6.6 (10j567)
Report Version:6
ALLOC 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | Main | Objc_msgsend | Lookupmethod | Prepareformethodlookup | _class_initialize | +[nsstring Initialize] | Objc_msgsend | Lookupmethod | Prepareformethodlookup | _class_initialize | Nxcreatemaptablefromzone | Malloc_zone_malloc
—-
Free 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | Main | Objc_msgsend | Lookupmethod | Prepareformethodlookup | _class_initialize | _finishinitializing | Free
ALLOC 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | Main | -[nsplaceholderstring initwithstring:] | Objc_msgsend | Lookupmethod | Prepareformethodlookup | _class_initialize | _class_initialize | +[nsmutablestring Initialize] | Objc_msgsend | Lookupmethod | Prepareformethodlookup | _class_initialize | Nxcreatemaptablefromzone | Malloc_zone_malloc
—-
Free 0x10010d340-0x10010d357 [size=24]: thread_7fff70118ca0 |start | Main | -[nsplaceholderstring initwithstring:] | Objc_msgsend | Lookupmethod | Prepareformethodlookup | _class_initialize | _class_initialize | _finishinitializing | Free
ALLOC 0x10010d340-0x10010d35f [size=32]: thread_7fff70118ca0 |start | Main | -[nscfstring Substringwithrange:] | cfstringcreatewithsubstring | __cfstringcreateimmutablefunnel3 | _cfruntimecreateinstance | Malloc_zone_malloc
This will quickly locate the code fragment of the problem, pay attention to the last line of the output, this line is not the final cause of the issue, but the problem is very close to the point, as it went on, probably will find the problem.