De acordo com a minha resposta a uma pergunta relacionada , vou discordar de BJ e sugerir que você examine primeiro o GCD sobre NSOperation / NSOperationQueue, a menos que este último forneça algo que o GCD não precisa.
Antes do GCD, eu usava muitos NSOperations / NSOperationQueues em meus aplicativos para gerenciar a simultaneidade. No entanto, desde que comecei a usar o GCD regularmente, substituí quase completamente o NSOperations e o NSOperationQueues por blocos e filas de despacho. Isso veio da maneira como utilizei as duas tecnologias na prática e do perfil que realizei nelas.
Primeiro, há uma quantidade não trivial de sobrecarga ao usar NSOperations e NSOperationQueues. Esses são objetos de cacau e precisam ser alocados e desalocados. Em um aplicativo iOS que escrevi que renderiza uma cena 3D a 60 FPS, eu estava usando NSOperations para encapsular cada quadro renderizado. Quando criei um perfil disso, a criação e o detalhamento dessas operações de NSO foram responsáveis por uma parte significativa dos ciclos da CPU no aplicativo em execução e estavam atrasando as coisas. Substituí-os por blocos simples e uma fila serial do GCD, e essa sobrecarga desapareceu, levando a um desempenho notavelmente melhor na renderização. Este não foi o único lugar em que notei sobrecarga ao usar NSOperations, e já vi isso no Mac e no iOS.
Segundo, há uma elegância ao código de despacho baseado em bloco que é difícil de combinar ao usar o NSOperations. É incrivelmente conveniente agrupar algumas linhas de código em um bloco e enviá-lo para uma fila serial ou simultânea, onde a criação de um NSOperation ou NSInvocationOperation personalizado para fazer isso exige muito mais código de suporte. Eu sei que você pode usar um NSBlockOperation, mas também pode estar enviando algo para o GCD. Embrulhar esse código em blocos alinhados com o processamento relacionado em seu aplicativo leva, em minha opinião, a uma melhor organização de código do que ter métodos separados ou NSOperations personalizadas que encapsulam essas tarefas.
NSOperations e NSOperationQueues ainda têm usos muito bons. O GCD não tem um conceito real de dependências, onde NSOperationQueues pode configurar gráficos de dependência bastante complexos. Eu uso NSOperationQueues para isso em alguns casos.
No geral, embora eu costumo advogar o uso do mais alto nível de abstração que realiza a tarefa, este é um caso em que defendo a API de nível mais baixo da GCD. Entre os desenvolvedores de iOS e Mac com quem conversamos sobre isso, a grande maioria escolhe usar o GCD em vez de NSOperations, a menos que eles tenham como alvo versões de SO sem suporte para ele (antes do iOS 4.0 e do Snow Leopard).