Ошибки в Objective-C


6 0

Играюсь с Objective-C, изучаю его и заодно пишу пару небольших примеров. Один из них связан с интернет программкой, другой – графический движок для себя (вспоминаю OpenGL). В одном месте у мне понадобилось часто использовать однообразные объекты, причем очень много раз. Логично стало не загружать их каждый раз и не освобождать память, а написать кэш, который будет сохранять данные для меня.

В качестве кэша я сделал статичную переменную для менеджера кэша, а сами данные решил размещать в NSMutableDictionary. Это что-то типа хэша. Переменная для хэша была объявлена у класса, а метод получения данных из него выглядит следующим образом:

cachedData = [cache objectForKey:filename];
if (cachedData) {
	return cachedData;
}
	
cachedData = [[MFLData alloc] initWithFilename:filename];
[cache setObject:cachedData forKey:filename];
    
return cachedData;

Никогда не видевший синтаксиса Objective-C да ужаснись. На самом деле я уже привык к нему. Вполне нормально работает. На C# это будет выглядеть как:

cachedData = cache[filename];
if (cachedData != null) {
	return cachedData;
}
	
cachedData = new MFLData(filename);
cache[filename] = cachedData;
    
return cachedData;

Запускаю программу и вижу, что все работает нормально на моем компьютере. Я этот код написал примерно месяц назад и забыл уже. Как только получил свой iPhone решил попробовать на нем. Установил программку на телефон, минут 10 работы в ней и программа перезагружает телефон. Что, думаю, за фигня. Попробовал еще раз. То же самое. Я уже и забыл про свой кэш и сначала думал, что где-то косяк доступа к памяти или еще что.

Вчера запустил профайлер и начал смотреть утечки памяти. Ничего не утекает, потому что я использую autorelease, а с ним не может ничего утекать. Зато заметно, что в те моменты, когда должна происходить загрузка из файлов, происходит скачок в использовании памяти. За 5 минут программа сжирает до 100 мегабайт памяти, что для настольного компьютера фигня из под коня, а для телефона серьезная проблема.

Нечал тестировать свой кэш и вот блин, переменная cache оказывается нигде не проинициализирована. Она просто нулевая. Когда я проверяю, есть ли что в кеше ([cache objectForKey:filename] – в С# аналогом будет cache[filename]), переменная cache не существует и Objective-C просто игнорирует любые сообщения для нулевого объекта, поэтому ничего не падает, все работает, зато в кэше ничего не сохраняется и я просто уничтожаю память телефона в мгновения ока. Пример на C# уже давно шарахнулся бы с исключением.

Этот пример показал мне, почему программы для iPhone и для Apple вообще падают реже. Если где-то вы обратитесь к несуществующей переменной, ошибка будет проигнорирована и вполне вероятен случай, когда все будет нормально работать. Как доказывает FireFox – утечка памяти не является причиной провала программы и можно распространять программы с проливами памяти.

Удивило то, что iPhone перезагружался, когда я съедал память. Может из-за того, что он в режиме разработчика, но я бы ожидал от него вылета программы. ОС вполне в состоянии увидеть, что памяти не достаточно и вырубить мою программу. Тут конечно же и я виноват, потому что не во всех объектах проверяю после alloc была ли выделена память. Я не проверяю как раз в объекте, который создается и уничтожается с данными из кэша. Нужно будет это исправить, но ОС могла бы и помочь, хотя и не обязана. Я тут был виноват, но пользователям телефона будет пофиг, что это программист программы налажал, а не телефон глючит и перезагружается.


Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым


Комментарии

Verus

28 Марта 2012

А какую Вы SDK исапользуете7


Михаил Фленов

28 Марта 2012

Стоит последняя XCode и последний SDK 5.1, но компилирую для платформы 4.3.


XC

28 Марта 2012

Михаил, я бы вам посоветовал обратиться в сервис с телефоном, я пишу под иос и сжирание памяти даже более катастрофическими методами приводит лишь к вылету приложения а не к перезагрузке телефона (мои тесты проходит на двух 3GS ,одном 4 и одном 4S).


Михаил Фленов

28 Марта 2012

Программа вылетала на двух разных телефонах, так что не думаю, что это телефон. Скорей всего все же iOS. Сейчас уже не буду издеваться над примером, уже все оптимизировал и сейчас программа жрет всего 20 мегабайт оперативки.


XC

28 Марта 2012

Хотелось бы поближе взглянуть на цельный вариант программы что привела к перезагрузке телефона ) мне такие фокусы ещё не удавались)


crsib

28 Марта 2012

О, это еще мелочи. Я как-то года три назад случайно писал в поле класса из селектора класса (статического метода в более привычной терминологии). И компилятор нормально это жрал, отделываясь ворнингом. А ворнингов было много, потому что на тот момент не успели исправить все deprecation ворнинги, коих было немерено после перехода на SDK 3.0. Приложение регулярно падало в селекторах класса, находящегося в следующей единице компиляции, потому что волшебным образом переписывалась isa следующего по компиляции класса. И вот вопрос, почему компилятор счел это semantic warning'ом, а не ошибкой, до сих пор открыт(

Так же открыт вопрос, как можно было без предупреждения разрушить совместимость iOS 5+ с приложениями собранными с более старыми версиями SDK. Причем приложение молча стартует, а затем в некий момент падает имея в колстеке вызовы из фреймворков iOS. Банальная пересборка с новым SDK проблему, внезапно, решает.


Добавить Комментарий

Еще что-нибудь

Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне