Викликання методу в основному потоці?


83

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

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

Проблема в тому, що мій макет знає, як телефонувати, doSomethingале не знає, як телефонувати performSelectorOnMainThread.

Так що будь-яке рішення?

Відповіді:


274

Завдання-C

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

Стрімкий

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

Спадщина Свіфт

dispatch_async(dispatch_get_main_queue()) {
    self.doSomething()
}

Ви щойно зробили мені день за допомогою швидкого коду 3. Дякую!
Феліпе Балдуїно,

Хорошою практикою є не використовувати себе безпосередньо в блоці. замість цього використовуйте слабке посилання на нього.
Яген

2

У програмному забезпеченні є приказка, що додавання рівня опосередкованості виправляє майже все.

Нехай метод doSomething буде опосередкованою оболонкою, яка лише виконуєSelectorOnMainThread, щоб викликати метод really_doSomething, щоб виконати фактичну роботу Something. Або, якщо ви не хочете змінювати метод doSomething, попросіть модуль тестування викликати метод doSomething_redirect_shell, щоб зробити щось подібне.


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


Це ні в якому разі не краще, ви створили функцію, яка не робить нічого, крім виклику іншої. до речі, що швидкий синтаксис можна додатково спростити "() -> Порожнеча в" не потрібна
aryaxt

Його зручніше для читання / записування. Так, автозаповнення додається в "() -> Позначити". Чи є спосіб відключити цю поведінку автозаповнення при закритті void> void?
Ескаррут

назва методу у вас може ввести в оману, схоже, блок буде виконаний відразу в основному потоці, але це неправда. dispatch_async у головній черзі додає блок коду до наступного циклу запуску, ця важлива поведінка прихована за методом, який називається "runThisInMainThread
aryaxt

1
це очікувана поведінка, dispatch_async додає код у кінець черги. Якщо ви хочете, щоб його відразу викликали, замість цього слід виконати dispatch_sync. Якщо ви зробите dispatch_sync у черзі для потоку, який ви вже в ній, викликає блокування потоку. у вашому прикладі порядок відбитків - "a", "c", "b". a та c виконуються за 1 цикл, оскільки вони знаходяться в одній області дії. b додається в кінець черги, тому його іноді викликають пізніше, коли інші існуючі елементи в черзі завершені
aryaxt

1
@Esqarrouth - Ви впевнені, що ваш dispatch_asyncзаблокований код після дзвінка на нього? Вся суть використання, asyncа не syncНЕ блокування того, що слід. (Звичайно, blockкод буде БЛОКУВАТИ що-небудь ще в основному потоці , оскільки суть запитуваного коду полягає у виконанні в основному потоці. Якщо ви хочете запустити фоновий код, тоді ви попросите іншу чергу, ні dispatch_get_main_queue.)
Виробник інструментів


-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
        }

    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.