У меня есть номер NSOperations
, который создает некоторые данные асинхронно. Я хочу собрать все результаты в один массив. Поскольку я обращаюсь к массиву на нескольких разных потоках, я поставил блокировку вокруг массива.Как вы можете собирать данные из NSOperations в массив?
NSOperationQueue
добавляет данные в массив, но результаты, похоже, пропустят некоторые объекты данных. Кажется, что результаты меняются каждый раз, когда я запускаю его.
Я создал упрощенный примерный проект, который воссоздает проблему. Код находится в Swift, но я не думаю, что это зависит от Swift.
import UIKit
class ViewController: UIViewController {
let queue = NSOperationQueue()
var bucket = [String]()
override func viewDidLoad() {
super.viewDidLoad()
queue.addObserver(self, forKeyPath: "operations", options: NSKeyValueObservingOptions.New, context: nil)
for _ in 0..<10 {
queue.addOperation(NSBlockOperation {
// Let's pretend that creating the "fish" string is actually potentially
// expensive and that's why we're doing it in an NSOperation.
let fish = "fish"
objc_sync_enter(self.bucket)
self.bucket.append(fish)
let fishCount = self.bucket.count
print("Bucket contains \(fishCount) fish" + ((fishCount != 1) ? "es" : ""))
objc_sync_exit(self.bucket)
})
}
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if let keyPath = keyPath {
if let object = object as? NSOperationQueue {
if object == queue && keyPath == "operations" {
if queue.operationCount == 0 {
objc_sync_enter(self.bucket)
let fishCount = bucket.count
print("Bucket finally contains \(fishCount) fish" + ((fishCount != 1) ? "es" : ""))
objc_sync_exit(self.bucket)
}
} else {
super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
}
}
}
}
}
Результаты варьируются, но часто что-то вроде этого:
Bucket contains 1 fish
Bucket contains 1 fish
Bucket contains 1 fish
Bucket contains 1 fish
Bucket contains 2 fishes
Bucket contains 1 fish
Bucket contains 1 fish
Bucket contains 3 fishes
Кроме того, иногда код упал с EXC_BAD_ACCESS
на линии self.bucket.append(fish)
Кроме того, линия print("Bucket finally contains \(fishCount) fish" + ((fishCount != 1) ? "es" : ""))
в observeValueForKeyPath
никогда вызывается. Я не уверен, что это отдельный вопрос или нет.
Я использую NSBlockOperations. Это неправильно? Кроме того, это всего лишь пример проблемы, с которой я столкнулся. Проект, к которому это относится, организован намного лучше. –
Да, вы можете использовать NSBlockOperation, но что делать, если вам нужно отменить операцию? У вас нет способа это сделать. Как вы отслеживаете свои операции. Если вы подклассифицируете NSOperation, я все равно буду использовать блоки. Это выбор дизайна, и использование NSBlockOperation требует от вас большего количества работы на ногах. В любом случае я бы переместил этот код из вашего контроллера. Спросите себя, как вы собираетесь управлять этими операциями? –
Предположим, на данный момент, что мне никогда не нужно отменять эти операции и что мне не нужно знать, когда все операции будут завершены. Проблема размещения 10 рыб в ведро все еще не происходит правильно. Это то, что я хотел бы знать, как делать асинхронно и правильно. –