DispatchQueue је фундаментални ред Grand Central Dispatch (GCD) оквира за управљање асинхроним задацима у iOS и macOS. Према Apple Developer Documentation, 2026, DispatchQueue апстрахује управљање нитима од програмера кроз serial и concurrent редове. GCD аутоматски распоређује задатке по системском базену нити, елиминишући ручно креирање и уништавање нити.
Главне тачке
DispatchQueue је објекат Grand Central Dispatch (GCD) оквира који управља извршавањем задатака у системским или прилагођеним редовима нити. Grand Central Dispatch је Apple-ова нисконвојска библиотека, доступна од iOS 4 и macOS 10.6, која потпуно апстрахује управљање нитима од програмера. GCD користи базен нити оперативног система и аутоматски скалира број нити под оптерећењем уређаја.
Програмер не мора ручно да креира и уништава нити — GCD преузима овај задатак, пружајући једноставан API кроз DispatchQueue. Задатак у облику затворења (closure) шаље се у ред кроз методе sync или async. У првом случају, нит која позива се блокира до завршетка задатка, у другом — наставља извршавање одмах.
Према Apple (2026), GCD користи системски базен нити који се прилагођава броју језгара и тренутном оптерећењу процесора. Concurrent ред не креира нову нит за сваки задатак — GCD поново користи нити из базена, што минимизира додатне трошкове креирања нити.
Grand Central Dispatch се састоји од три кључне компоненте: реда (DispatchQueue), групе (DispatchGroup) и семафора (DispatchSemaphore). Ред је основни елемент који прима задатке у облику блокова кода. DispatchGroup синхронизује извршавање више задатака, а DispatchSemaphore ограничава приступ заједничком ресурсу на одређени број нити.
Сваки GCD ред је повезан са одређеном QoS (Quality of Service) класом која обавештава систем о важности задатка. Систем користи QoS за расподелу процесорског времена између редова, дајући приоритет критичнијим задацима — на пример, ажурирању UI или обради додира корисника.
Serial ред извршава задатке строго секвенцијално, један за другим. Ако се у serial ред поставе три задатка, други почиње тек након потпуног завршетка првог. Serial редови се користе за синхронизацију приступа заједничким ресурсима — на пример, низу који се мења из више делова кода.
Concurrent ред покреће више задатака истовремено, распоређујући их између доступних нити из системског базена. Задаци на concurrent реду се покрећу по редоследу доласка (FIFO), али се завршавају произвољним редоследом ако им је време извршавања различито. Concurrent ред не гарантује редослед завршетка — само редослед покретања.
| Параметар | Serial ред | Concurrent ред |
|---|---|---|
| Редослед извршавања | Строго секвенцијалан | Паралелан |
| Број нити | Једна | Више из GCD базена |
| Примена | Заштита дељених ресурса | Независна израчунавања |
| Main queue | Да (главна нит) | Не |
| Ризик од deadlock-а | Висок при sync на истом реду | Низак |
Serial ред је идеалан за задатке који мењају заједничко стање — упис у датотеку, ажурирање модела података или рад са Core Data. Коришћење serial реда гарантује да два дела кода неће истовремено мењати исте податке, елиминишући стање трке без додатних блокирања.
Concurrent ред је погодан за задатке који не зависе једни од других: учитавање више слика, паралелни мрежни захтеви или групна обрада података. GCD аутоматски одлучује колико задатака покренути истовремено, на основу броја језгара процесора и тренутног оптерећења система.
QoS (Quality of Service) — механизам GCD који обавештава оперативни систем о важности и хитности задатка. Систем користи QoS за планирање нити: задаци са вишим QoS добијају више процесорског времена и покрећу се раније. Вредност QoS се преноси при креирању реда или слању конкретног задатка.
У GCD-у је доступно пет QoS класа. .userInteractive — највиши приоритет за задатке везане за UI. .userInitiated — за задатке које је покренуо корисник. .utility — за позадинске задатке са приказом напретка. .background — за задатке невидљиве кориснику. .default — средњи ниво између userInitiated и utility, користи се подразумевано.
Према Apple (2026), неправилан избор QoS је један од честих узрока проблема са перформансама. Покретање позадинског учитавања са QoS .userInteractive одузима ресурсе UI-ју, изазивајући микро-застоје у анимацијама. Препоручује се избор најнижег QoS који још увек обезбеђује прихватљиво време извршавања.
Приликом учитавања слике за тренутно приказивање користите .userInitiated — корисник очекује резултат. За претходно учитавање следећег екрана довољан је .utility. Позадинска синхронизација са сервером се извршава са .background, минимизирајући утицај на активне задатке.
DispatchGroup омогућава праћење завршетка групе задатака. Када су сви задаци у групи завршени, GCD позива notify руковаоца на наведеном реду. Ово је посебно корисно при учитавању више независних ресурса — података профила, листе пријатеља и подешавања, када интерфејс треба ажурирати тек након пријема свих података.
DispatchGroup подржава синхрони позив wait() који блокира тренутну нит до завршетка свих задатака. Ово је згодно када код не може да настави без резултата групе. Асинхрона варијанта — notify() — позива затворење на наведеном реду након завршетка свих задатака, не блокирајући нит која позива.
DispatchSemaphore контролише приступ ресурсу, ограничавајући број истовремених приступа. Семафор са почетном вредношћу 3 омогућава покретање не више од три паралелна задатка. При позиву wait() бројач се смањује, при signal() — повећава. Ако је бројач нула, нит се блокира до ослобађања ресурса.
Размотримо три практична примера коришћења DispatchQueue у Swift. Први приказује основни async позив са повратком на главну нит, други — синхронизацију кроз serial ред, трећи — DispatchGroup за паралелне захтеве.
DispatchQueue.main је serial ред главне нити, намењен искључиво за UI операције. Увек га користите за ажурирање интерфејса након завршетка позадинског рада.
let queue = DispatchQueue.global(qos: .userInitiated)
queue.async {
let data = self.fetchData()
DispatchQueue.main.async {
self.updateUI(with: data)
}
}
Креирање сопственог serial реда са јединственим идентификатором синхронизује приступ променљивом низу. Све операције читања и уписа пролазе кроз један ред, елиминишући стање трке.
let serialQueue = DispatchQueue(label: "com.app.items")
var items: [Int] = []
serialQueue.async {
items.append(1)
}
serialQueue.async {
let last = items.last
DispatchQueue.main.async {
print("Last item: \(last)")
}
}
DispatchGroup омогућава покретање више задатака на concurrent реду и добијање обавештења о завршетку свих. Ово је корисно при учитавању података за екран профила.
let group = DispatchGroup()
let worker = DispatchQueue.global()
worker.async(group: group) { self.loadProfile() }
worker.async(group: group) { self.loadFriends() }
worker.async(group: group) { self.loadSettings() }
group.notify(queue: DispatchQueue.main) {
self.showCompleteUI()
}
Deadlock при sync позиву на serial реду — најчешћа грешка. Ако задатак на serial реду позове queue.sync на истом реду, нит се заувек блокира. Ред чека завршетак тренутног задатка, а задатак чека завршетак sync позива — класична међусобна блокада.
Све операције са UIKit морају се извршавати на главној нити. Xcode открива ове грешке у Debug режиму кроз Main Thread Checker. У Release верзији one доводе до непредвидивог понашања: анимације се не покрећу, UI се не ажурира, могући су crash-еви.
Креирање стотина прилагођених редова уместо глобалних — антиобразац. Сваки ред троши системске ресурсе. За већину задатака довољни су глобални concurrent редови са различитим QoS и један-два serial реда за синхронизацију дељених података.
При извршавању ресурсно захтевних цикличних задатака на позадинском реду без autoreleasepool, меморија расте до завршетка целе петље. ARC ослобађа објекте тек при изласку из autorelease pool-а. Умотајте итерације петље у autoreleasepool { } за правовремено ослобађање меморије.
Често постављана питања
OperationQueue је изграђена на GCD, али пружа API вишег нивоа са зависностима операција, KVO и подршком за отказивање. DispatchQueue је нисконвојски ред за једноставне async задатке без управљања зависностима.
GCD не подржава заустављање покренутог задатка. Метод suspend() зауставља само нове задатке, тренутни се извршава до краја. За отказивање је потребна ручна провера заставице унутар кода задатка.
За основни захтев са тренутним приказом резултата — .userInitiated. За претходно учитавање података — .utility. За позадинску синхронизацију — .background.
GCD не фиксира број нити. Базен нити се динамички скалира под оптерећењем, узимајући у обзир језгра процесора, тренутно оптерећење и QoS сваког задатка. Максимални број је ограничен системом.
UIKit није threadsafe — све његове класе морају се позивати само са главне нити. Кршење изазива непредвидиво понашање, пропуштена ажурирања и crash-еве у продукцији.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође