Как реализовать цикл для BlockOperation ?


#1

Добрый день, коллеги.
Возник следующий вопрос.
Ниже написал несколько BlockOperation и исполнение последнего из них зависит от остальных. Есть необходимость повторить последовательность этих блоков, соотвественно когда закончится последний из них blockOperation4 имеющий зависимость от blockOperation1, blockOperation2, blockOperation3. Насколько я понимаю ничего не получится если засунуть это все в for in loop.

let blockOperation1 = BlockOperation
{
}
queue1.addOperation(blockOperation1)

let blockOperation2 = BlockOperation
{
}
queue1.addOperation(blockOperation2)

let blockOperation3 = BlockOperation
{
}
queue1.addOperation(blockOperation3)

let blockOperation4 = BlockOperation
{
}
blockOperation4.addDependency(blockOperation1)
blockOperation4.addDependency(blockOperation2)
blockOperation4.addDependency(blockOperation3)
queue4.addOperation(blockOperation4)

#2
let qroup = DispatchGroup()

for i in 0..<30 {
    qroup.enter()
    DispatchQueue(label: "background: \(i)").async {
        print("background: \(i)")
        qroup.leave()
    }
}

qroup.notify(queue: .main) {
    print("completed")
}

#3

Возможно я не понимаю. Вы повидимому предложили объединить в цикл для повторения операции в blockOperation1, blockOperation2, blockOperation3.
Если так, то это несколько не то что мне нужно. Нужно повторить все четыре - blockOperation1, blockOperation2, blockOperation3, blockOperation4. Т.е. три блока выполняют в параллель операции, затем когда они закончат, их результаты суммируются в четвертом блоке и задаются новые значения для переменых которые можно использовать опять в трех блоках. Т.е. после окончания работы четвертого блока нужно повторить все сначала. Поскольку мне нужна возможность сделать cancel для отмены операции то я могу использовать только BlockOperation, с DispatchQueue это насколько я понимаю почти не возможно.


#4

Тогда наверно так (если я правильно понял):

func mySuperOperation(count: Int, completion: @escaping (Int) -> Void) {
    var result = 0
    var current = 0
    var operations: (() -> Void)!
    operations = {
        let queue1 = OperationQueue()
        let blockOperation1 = BlockOperation {
            result += 1
        }
        queue1.addOperation(blockOperation1)
        
        let blockOperation2 = BlockOperation {
            result += 1
        }
        queue1.addOperation(blockOperation2)
        
        let blockOperation3 = BlockOperation {
            result += 1
        }
        queue1.addOperation(blockOperation3)
        
        let blockOperation4 = BlockOperation {
            current += 1
            current < count ? operations() : completion(result)
        }
        blockOperation4.addDependency(blockOperation1)
        blockOperation4.addDependency(blockOperation2)
        blockOperation4.addDependency(blockOperation3)
        OperationQueue().addOperation(blockOperation4)
    }
    operations()
}

mySuperOperation(count: 4) { result in
    print(result)
}

#5

Огромное Спасибо!
Попробую. Поскольку ни разу не использовал подобную конструкцию, есть пара вопросов.

Что определяет эта строка

completion: @escaping (Int) -> Void

Извиняюсь за глупый вопрос наверное, но что есть такое operations ?


#6

Это всё замыкания.


#7

Почитал про escaping closure. Но должен признать что не понимаю как в Вашем коде происходит повторение четырех блоков. Не могли бы Вы пояснить пошагово что происходит ?


#8

0 Вызывается функция mySuperOperation
1 Вызывается замыкание operations
2, 3, 4 Вызывается operations внутри BlockOperation (другого замыкания), главное что оно вызывается внутри себя, фактически рекурсия
5 Как current стал равен count вызывается completion
6 В параметрах которого приходит result


#9

Спасибо за пояснение!
Для меня, для усвоения. Правильно ли будет сказать, что “completion” есть escaping closure. Прописав его как параметр функции мы задекларировали его тип и после того как функция выполнила свою работу его инициализировали, передав результат функции как результат четырехкратной рекурсии другого closure, т.е. результат четырехкратного повторения наших четырех блоков ?


#10

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