I'm making a UITableView which display image created from processed data.
This processing task is too heavy, I decide to declare an array type instance variable of UITableView class and create an operation per one processing task.
Because Every results would be stored into separate memory space identified by index, I thought It is thread-safe.
A Short version example:
class TestOperation: Operation {
var pi: [Int?];
override var isExecuting: Bool { ... }
override var isFinished: Bool { ... }
init(_ p: inout [Int?]) {
pi = p;
}
override func start() {
if pi[0] == nil {
pi[0] = 0;
} else if pi[1] == nil {
pi[1] = 1;
} else {
pi[2] = 2;
}
}
}
class Root {
var sharedArr: [Int?];
var queue: OperationQueue;
init() {
sharedArr = Array(repeating: nil, count: 3);
queue = OperationQueue.init();
for _ in 0...2 {
let operation = TestOperation.init(&sharedArr);
queue.addOperation(operation);
}
}
}
Root.init();
I expected sharedArr
to change, But all I get is array of nil. Is there anything I can try?
Arrays in swift are structs and so passed by value. I see you are passing the array as inout, so you already know this. I have had this problem a couple of times and in the end I cheated.
Cheat 1: pass a reference to Root into TestOperation, and call a method on Root that adds the value to the shared array. You can make this cleaner with a protocol.
Cheat 2: Create a class that wraps the shared array and has methods to update the wrapped array.
In both cases I would pass the index to use into TestOperation instead of deducing it from the array contents. Deductions may be timing dependent.
I know that this is avoiding rather than solving the problem, but sometimes life is too short.
Here is the gist, untested:
protocol TestOperationProtocol: class {
function setValue(index: Int, value: Int)
}
class TestOperation: Operation {
weak var owner: TestOperationProtocol
let index: Int
override var isExecuting: Bool { ... }
override var isFinished: Bool { ... }
init(owner: TestOperationProtocol, index: Int) {
self.owner = owner
self.index = index
}
override func start() {
// calculate value
let value = self.index
self.owner?.setValue(self.index, value)
}
}
class Root: TestOperationProtocol {
var sharedArr: [Int?];
var queue: OperationQueue;
init() {
sharedArr = Array(repeating: nil, count: 3);
queue = OperationQueue.init();
for i in 0...sharedArr.count {
let operation = TestOperation.init(self, index: index);
queue.addOperation(operation);
}
}
func setValue(index: Int, value: Int) {
sharedArray[index] = value
}
}
The protocol allows you to break a dependency cycle. TestOperation depends on TestOperationProtocol and not on Root. Root depends on TestOperation and its Protocol.