Как создать переменную экземпляра, которая используется несколькими операциями - PullRequest
0 голосов
/ 04 сентября 2018

Я делаю UITableView, который отображает изображение, созданное из обработанных данных.

Эта задача обработки слишком сложна, я решил объявить переменную экземпляра типа массива класса UITableView и создать операцию для одной задачи обработки.

Поскольку все результаты будут храниться в отдельном пространстве памяти, указанном индексом, я подумал, что это потокобезопасно.

Пример короткой версии:

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();

Я ожидал, что sharedArr изменится, но все, что я получу, это массив нулей. Я могу что-нибудь попробовать?

1 Ответ

0 голосов
/ 04 сентября 2018

Массивы в swift являются структурами и поэтому передаются по значению. Я вижу, вы передаете массив как inout, так что вы уже знаете это. У меня была эта проблема пару раз, и в конце концов я обманул.

Cheat 1: передать ссылку на Root в TestOperation и вызвать метод Root, который добавляет значение в общий массив. Вы можете сделать это чище с протоколом.

Чит 2. Создание класса, который оборачивает общий массив и имеет методы для обновления обернутого массива.

В обоих случаях я передал бы индекс для использования в TestOperation вместо того, чтобы выводить его из содержимого массива. Отчисления могут зависеть от времени.

Я знаю, что это скорее предотвращение, чем решение проблемы, но иногда жизнь слишком коротка.

Вот суть, не проверенная:

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
    }
}

Протокол позволяет разорвать цикл зависимости. TestOperation зависит от TestOperationProtocol, а не от Root. Корень зависит от TestOperation и его протокола.

...