Cocoa

Управление памятью в Objective C

При разработке софта под iPhone, столкнулся с проблемой непонимания механизма распределения памяти. Являясь java-разработчиком, привыкшим к чудесам Garbage Collector'а, тема памяти в Objective C поначалу доставляла мне массу неприятностей. Спустя некоторое время, написав свое первое приложение, я подумал, что полностью разобрался в этой непростой теме... и это было моей ошибкой. Все таки, сначала надо хорошо читать мануалы и желательно до конца :)

Назвал я данную тему непростой не из-за сложности механизмов управления памятью - они то как раз более-менее понятные и простые, а, скорее, из-за того, что не разобравшись до конца, как правильно "освободить" объект из памяти, можно получить массу сложноотлавливаемых ошибок типа EXC_BAD_ACCESS, причем необязательно именно в том месте, где была допущена ошибка распределения памяти.

Cocoa / iPhone: отладка ошибки EXC_BAD_ACCESS

Если вы хоть раз занимались разработкой программного обеспечения под iPhone, то наверняка встречались с ошибкой EXC_BAD_ACCESS. Отловить ее достаточно непросто, т.к. встроенный дебагер не покажет вам нужный стектрейс и тем более не подскажет, как все исправить.

Что же такое EXC_BAD_ACCESS? Мне удобнее сравнивать эту ошибку с NullPointerException в Java, т.к. возникает она в ситуации, когда вы отправляете "сообщение" объекту, который уже был выгружен из памяти (released). Например, попробуйте создать объект с помощью alloc и затем два раза подряд его "отпустить" с помощью release.

Так как же быть, если у нас достаточно большой проект с массой кода и объектов? Как проще и быстрее отловить данную ошибку? На помощь придет директива NSZombiEnabled, установленная в переменных окружения проекта. Все, что она сделает - это заставит Objective C runtime оставлять объект-пустышку за каждым выгруженным реальным объектом и в следующий раз, когда вы попытаетесь обратиться к своему выгруженному объекту, вызов пойдет именно к пустышке, которая остановит выполнение кода и выведет короткое и ясное сообщение в дебагер о том, какой объект был вызван и что за сообщение ему было отправлено. Стектрейс при этом также не будет испорчен, и сможет дать дополнительную информацию о месте баги.

2010-01-08 16:21:35.802 My Project[4833:207] *** -[NSMutableURLRequest release]: message sent to deallocated instance 0x4925f30

Cocoa / iPhone: форматирование даты

Простой пример для тех, кто ищет простой и быстрый путь отформатировать дату при разработке под iPhone. В моем примере будем форматировать дату по стандарту RFC2822.

NSString *rfcDate = @"Mon, 4 Jan 2010 20:41:12 +0300";

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];

/* Установка локали обязательна, т.к. иначе будет использована текущая */
NSLocale *enUS = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
[formatter setLocale:enUS];
[enUS release];
[formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss ZZ"];
NSDate *theDate = [formatter dateWithString:rfcDate];

Данный подход достаточно прост и эффективен, но у него есть один минус - куча строк, которые придется писать каждый раз, когда надо сделать преобразование. Чтобы этого избежать можно сделать так: