3

Скажем, я хочу, чтобы реализовать шаблон, как так:Выполнение синхронных операций

a = some array I download from the internet 
b = manipulate a somehow (long operation) 
c = first object of b 

Это, очевидно, должны называться синхронно, что является причиной моих проблем в Objective C. Я читал о NSOperationQueue и НОД, и я не совсем понимаю их, или это было бы уместно здесь. Может кто-нибудь предложить решение? Я знаю, что я также могу использовать performSelector:@selector(sel)WaitUntilDone, но это не кажется эффективным для больших операций.

ответ

5

Итак, создайте очередную диспетчерскую очередь, выгрузите всю работу там (каждый в блоке) и последний блок отправите метод обратно себе в основную очередь, сообщив вашему классу управления, что работа выполнена.

Это далеко и далеко лучшая архитектура для многих подобных задач.

2

Я рад, что на ваш вопрос ответили. Несколько дополнительных наблюдений:

  1. Незначительное уточнение в вашей терминологии, но я предполагаю, вы хотите, чтобы выполнить эти задачи асинхронно (т.е. не блокировать основной очереди и заморозить пользовательский интерфейс), но вы хотите, чтобы они работали последовательным образом (т. е. каждый из них будет ждать завершения предыдущего шага до начала следующей задачи).

  2. Самый простой подход, прежде чем я нырять в последовательные очереди, чтобы просто сделать эти три в одной посланной задачи:

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
        [self doDownloadSynchronously]; 
        [self manipulateResultOfDownload]; 
        [self doSomethingWithFirstObject]; 
    }); 
    

    Как вы можете видеть, поскольку все это одна задача, для выполнения этих трех шаги друг за другом, вы действительно можете отправить это в любую фоновую очередь (в приведенном выше примере это одна из глобальных фоновых очередей), но поскольку вы делаете все это в пределах заданного блока отправки, эти три этапа будут последовательно, один после следующего.

    Обратите внимание, что, как правило, не требуется создавать синхронные сетевые запросы, если вы делаете это в фоновом режиме, это менее проблематично (хотя вы можете создать сетевой запрос на основе операций, как описано ниже в пункте # 5, если вы хотите получить возможность отменить незавершенное сетевое требование).

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

    dispatch_queue_t queue = dispatch_queue_create("com.company.app.queuename", 0); 
    

    Вы можете запланировать эти три задачи:

    dispatch_async(queue, ^{ 
        [self doDownloadSynchronously]; 
    }); 
    
    dispatch_async(queue, ^{ 
        [self manipulateResultOfDownload]; 
    }); 
    
    dispatch_async(queue, ^{ 
        [self doSomethingWithFirstObject]; 
    }); 
    
  4. Операции подход очередь так же, как легко, но по умолчанию, операция очередь одновременно, поэтому, если мы хотим, чтобы быть последовательной очередь, мы должны указать, что нет никаких параллельных операций (т.е. максимальной одновременной кол-операции 1):

    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
    queue.maxConcurrentOperationCount = 1; 
    
    [queue addOperationWithBlock:^{ 
        [self doDownloadSynchronously]; 
    }]; 
    
    [queue addOperationWithBlock:^{ 
        [self manipulateResultOfDownload]; 
    }]; 
    
    [queue addOperationWithBlock:^{ 
        [self doSomethingWithFirstObject]; 
    }]; 
    

    Это вызывает вопрос о том, почему вы можете использовать подход очереди операций над подходом GCD.Основная причина заключается в том, что если вам нужна возможность отмены операций (например, вы можете остановить операции, если пользователь отклоняет контроллер представления, который инициировал асинхронную операцию), очереди операций предлагают возможность отмены операций, тогда как это гораздо более громоздко сделать это с помощью задач GCD.

  5. Единственный сложный вопрос, на мой взгляд, заключается в том, как вы хотите сделать эту операцию в сети синхронно. Вы можете использовать метод класса NSURLConnectionsendSynchronousRequest или просто захватить NSData с сервера, используя dataWithContentsOfURL. Существуют ограничения на использование этих видов синхронных сетевых запросов (например, вы не можете отменить запрос после его запуска), поэтому многие из нас будут использовать сетевой запрос NSOperation.

    Выполнение этого действия, вероятно, выходит за рамки вашего вопроса, поэтому я могу предположить, что вы можете использовать AFNetworking для создания сетевого запроса на основе операции, который вы могли бы интегрировать в решение № 4 выше, устраняя большую часть необходимого программирования если вы сделали свою собственную сетевую работу на основе NSOperation.

  6. Главное, чтобы помнить, что когда вы запускаете такой код в фоновом режиме, когда вам нужно делать обновления пользовательского интерфейса (или обновлять модель), они должны быть возвращены в основную очередь, а не фоновой очереди. Таким образом, если делать реализацию НОД, вы могли бы сделать:

    dispatch_async(queue, ^{ 
        [self doSomethingWithFirstObject]; 
    
        dispatch_async(dispatch_get_main_queue(),^{ 
         // update your UI here 
        }); 
    }); 
    

    Эквивалент NSOperationQueue цветопередача будет:

    [queue addOperationWithBlock:^{ 
        [self doSomethingWithFirstObject]; 
    
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
         // update your UI here 
        }]; 
    }]; 
    

Эфирное Грунтовка по этим вопросам является Concurrency Programming Guide.

Есть тонна больших WWDC видео на эту тему, включая WWDC 2012 видео Asynchronous Design Patterns with Blocks, GCD, and XPC и Building Concurrent User Interfaces on iOS и WWDC 2011 видео Blocks and Grand Central Dispatch in Practice и Mastering Grand Central Dispatch

+0

Wow! Большое спасибо за этот ответ, я собираюсь распечатать его и взять его со мной в кафе прямо сейчас! Я очень ценю это! Кажется, NSOperationQueue очень проста в использовании! – JoshDG

Смежные вопросы