Для того чтобы облегчить работу с потоками в Objective C был создан класс NSThread, как и многие другие классы он был перенесён в Thread без приставки NS. В данной лекции мы подробнее рассмотрим работу с ним. Работать c Thread намного удобнее чем с APIPiThread. Все потоки создаются типа detacht, но вызывать у них метод для открепления не нужно. Есть два способа создания потока: первый способ - воспользоваться статической методом. Метод для создания такого потока принимает на вход селектор, цель на который этот селектор будет вызван и аргумент, который будет передан в этот селектор. Для этого нам пришлось создавать класс и делать метод доступным для Objective C. Также начиная IOS10 доступно использование замыканий, в этом случае метод не принимает дополнительных аргументов. У этого способа есть недостаток - созданный поток сразу запускается, мы не можем перед запуском поменять ему, например, приоритет. Второй способ позволяет этого избежать. Для создания потока используется инициализатор класса Thread, он принимает те же аргументы, после создания объекта можно изменить его параметры. Приоритет потока выставляется в свойстве ThreadPriority и может принимать значения от нуля до единицы. Система, при планировании ресурсов, будет принимать решение о порядке потоков, учитывая это значение, однако, выставление высокого приоритета, не гарантирует порядок и время начала выполнения потока. Если вы поддерживаете только IOS8 и более новые версию, то лучше воспользоваться Quality of service - это универсальный способ выставления приоритетов используемый в различных API. Свойство Quality of service можно принимать пять значений: background - самый низкий приоритет, его нужно использовать если время выполнения задачи не важно. Например, для синхронизации или индексации. Обычный результат выполнения таких задач не виден пользователю. Utility - можно использовать и для автоматических операций, и для инициированных пользователем, но только, если очевидно, что для выполнения этой операции требуется время. Примером могут быть, импорт больших медиа-файлов или обработка большого количества данных. Не забывайте в таких случаях использовать какой-то индикатор прогресса для пользователя. Default - средний приоритет, означает, что приоритет для задачи не задан явно. UserInitiated - высокий приоритет, используется для задач инициированных пользователем, если он ожидает их немедленного выполнения. Например, загрузка полноразмерного изображения при нажатии на preview или загрузка полной версии текста статьи при выборе её из списка с заголовком. UserInteractiv - самый высокий приоритет, используются при взаимодействии пользователя с интерфейсом. Например, для перерисовки каких-то элементов интерфейса, при их перемещении пользователем. Использование CuOS естественно тоже не гарантирует порядок выполнения, решение о переключение потоков, в любом случае, остается за OES. Для запуска потока нужно вызвать метод start, для остановки cancel, однако с остановкой не всё так просто, нельзя просто так прерывать выполнение потока, это может привести к повреждению данных, вместо прерывания потока, при вызове метода cancle, просто изменяется значение свойства из ncle в true. Далее, ваша обязанность во время выполнения потока проверить значение этой переменной. Если это имеет, в вашем случае смысл, нужно перевести данные в правильные состояние, например, отменив все изменения и осуществить выход из функции. Продемонстрируем это на простом примере. Для этого воспользуемся вторым инициализатором потока, принимающим замыкание, с помощью статистического свойства current можно обратиться к текущему потоку. Внутри замыкания, в цикле, мы проверяем значение свойства isCancelled, если оно равно true, то выходим из цикла, если нет - выводим значение счетчика и приостанавливает поток на одну секунду, тем временем главный поток тоже будет остановлен на три секунды, а после этого вызовется метод cansel на втором потоке, в результате замыкания не успеет вывести все 10 сообщений и будет остановлено. Запомните этот паттерн. Он используется и в других многопоточных API на IOS. В классе Thread есть еще несколько интересных для нас свойств. Main позволяет обратиться к главному потоку, а isMainThread - проверить является ли поток главным. IsExecuting имеет значение true, если поток в данный момент выполняется, а isFinished если он закончил свое выполнение. В нашем случае, сразу после вызова cancle, второй поток ещё не успеет завершиться, но после небольшой паузы, значение его свойства isFinished и IsExecuting примут значения true и false соответственно. Ещё одним способом взаимодействия thread можно считать создание sub class-ов. Для этого необходимо переопределить метод Main. По умолчанию, он после вызова start, вызывает переданный вами селектор на переданном target, создав sub class, вы можете разместить в этом методе саму логику, которую нужно выполнить в отдельном потоке, и таким образом отказаться от работы с селекторами. На слайде вы видите простой пример с использованием этого подхода. Работа с sub class осуществляется так же, как и в предыдущих примерах. Единственный интересный момент это использование Darwin.sleep - это тот же самый sleep, который мы использовали в прошлых примерах. Раньше мы просто не указывали явное название модуля, но так как Thread имеет метод под названием sleep, возникает неоднозначная ситуация. Для решения этой неоднозначности нужно добавить название модуля, в котором объявлена функция sleep. Последняя тема, которую мы рассмотрим, выполнение селекторов в другом потоке. Напомним, что селектор - это просто название метода. Они пришли в swift из Objective C. Выполнение селекторов работает только на наследников NSObgect. Рассмотрим простой пример, на экране вы видите один из вариантов метода performeSelector, при его вызове, будет создан фоновый поток и метод с переданным названием будет исполнен на нем. Опционально можно передать для него аргумент. Есть и другие варианты, которые исполняют код либо на главном потоке, либо на указанном вами. На этом лекция по NSThread закончена. В реальных проектах вы вполне можете встретиться с этим API, однако, при разработке новых приложений лучше использовать более высокоуровневый API, которые мы обязательно позже рассмотрим.