iOS. Приемы программирования
Шрифт:
Программист
В этой главе будет рассказано обо всем, что нужно знать о GCD. Здесь вы научитесь писать современные многопоточные приложения для iOS и Mac OS X, помогающие достичь впечатляющей производительности на таких многоядерных устройствах, как iPad 2.
Мы довольно много будем работать с диспетчерскими очередями, поэтому необходимо досконально разобраться с теми концепциями, которые лежат в их основе. Диспетчерские очереди бывают трех типов.
Главная очередь — занимается выполнением всех задач из главного потока, и именно здесь Cocoa и Cocoa Touch требуют от программиста вызывать все методы, относящиеся к пользовательскому интерфейсу. Пользуйтесь функцией dispatch_get_main_queue, помогающей управлять главной очередью.
Параллельные очереди — это очереди, которые можно получать из GCD для выполнения синхронных или асинхронных задач. В нескольких параллельных очередях могут одновременно выполняться несколько задач, причем с завидной легкостью. Представляете, больше никакого управления потоками, ур-р-ра! Пользуйтесь функцией dispatch_get_global_queue, помогающей управлять параллельными очередями.
Последовательные очереди — всегда выполняют поставленные в них задачи по принципу «первым пришел — первым обслужен» (First In First Out, FIFO). При этом не имеет значения, являются эти задачи синхронными или асинхронными. Такой принцип работы означает, что последовательная очередь может выполнять в любой момент только один блок кода. Однако такие очереди не применяются в главном потоке, поэтому отлично подходят для решения задач, которые должны выполняться в строгом порядке и не блокировать при этом главный поток. Чтобы создать последовательную очередь, пользуйтесь функцией dispatch_queue_create.
Существуют два механизма отправки задач в диспетчерские очереди:
блочные объекты (см. раздел 7.1);
• функции C.
Блочные объекты позволяют наиболее эффективно использовать GCD и его огромный потенциал. Некоторые функции GCD были расширены таким образом, чтобы программист мог использовать функции C вместо блочных объектов. Однако в действительности
лишь небольшое подмножество GCD-функций допускают замену объектов функциями C, поэтому перед дальнейшим изучением материала обязательно ознакомьтесь с разделом о блочных объектах (разделом 7.1).Функции C, предоставляемые различным GCD-функциям, должны относиться к типу dispatch_function_t. Вот как этот тип определяется в библиотеках Apple:
Итак, если мы хотим, например, создать функцию под названием myGCDFunction, потребуется реализовать ее следующим образом:
Параметр paramContext относится к контексту, который GCD позволяет передавать C-функциям при диспетчеризации задач к этим функциям. Вскоре мы подробно об этом поговорим.
Блочные объекты, передаваемые GCD-функциям, не всегда имеют одинаковую структуру. Некоторые должны принимать параметры, другие — нет, но ни один блочный объект, передаваемый GCD, не возвращает значения.
В любой момент в ходе жизненного цикла приложения вы можете одновременно задействовать несколько диспетчерских очередей. В системе есть только одна основная очередь, но вы сами можете создать сколько угодно последовательных диспетчерских очередей (конечно, в разумных пределах) для любых функций, которые, возможно, понадобится реализовать в вашем приложении. Кроме того, можно получить несколько параллельных очередей и направить им ваши задачи. Задачи можно передавать диспетчерским очередям двумя способами: как блоковые объекты и как функции языка C, о чем рассказано ранее.
Блоковые объекты — это пакеты с кодом, которые в Objective-C обычно имеют форму методов. Блоковые объекты вместе с GCD образуют гармоничную среду, в которой можно создавать высокопроизводительные многопоточные приложения для iOS и Mac OS X. Вы можете спросить: «А что же такого особенного в блоковых объектах и GCD?» Ответ прост: больше никаких потоков! Все, что от вас требуется, — поместить код в блоковые объекты и перепоручить GCD выполнение этого кода.
Вероятно, важнейшая разница между блоковыми объектами и традиционными указателями на функции заключается в том, что блоковые объекты копируют значения локальных переменных, доступ к которым происходит внутри блокового объекта, и сохраняют эти копии для локального использования. Если значения этих переменных изменяются вне области видимости блокового объекта, вы тем не менее можете быть уверены в том, что в блоковом объекте сохранилась собственная копия переменной. Вскоре мы обсудим эти вопросы подробнее.
Блоковые объекты в Objective-C — это сущности, которые в среде программистов принято называть объектами первого класса. Это означает, что вы можете создавать код динамически, передавать блоковый объект методу в качестве параметра и возвращать блоковый объект от метода. Все это позволяет более уверенно выбирать, что вы хотите делать во время исполнения и изменять ход действия программы. В частности, GCD может выполнять блоковые объекты в отдельных потоках. Поскольку блоковые объекты являются объектами Objective-C, с ними можно обращаться как с любыми другими объектами.
Иногда блоковые объекты называются замкнутыми выражениями (Closures).
Создание блоковых объектов напоминает создание обычных функций языка C, как будет показано в разделе 7.1. Блоковые объекты могут возвращать значения и принимать параметры. Блоковые объекты можно определять как встраиваемые либо обрабатывать как отдельные блоки кода наподобие функций языка C. При создании встраиваемым способом область видимости переменных, доступных блоковым объектам, существенно отличается от аналогичной области видимости, если блоковый объект реализуется как отдельный блок кода.