Category Archives: Objective-C

Debugging EXC_BAD_ACCESS

This article is from http://www.cnblogs.com/junz/archive/2010/05/23/1742118.html , useful for debugging the annoying EXC_BAD_ACCESS exception.


You have to accept the fact that sooner or later you will need to debug an EXC_BAD_ACCESS problem and most probably won’t be easy to.

This article however is about how to make the process easier, in some cases easy as a piece of cake.

What does EXC_BAD_ACCESS mean?

EXC_BAD_ACCESS means that message was sent to a point in the memory where there’s no instance of a class to execute it. Thus “bad access”

When EXC_BAD_ACCESS happen?

You will get EXC_BAD_ACCESS in 3 cases:

  1. An object is not initialized
  2. An object is already released
  3. Something else that is not very likely to happen

That’s already a good starting point. Start using the debugger, if you recently added a new object to the class you’re working on, put a breakpoint at the line before the freshly added object is used for the first time and check the values in the debugger.

What’s happening most though is that you will be sending a message to an overreleased object – i.e. object that is gone from the call stack. In this cases everything (and indeed everything) you will get in the console will be just :

EXC_BAD_ACCESS.

This is because the object is gone, there is no information what class was it, or what source file or anything else. That’s really tough to debug with NSLog … NSLog is helpful, but you need to put 1,000 NSLogs around to fetch where is the problem.

Enabling NSZombies

The solution to overreleased objects are the zombies. When this feature is enabled, a dummy object (a zombie) is kept on the place of every released object, thus allowing to debug objects which were released already. Very easy to enable:

  1. Double click your executable in the “Executables” in XCode
  2. Open “Arguments” tab
  3. In “Variables to be set in the environment” (that’s the list at the bottom, be careful which one you edit) click the “+” button and for name of the variable enter “NSZombieEnabled” and for value “YES”

Voila!

Now instead of wondering what’s going on and which exact object produced the problem, you’ll see exactly which class is the trouble maker, and you’ll debug it quite fast.

Beware the zombies though

Just a reminder not to leave the zombies enabled, when you submit your app to the App store. Also, it’s a good practice to disable them if you don’t really need them.

How to enable “swipe to delete” for UITableViewCell

- (UITableViewCellEditingStyle)tableView:(UITableView *)aTableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
// No editing style if not editing or the index path is nil.
if (self.editing == NO || !indexPath) return UITableViewCellEditingStyleDelete;
}

Get a list of the languages that iPhone supports

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defaults objectForKey:@"AppleLanguages"];
NSLog(@"%@", languages);

NSMutableArray count always returns zero

The code is as follows, rowsToUpdate is NSMutableArray *, [sites count] is greater than 0, and there is value for row index, but [rowsToUpdate count] always returns 0:

	for (int i=0; i<[sites count]; i++) {
		NSLog(@"row index: %i, %@", i, [NSString stringWithFormat:@"%i", i]);
		[rowsToUpdate addObject:[NSString stringWithFormat:@"%i", i]];
		NSLog(@"[rowsToUpdate count] = %i", [rowsToUpdate count]);
	}

There is no obvious problem with the code, and it doesn’t make sense to return 0.

After a couple of search, I found it on stackoverflow.com that I missed the initialization for “rowsToUpdate”. The fix is as follows (a couple lines of code added):

	if (rowsToUpdate == nil) {
		rowsToUpdate = [[NSMutableArray alloc] init];
	}
	else {
		[rowsToUpdate removeAllObjects];
	}

	for (int i=0; i<[sites count]; i++) {
		NSLog(@"row index: %i, %@", i, [NSString stringWithFormat:@"%i", i]);
		[rowsToUpdate addObject:[NSString stringWithFormat:@"%i", i]];
		NSLog(@"[rowsToUpdate count] = %i", [rowsToUpdate count]);
	}

Xcode Warning: “UIKeyboardBoundsUserInfoKey” is deprecated

Simply use “UIKeyboardFrameBeginUserInfoKey” instead:

NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];

NSURL Tips

# Loading a string from a website
(this will block until it loads)

    NSURL *url;
    NSData *data;
    NSString *blork;
    url = [NSURL URLWithString: @"https://langui.net/"];
    data = [url resourceDataUsingCache: NO];
    blork = [[NSString alloc] initWithData: data  encoding: NSASCIIStringEncoding];

# Loading an image from a website
(this will block until it loads)

    NSURL *url;
    NSData *data;
    NSImage *blork;
    url = [NSURL URLWithString: @"https://langui.net/wp-content/uploads/2011/03/banner.png"];
    data = [url resourceDataUsingCache: NO];
    blork = [[NSImage alloc] initWithData: data];

# Open an URL in iphone safari

    NSURL *url = [NSURL URLWithString: @"https://langui.net/"];
    [[UIApplication sharedApplication] openURL: url];

More tips available here: http://borkware.com/quickies/

Converting NSString* to NSData* and Vice Versa

NSString* str = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSData* data = [str dataUsingEncoding: NSASCIIStringEncoding];

How-To: URL Encode NSString in Objective-C

NSString *url = [@"langui.net" stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];

Converting unsigned char array to NSString *

The code snippet:

NSString* s = [[NSString alloc] initWithBytes:buffer length:sizeof(buffer) encoding:NSASCIIStringEncoding];

Calling C Functions from Objective-C

As Objective-C is a superset of C, it allows developers to mix pure c source files with Object-C source files.

But to call a C function from Objective-C, you should not import the .c file in your Objective-C .m file, that won’t work.

To call a C function from the Objective-C, you need to create a .h header file to include the C function declaration, and, of cause, include the .h file in the .c source file where the C function resides. Then import the .h file in the .m source file where you would like to call the C function, and simply call the function.