Вандад Нахавандипур - iOS. Приемы программирования
- Название:iOS. Приемы программирования
- Автор:
- Жанр:
- Издательство:Питер
- Год:2014
- Город:Санкт-Петербург
- ISBN:978-5-496-01016-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Вандад Нахавандипур - iOS. Приемы программирования краткое содержание
Книга, которую вы держите в руках, представляет собой новый, полностью переписанный сборник приемов программирования по работе с iOS. Он поможет вам справиться с наболевшими проблемами, с которыми приходится сталкиваться при разработке приложений для iPhone, iPad и iPod Touch. Вы быстро освоите всю информацию, необходимую для начала работы с iOS 7 SDK, в частности познакомитесь с решениями для добавления в ваши приложения реалистичной физики или движений — в этом вам помогут API UIKit Dynamics.
Вы изучите новые многочисленные способы хранения и защиты данных, отправки и получения уведомлений, улучшения и анимации графики, управления файлами и каталогами, а также рассмотрите многие другие темы. При описании каждого приема программирования приводятся образцы кода, которые вы можете смело использовать.
iOS. Приемы программирования - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
— (void) firstCounter{
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"First Counter = %lu", (unsigned long)counter);
}
}
— (void) secondCounter{
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Second Counter = %lu", (unsigned long)counter);
}
}
— (void) thirdCounter{
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Third Counter = %lu", (unsigned long)counter);
}
}
Очень просто, правда? Все циклы проходят от 0 до 1000, выводя на консоль номера счетчиков. Теперь предположим, что вы хотите, как обычно, запустить эти счетчики:
— (void) viewDidLoad{
[super viewDidLoad];
[self firstCounter];
[self secondCounter];
[self thirdCounter];
}
Этот код не обязательно должен находиться в методе viewDidLoad контроллера вида.
Теперь откройте окно консоли и запустите это приложение. Вы увидите, как сначала целиком выполнится первый счетчик, потом второй и, наконец, третий. Это означает, что данные циклы выполняются в одном и том же потоке. Каждый счетчик блокирует исполнение остального кода, относящегося к потоку, пока этот счетчик не завершит свой цикл.
А что, если бы мы захотели запустить все счетчики одновременно? Разумеется, для каждого из них нам пришлось бы создать отдельный поток. Но подождите! Мы ведь уже знаем, что прямо при загрузке приложение само создает для нас потоки. Кроме того, весь код, который мы уже успели создать для приложения, когда бы он ни был написан, исполняется в полученном потоке. Итак, мы уже создали по потоку для первого и второго счетчиков, а третий счетчик будет работать в главном потоке:
— (void) firstCounter{
@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"First Counter = %lu", (unsigned long)counter);
}
}
}
— (void) secondCounter{
@autoreleasepool {
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Second Counter = %lu", (unsigned long)counter);
}
}
}
— (void) thirdCounter{
NSUInteger counter = 0;
for (counter = 0;
counter < 1000;
counter++){
NSLog(@"Third Counter = %lu", (unsigned long)counter);
}
}
— (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:@selector(firstCounter)
toTarget: self
withObject: nil];
[NSThread detachNewThreadSelector:@selector(secondCounter)
toTarget: self
withObject: nil];
/* Этот код запускаем в главном потоке. */
[self thirdCounter];
}
У метода thirdCounter нет автоматически высвобождаемого пула, поскольку он не работает в новом открепленном потоке. Этот метод будет выполняться в главном потоке приложения, а главный поток располагает автоматически высвобождаемым пулом. Данный пул создается автоматически при написании любого приложения Cocoa Touch.
Ближе к концу кода мы видим вызовы селектора detachNewThreadSelector, предназначенные для запуска первого и второго счетчиков в отдельных потоках. Теперь, запустив приложение, вы увидите в окне консоли примерно следующий вывод:
Second Counter = 921
Third Counter = 301
Second Counter = 922
Second Counter = 923
Second Counter = 924
First Counter = 956
Second Counter = 925
First Counter = 957
Second Counter = 926
First Counter = 958
Third Counter = 302
Second Counter = 927
Third Counter = 303
Second Counter = 928
Иными словами, все три счетчика работают одновременно и их вывод перемежается случайным образом.
Каждый поток должен создавать автоматически высвобождаемый пул. Внутри такого пула содержатся ссылки на объекты, автоматически высвобождаемые до того, как будет высвобожден весь пул. Это очень важный механизм, действующий при управлении памятью с подсчетом ссылок в таких окружениях, как Cocoa Touch, то есть в средах, где объекты могут автоматически высвобождаться. Всякий раз при выделении экземпляра объекта количество ссылок на объект становится равным 1. Если пометить объекты как автоматически высвобождаемые, то количество ссылок на объект остается равным 1, но только до того момента, как высвободится тот пул, в котором создан объект. При высвобождении всего пула объект также получает сообщение release. Если на данный момент количество ссылок на объект так и осталось равным 1, объект высвобождается.
В каждом потоке необходимо создавать автоматически высвобождаемый пул, причем это должен быть самый первый объект, создаваемый в конкретном потоке. Если этого не сделать, то любой объект, создаваемый в потоке на протяжении его существования, будет вызывать утечку памяти. Чтобы лучше понять эту проблему, рассмотрим следующий код:
— (void) autoreleaseThread:(id)paramSender{
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:@"AnImage"
ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile: filePath];
/* Делаем что-нибудь с изображением. */
NSLog(@"Image = %@", image);
}
— (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:@selector(autoreleaseThread:)
toTarget: self
withObject: self];
}
Если запустить этот код и одновременно следить за окном консоли, то можно увидеть примерно следующее сообщение:
*** __NSAutoreleaseNoPool(): Object 0x5b2c990 of
class NSCFString autoreleased with no pool in place — just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b2ca30 of
class NSPathStore2 autoreleased with no pool in place — just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b205c0 of
class NSPathStore2 autoreleased with no pool in place — just leaking
*** __NSAutoreleaseNoPool(): Object 0x5b2d650 of
class UIImage autoreleased with no pool in place — just leaking
Эти данные свидетельствуют о том, что созданный нами автоматически высвобождаемый экземпляр UIImage приводит к утечке памяти. Более того, утечку вызывают и экземпляр класса NSString под названием FilePath, а также другие объекты, которые в обычной ситуации спокойно высвободились бы. Дело в том, что при создании потока мы забыли первым делом выделить и инициализировать автоматически высвобождаемый пул — именно первым делом. Далее приведен правильный код. Можете сами его протестировать и убедиться, что никаких утечек не возникает:
— (void) autoreleaseThread:(id)paramSender{
@autoreleasepool {
NSBundle *mainBundle = [NSBundle mainBundle];
NSString *filePath = [mainBundle pathForResource:@"AnImage"
ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile: filePath];
/* Делаем что-то с изображением. */
NSLog(@"Image = %@", image);
}
}
— (void)viewDidLoad {
[super viewDidLoad];
[NSThread detachNewThreadSelector:@selector(autoreleaseThread:)
toTarget: self
withObject: self];
}
7.16. Активизация фоновых методов
Постановка задачи
Необходимо найти простой способ создания потоков так, чтобы с потоками не приходилось работать напрямую.
Читать дальшеИнтервал:
Закладка: