Как вы планируете запуск блока на следующей итерации цикла запуска?

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

Я знаю, что следующее не работает, потому что оно чередуется с основным циклом запуска, поэтому мой код может выполняться в следующем цикле выполнения, но это может и не быть.

 dispatch_async(dispatch_get_main_queue(),^{ //my code }); 

Следующее, что я считаю, испытывает ту же проблему, что и выше:

 dispatch_after(DISPATCH_TIME_NOW, dispatch_get_main_queue(), ^(void){ //my code }); 

Теперь я считаю, что следующее будет работать, поскольку оно помещается в конец текущего цикла цикла (исправьте меня, если я ошибаюсь), будет ли это действительно работать?

 [self performSelector:@selector(myMethod) withObject:nil afterDelay:0]; 

Как насчет таймера с интервалом 0 ? В документации указано: If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead. Означает ли это, что это гарантирует выполнение на следующей итерации цикла запуска?

 [NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(myMethod) userInfo:nil repeats:NO]; 

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

Возможно, вы не знаете обо всем, что работает цикл выполнения на каждой итерации. (Я не был до того, как я исследовал этот ответ!) Так как это происходит, CFRunLoop является частью пакета CoreFoundation с открытым исходным кодом , поэтому мы можем взглянуть на то, что он влечет за собой. Пробег выглядит примерно так:

 while (true) { Call kCFRunLoopBeforeTimers observer callbacks; Call kCFRunLoopBeforeSources observer callbacks; Perform blocks queued by CFRunLoopPerformBlock; Call the callback of each version 0 CFRunLoopSource that has been signalled; if (any version 0 source callbacks were called) { Perform blocks newly queued by CFRunLoopPerformBlock; } if (I didn't drain the main queue on the last iteration AND the main queue has any blocks waiting) { while (main queue has blocks) { perform the next block on the main queue } } else { Call kCFRunLoopBeforeWaiting observer callbacks; Wait for a CFRunLoopSource to be signalled OR for a timer to fire OR for a block to be added to the main queue; Call kCFRunLoopAfterWaiting observer callbacks; if (the event was a timer) { call CFRunLoopTimer callbacks for timers that should have fired by now } else if (event was a block arriving on the main queue) { while (main queue has blocks) { perform the next block on the main queue } } else { look up the version 1 CFRunLoopSource for the event if (I found a version 1 source) { call the source's callback } } } Perform blocks queued by CFRunLoopPerformBlock; } 

Вы можете видеть, что существует множество способов подключиться к циклу запуска. Вы можете создать CFRunLoopObserver для CFRunLoopObserver любой из «действий», которые вы хотите. Вы можете создать версию 0 CFRunLoopSource и немедленно сообщить об этом. Вы можете создать связанную пару CFMessagePorts , обернуть ее в CFRunLoopSource 1 CFRunLoopSource и отправить ему сообщение. Вы можете создать CFRunLoopTimer . Вы можете блокировать очереди с помощью dispatch_get_main_queue или CFRunLoopPerformBlock .

Вам нужно будет решить, какой из этих API следует использовать на основе того, когда вы планируете блок, и когда вам нужно его вызывать.

Например, касания обрабатываются в источнике версии 1, но если вы справляетесь с прикосновением, обновляя экран, это обновление фактически не выполняется до тех пор, пока транзакция Core Animation не будет выполнена, что происходит в наблюдателе kCFRunLoopBeforeWaiting .

Теперь предположим, что вы хотите запланировать блок во время обработки касания, но вы хотите, чтобы он выполнялся после совершения транзакции.

Вы можете добавить свой собственный CFRunLoopObserver для действия kCFRunLoopBeforeWaiting , но этот наблюдатель может работать до или после наблюдателя Core Animation, в зависимости от указанного вами заказа и указания Core Animation. (Core Animation в настоящее время указывает порядок 2000000, но это не документировано, чтобы оно могло измениться.)

Чтобы убедиться, что ваш блок работает после наблюдателя Core Animation, даже если ваш наблюдатель работает перед наблюдателем Core Animation, не вызывайте блок непосредственно в обратном вызове наблюдателя. Вместо этого используйте dispatch_async в этой точке, чтобы добавить блок в основную очередь. Помещение блока в основную очередь заставит цикл выполнения просыпаться из своего «ожидания» немедленно. Он будет запускать любые наблюдатели kCFRunLoopAfterWaiting , а затем он kCFRunLoopAfterWaiting основную очередь, и в это время он запустит ваш блок.

Я не верю, что есть какой-либо API, который позволит вам гарантировать, что код будет запущен на следующем шаге цикла события. Мне также любопытно, почему вам нужна гарантия, что в цикле больше ничего не было, главное в частности.

Я также могу подтвердить, что использование perforSelector: withObject: afterDelay использует таймер на основе runloop и будет иметь функционально подобное поведение для dispatch_async’ing на dispatch_get_main_queue ().

редактировать:

Собственно, после повторного чтения вашего вопроса, похоже, вам нужно только, чтобы текущий runloop завершался. Если это так, то dispatch_async – именно то, что вам нужно. Фактически, весь вышеприведенный код делает гарантию завершения текущего цикла runloop.

Я написал себе категорию NSObject, которая принимает значение переменной задержки, основанную на другом вопросе stackoverflow . Передавая значение нуля, вы фактически делаете код запущенным на следующей доступной итерации runloop.

dispatch_async on mainQueue – хорошее предложение, но он не запускается в следующем цикле запуска, который вставляется в текущий прогон в цикле.

Чтобы получить такое поведение, вам нужно прибегнуть к традиционному способу:

 [self performSelector:@selector(myMethod) withObject:nil afterDelay:0]; 

Это также дает дополнительное преимущество в том, что его можно отменить, используя NSObject’s cancelPreviousPerforms.

  • JSON и core data на iPhone
  • Как можно разрабатывать приложения для iPhone на Java?
  • Кроссплатформенный обмен кодами iPhone / Android
  • NSString - целое число?
  • Переполнение кнопки навигации iOS7
  • Получение NSDecimalNumber из определенной в локали строки?
  • Код примера Objective-C для HMAC-SHA1
  • Можно ли использовать Swift's Enum в Obj-C?
  • Почему переменная NSInteger должна быть отброшена дольше при использовании в качестве аргумента формата?
  • Заменить несколько символов в строке в Objective-C?
  • Можно ли запрограммировать iPhone на C ++?
  • Interesting Posts
    Давайте будем гением компьютера.