Skip to content
This repository has been archived by the owner on Oct 29, 2021. It is now read-only.

Commit

Permalink
Allowing make, execute and cancel multiple Kommands concurrently, seq…
Browse files Browse the repository at this point in the history
…uentially and waiting until finished.
  • Loading branch information
Alex Rupérez committed Jan 31, 2017
1 parent d279abe commit dc1b5d7
Show file tree
Hide file tree
Showing 4 changed files with 173 additions and 4 deletions.
22 changes: 22 additions & 0 deletions Kommander/Dispatcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@ public class Dispatcher {
}
}

public func execute(_ blocks: [() -> Void], concurrent: Bool = true, waitUntilFinished: Bool = false) -> [Any] {
var actions = [Any]()
if concurrent {
for block in blocks {
actions.append(execute(block))
}
}
else {
for block in blocks {
let blockOperation = BlockOperation(block: block)
if let lastOperation = actions.last as? Operation {
blockOperation.addDependency(lastOperation)
}
actions.append(blockOperation)
}
if let operations = actions as? [Operation] {
execute(operations, waitUntilFinished: waitUntilFinished)
}
}
return actions
}

public func execute(qos: DispatchQoS?, flags: DispatchWorkItemFlags?, block: @escaping @convention(block) () -> ()) -> DispatchWorkItem {
let work = DispatchWorkItem(qos: qos ?? .default, flags: flags ?? .assignCurrentContext, block: block)
execute(work)
Expand Down
8 changes: 4 additions & 4 deletions Kommander/Kommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public class Kommand<T> {

private final let deliverer: Dispatcher
private final let executor: Dispatcher
private final let actionBlock: ActionBlock
private final var successBlock: SuccessBlock?
private final var errorBlock: ErrorBlock?
private final var action: Any?
internal final let actionBlock: ActionBlock
private(set) internal final var successBlock: SuccessBlock?
private(set) internal final var errorBlock: ErrorBlock?
internal final var action: Any?

internal init(deliverer: Dispatcher, executor: Dispatcher, actionBlock: @escaping ActionBlock) {
self.deliverer = deliverer
Expand Down
35 changes: 35 additions & 0 deletions Kommander/Kommander.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,39 @@ public class Kommander {
return Kommand<T>(deliverer: deliverer, executor: executor, actionBlock: actionBlock)
}

public func makeKommands<T>(_ actionBlocks: [() throws -> T]) -> [Kommand<T>] {
var kommands = [Kommand<T>]()
for actionBlock in actionBlocks {
kommands.append(Kommand<T>(deliverer: deliverer, executor: executor, actionBlock: actionBlock))
}
return kommands
}

func execute<T>(_ kommands: [Kommand<T>], concurrent: Bool = true, waitUntilFinished: Bool = false) {
let blocks = kommands.map { kommand -> () -> Void in
return {
do {
let result = try kommand.actionBlock()
_ = self.deliverer.execute {
kommand.successBlock?(result)
}
} catch {
_ = self.deliverer.execute {
kommand.errorBlock?(error)
}
}
}
}
let actions = executor.execute(blocks, concurrent: concurrent, waitUntilFinished: waitUntilFinished)
for (index, kommand) in kommands.enumerated() {
kommand.action = actions[index]
}
}

func cancel<T>(_ kommands: [Kommand<T>]) {
for kommand in kommands {
kommand.cancel()
}
}

}
112 changes: 112 additions & 0 deletions KommanderTests/KommanderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,118 @@ class KommanderTests: XCTestCase {
waitForExpectations(timeout: 100, handler: nil)
}

func test_nCalls_concurrent_waitUntilFinished() {

let ex = expectation(description: String(describing: type(of: self)))

var successes = 0
let calls = Int(arc4random_uniform(10) + 1)

var kommands = [Kommand<String>]()

for i in 0..<calls {
kommands.append(interactor.getCounter(name: "C\(i)", to: 3)
.onSuccess({ (name) in
successes+=1
if successes>=calls {
ex.fulfill()
}
})
.onError({ (error) in
ex.fulfill()
XCTFail()
}))
}

interactor.kommander.execute(kommands, concurrent: true, waitUntilFinished: true)

waitForExpectations(timeout: 100, handler: nil)
}

func test_nCalls_concurrent() {

let ex = expectation(description: String(describing: type(of: self)))

var successes = 0
let calls = Int(arc4random_uniform(10) + 1)

var kommands = [Kommand<String>]()

for i in 0..<calls {
kommands.append(interactor.getCounter(name: "C\(i)", to: 3)
.onSuccess({ (name) in
successes+=1
if successes>=calls {
ex.fulfill()
}
})
.onError({ (error) in
ex.fulfill()
XCTFail()
}))
}

interactor.kommander.execute(kommands, concurrent: true, waitUntilFinished: false)

waitForExpectations(timeout: 100, handler: nil)
}

func test_nCalls_sequential_waitUntilFinished() {

let ex = expectation(description: String(describing: type(of: self)))

var successes = 0
let calls = Int(arc4random_uniform(10) + 1)

var kommands = [Kommand<String>]()

for i in 0..<calls {
kommands.append(interactor.getCounter(name: "C\(i)", to: 3)
.onSuccess({ (name) in
successes+=1
if successes>=calls {
ex.fulfill()
}
})
.onError({ (error) in
ex.fulfill()
XCTFail()
}))
}

interactor.kommander.execute(kommands, concurrent: false, waitUntilFinished: true)

waitForExpectations(timeout: 100, handler: nil)
}

func test_nCalls_sequential() {

let ex = expectation(description: String(describing: type(of: self)))

var successes = 0
let calls = Int(arc4random_uniform(10) + 1)

var kommands = [Kommand<String>]()

for i in 0..<calls {
kommands.append(interactor.getCounter(name: "C\(i)", to: 3)
.onSuccess({ (name) in
successes+=1
if successes>=calls {
ex.fulfill()
}
})
.onError({ (error) in
ex.fulfill()
XCTFail()
}))
}

interactor.kommander.execute(kommands, concurrent: false, waitUntilFinished: false)

waitForExpectations(timeout: 100, handler: nil)
}

}

extension KommanderTests {
Expand Down

0 comments on commit dc1b5d7

Please sign in to comment.