Вызов метода в основном потоке?

83

В первую очередь пишу код для iphone. Мне нужно иметь возможность вызывать метод в основном потоке без использования performSelectorOnMainThread. Причина, по которой я не хочу использовать, performSelectorOnMainThreadзаключается в том, что это вызывает проблемы, когда я пытаюсь создать макет для модульного тестирования.

[self performSelectorOnMainThread:@Selector(doSomething) withObject:nil];

Проблема в том, что мой макет умеет звонить, doSomethingно не умеет звонить performSelectorOnMainThread.

Итак, любое решение?

арьякст
источник

Ответы:

274

Цель-C

dispatch_async(dispatch_get_main_queue(), ^{
    [self doSomething];
});

Swift

DispatchQueue.main.async {
    self.doSomething()
}

Наследие Swift

dispatch_async(dispatch_get_main_queue()) {
    self.doSomething()
}
арьякст
источник
Вы только что сделали мой день с быстрым кодом 3. Благодаря!
Фелипе Балдуино
Хорошая практика - не использовать self непосредственно в блоке. вместо этого используйте слабую ссылку на него.
Jageen
2

В программном обеспечении есть поговорка, что добавление уровня косвенного обращения исправит почти все.

Пусть метод doSomething будет косвенной оболочкой, которая выполняет только функцию performSelectorOnMainThread для вызова метода really_doSomething для выполнения фактической работы Something. Или, если вы не хотите изменять свой метод doSomething, пусть тестовый модуль вызывает метод doSomething_redirect_shell, чтобы сделать что-то подобное.

hotpaw2
источник
1

Вот лучший способ сделать это в Swift:

runThisInMainThread { () -> Void in
    // Run your code
    self.doSomething()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

Он включен в качестве стандартной функции в мое репо, проверьте это: https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
источник
Это никоим образом не лучше, вы создали функцию, которая ничего не делает, кроме вызова другой. кстати, этот быстрый синтаксис можно еще больше упростить "() -> Void in" не требуется
aryaxt 06
Его более читаемый / записываемый человек. Да, автозаполнение добавляет в "() -> Void in". Есть ли способ отключить это поведение автозаполнения при закрытии void> void?
Esqarrouth
имя вашего метода может вводить в заблуждение, похоже, что блок будет выполнен сразу в основном потоке, но это не так. dispatch_async в основной очереди добавляет блок кода в следующий цикл выполнения, это важное поведение скрыто за методом, который называется "runThisInMainThread
aryaxt
1
это ожидаемое поведение, dispatch_async добавляет код в конец очереди. Если вы хотите, чтобы он был вызван сразу же, вам следует вместо этого выполнить dispatch_sync. Если вы выполняете dispatch_sync в очереди для потока, в котором вы уже находитесь, это вызывает блокировку потока. в вашем примере порядок отпечатков - «а», «в», «б». a и c выполняются в 1 цикле выполнения, потому что они находятся в одной области. b добавляется в конец очереди, поэтому он иногда
вызывается
1
@Esqarrouth - УВЕРЕНЫ ли вы в своем dispatch_asyncзаблокированном коде после звонка на него? Весь смысл использования, asyncа не в syncтом, чтобы НЕ блокировать то, что следует. (Конечно, blockкод БУДЕТ блокировать что-либо еще в основном потоке , так как цель запрошенного кода - выполнение в основном потоке. Если вы хотите запустить фоновый код, вы бы запросили другую очередь, нет dispatch_get_main_queue.)
ToolmakerSteve
1

А теперь в Swift 3:

DispatchQueue.main.async{
   self.doSomething()
}
RomOne
источник
-4
// Draw Line
    func drawPath(from polyStr: String){
        DispatchQueue.main.async {
            let path = GMSPath(fromEncodedPath: polyStr)
            let polyline = GMSPolyline(path: path)
            polyline.strokeWidth = 3.0
            polyline.strokeColor = #colorLiteral(red: 0.05098039216, green: 0.5764705882, blue: 0.2784313725, alpha: 1)
            polyline.map = self.mapVu // Google MapView
        }

    }
Мухаммад Зишан
источник