Adding items to Swift array across multiple threads causing issues (because arrays aren't thread safe) - how do I get around that?

后端 未结 5 1029
南笙
南笙 2020-11-28 12:12

I want to add given blocks to an array, and then run all the blocks contained in the array, when requested. I have code similar to this:

class MyArrayBlockCl         


        
5条回答
  •  渐次进展
    2020-11-28 12:47

    Details

    • Xcode 10.1 (10B61)
    • Swift 4.2

    Solution

    import Foundation
    
    class AtomicArray {
    
        private lazy var semaphore = DispatchSemaphore(value: 1)
        private var array: [T]
    
        init (array: [T]) { self.array = array }
    
        func append(newElement: T) {
            wait(); defer { signal() }
            array.append(newElement)
        }
    
        subscript(index: Int) -> T {
            get {
                wait(); defer { signal() }
                return array[index]
            }
            set(newValue) {
                wait(); defer { signal() }
                array[index] = newValue
            }
        }
    
        var count: Int {
            wait(); defer { signal() }
            return array.count
        }
    
        private func wait() { semaphore.wait() }
        private func signal() { semaphore.signal() }
    
        func set(closure: (_ curentArray: [T])->([T]) ) {
            wait(); defer { signal() }
            array = closure(array)
        }
    
        func get(closure: (_ curentArray: [T])->()) {
            wait(); defer { signal() }
            closure(array)
        }
    
        func get() -> [T] {
            wait(); defer { signal() }
            return array
        }
    }
    
    extension AtomicArray: CustomStringConvertible {
        var description: String { return "\(get())"}
    }
    

    Usage

    The basic idea is to use the syntax of a regular array

    let atomicArray = AtomicArray(array: [3,2,1])
    
     print(atomicArray)
     atomicArray.append(newElement: 1)
    
     let arr = atomicArray.get()
     print(arr)
     atomicArray[2] = 0
    
     atomicArray.get { currentArray in
          print(currentArray)
     }
    
     atomicArray.set { currentArray -> [Int] in
          return currentArray.map{ item -> Int in
               return item*item
          }
     }
     print(atomicArray)
    

    Usage result

    Full sample

    import UIKit
    
    class ViewController: UIViewController {
    
        var atomicArray = AtomicArray(array: [Int](repeating: 0, count: 100))
    
        let dispatchGroup = DispatchGroup()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            arrayInfo()
    
            sample { index, dispatch in
                self.atomicArray[index] += 1
            }
    
            dispatchGroup.notify(queue: .main) {
                self.arrayInfo()
                self.atomicArray.set { currentArray -> ([Int]) in
                    return currentArray.map{ (item) -> Int in
                        return item + 100
                    }
                }
               self.arrayInfo()
            }
    
        }
    
        private func arrayInfo() {
            print("Count: \(self.atomicArray.count)\nData: \(self.atomicArray)")
        }
    
        func sample(closure: @escaping (Int,DispatchQueue)->()) {
    
            print("----------------------------------------------\n")
    
            async(dispatch: .main, closure: closure)
            async(dispatch: .global(qos: .userInitiated), closure: closure)
            async(dispatch: .global(qos: .utility), closure: closure)
            async(dispatch: .global(qos: .default), closure: closure)
            async(dispatch: .global(qos: .userInteractive), closure: closure)
        }
    
        private func async(dispatch: DispatchQueue, closure: @escaping (Int,DispatchQueue)->()) {
    
            for index in 0..

    Full sample result

提交回复
热议问题