编辑:
我对下面提供的解决方案不满意,因为它不允许并发读取。
WriteLockableSynchronizedArray
.
它的基础是
Basem Emara's SynchronizedArray
(再次感谢,Basem),即它确实允许并发读取,并且具有以下特性:
-
它有一个方便的初始化器,可以使
从一个
Array
array
返回底层数组。
-
它有两个功能
lockArray()
unlockArray()
-
它采用
Sequence
协议,所以
for element in writeLockableSynchronizedArray {}
.
-
如果
写入按顺序执行。
以下是新的解决方案(推荐):
import Foundation
public class WriteLockableSynchronizedArray<Element> {
typealias WriteOperation = ()->Void
fileprivate var lockCounter = 0
fileprivate let queue = DispatchQueue(label: "com.zeh4soft.WriteLockableSynchronizedArray", attributes: .concurrent)
fileprivate var internalArray = [Element]()
fileprivate var deferredWriteOperations: [WriteOperation] = []
var array: [Element]? {
var result: [Element]?
queue.sync { result = self.internalArray }
return result
}
}
public extension WriteLockableSynchronizedArray {
var first: Element? {
var result: Element?
queue.sync { result = self.internalArray.first }
return result
}
var last: Element? {
var result: Element?
queue.sync { result = self.internalArray.last }
return result
}
var count: Int {
var result = 0
queue.sync { result = self.internalArray.count }
return result
}
var isEmpty: Bool {
var result = false
queue.sync { result = self.internalArray.isEmpty }
return result
}
var description: String {
var result = ""
queue.sync { result = self.internalArray.description }
return result
}
}
public extension WriteLockableSynchronizedArray {
convenience init(with array: [Element]) {
self.init()
self.internalArray = array
}
}
public extension WriteLockableSynchronizedArray {
func lockArray() {
queue.async(flags: .barrier) {
self.lockCounter += 1
}
}
func unlockArray() {
queue.sync(flags: .barrier) {
if self.lockCounter > 0 {
self.lockCounter -= 1
}
if self.lockCounter == 0 {
while self.deferredWriteOperations.count > 0 {
let nextOp = self.deferredWriteOperations.remove(at: 0)
self.queue.async(flags: .barrier) { nextOp() }
print("Enqueued deferred write op")
}
}
}
}
}
public extension WriteLockableSynchronizedArray {
func first(where predicate: (Element) -> Bool) -> Element? {
var result: Element?
queue.sync { result = self.internalArray.first(where: predicate) }
return result
}
func filter(_ isIncluded: (Element) -> Bool) -> [Element] {
var result = [Element]()
queue.sync { result = self.internalArray.filter(isIncluded) }
return result
}
func index(where predicate: (Element) -> Bool) -> Int? {
var result: Int?
queue.sync { result = self.internalArray.index(where: predicate) }
return result
}
func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element] {
var result = [Element]()
queue.sync { result = self.internalArray.sorted(by: areInIncreasingOrder) }
return result
}
func flatMap<ElementOfResult>(_ transform: (Element) -> ElementOfResult?) -> [ElementOfResult] {
var result = [ElementOfResult]()
queue.sync { result = self.internalArray.compactMap(transform) }
return result
}
func forEach(_ body: (Element) -> Void) {
queue.sync { self.internalArray.forEach(body) }
}
func contains(where predicate: (Element) -> Bool) -> Bool {
var result = false
queue.sync { result = self.internalArray.contains(where: predicate) }
return result
}
}
public extension WriteLockableSynchronizedArray {
func append( _ element: Element) {
let op = { self.internalArray.append(element) }
handleWriteOperation(op)
}
func append( _ elements: [Element]) {
let op = { self.internalArray += elements }
handleWriteOperation(op)
}
func insert( _ element: Element, at index: Int) {
let op = { self.internalArray.insert(element, at: index) }
handleWriteOperation(op)
}
func remove(at index: Int, completion: ((Element) -> Void)? = nil) {
let op = {
let element = self.internalArray.remove(at: index)
DispatchQueue.main.async {
completion?(element)
}
}
handleWriteOperation(op)
}
func remove(where predicate: @escaping (Element) -> Bool, completion: ((Element) -> Void)? = nil) {
let op = {
guard let index = self.internalArray.index(where: predicate) else { return }
let element = self.internalArray.remove(at: index)
DispatchQueue.main.async {
completion?(element)
}
}
handleWriteOperation(op)
}
func removeAll(completion: (([Element]) -> Void)? = nil) {
let op = {
let elements = self.internalArray
self.internalArray.removeAll()
DispatchQueue.main.async {
completion?(elements)
}
}
handleWriteOperation(op)
}
}
public extension WriteLockableSynchronizedArray {
subscript(index: Int) -> Element? {
get {
var result: Element?
queue.sync {
guard self.internalArray.startIndex..<self.internalArray.endIndex ~= index else { return }
result = self.internalArray[index]
}
return result
}
set {
guard let newValue = newValue else { return }
let op = { self.internalArray[index] = newValue }
handleWriteOperation(op)
}
}
}
public extension WriteLockableSynchronizedArray where Element: Equatable {
func contains(_ element: Element) -> Bool {
var result = false
queue.sync { result = self.internalArray.contains(element) }
return result
}
}
public extension WriteLockableSynchronizedArray {
static func +=(left: inout WriteLockableSynchronizedArray, right: Element) {
left.append(right)
}
static func +=(left: inout WriteLockableSynchronizedArray, right: [Element]) {
left.append(right)
}
}
extension WriteLockableSynchronizedArray: Sequence {
public func makeIterator() -> Iterator {
return Iterator(self.array)
}
public struct Iterator: IteratorProtocol {
private var index: Int
private var arr: [Element]?
init(_ array: [Element]?) {
self.arr = array
index = 0
}
mutating public func next() -> Element? {
guard let arr = self.arr, arr.count > index else { return nil }
let returnValue = arr[index]
index += 1
return returnValue
}
}
}
fileprivate extension WriteLockableSynchronizedArray {
func handleWriteOperation(_ op: @escaping WriteLockableSynchronizedArray.WriteOperation) {
queue.sync {
if self.lockCounter > 0 {
self.deferredWriteOperations.append { op() }
} else {
queue.async(flags: .barrier) {
op()
}
}
}
}
}
这是我以前的解决方案(不再推荐):
-
我实现了一个类
LockableArray
SynchronizedArray
使用递归锁同步对数组的访问。
-
我实现了一个方便的初始化器,它使
可锁定阵列
从一个
阵列
阵列
.
-
我定义了两个函数
锁阵列()
解锁数组()
可以在批处理tableView操作之前和之后调用的。
-
顺序
可锁定阵列
可用于如下语句中
for element in lockablaArray {}
.
同步阵列
.
以下是实现方法:
import Foundation
public class LockableArray<Element> {
fileprivate var lock = NSRecursiveLock()
fileprivate var privateArray = [Element]()
var array: [Element]? {
let result: [Element]
lock.lock()
result = privateArray
lock.unlock()
return result
}
}
public extension LockableArray {
var first: Element? {
var result: Element?
lock.lock()
result = self.privateArray.first
lock.unlock()
return result
}
var last: Element? {
var result: Element?
lock.lock()
result = self.privateArray.last
lock.unlock()
return result
}
var count: Int {
var result = 0
lock.lock()
result = self.privateArray.count
lock.unlock()
return result
}
var isEmpty: Bool {
var result = false
lock.lock()
result = self.privateArray.isEmpty
lock.unlock()
return result
}
var description: String {
var result = ""
lock.lock()
result = self.privateArray.description
lock.unlock()
return result
}
}
public extension LockableArray {
convenience init(with array: [Element]) {
self.init()
self.privateArray = array
}
}
public extension LockableArray {
func lockArray() {
lock.lock()
}
func unlockArray() {
lock.unlock()
}
}
public extension LockableArray {
func first(where predicate: (Element) -> Bool) -> Element? {
var result: Element?
lock.lock()
result = self.privateArray.first(where: predicate)
lock.unlock()
return result
}
func filter(_ isIncluded: (Element) -> Bool) -> [Element] {
var result = [Element]()
lock.lock()
result = self.privateArray.filter(isIncluded)
lock.unlock()
return result
}
func index(where predicate: (Element) -> Bool) -> Int? {
var result: Int?
lock.lock()
result = self.privateArray.index(where: predicate)
lock.unlock()
return result
}
func sorted(by areInIncreasingOrder: (Element, Element) -> Bool) -> [Element] {
var result = [Element]()
lock.lock()
result = self.privateArray.sorted(by: areInIncreasingOrder)
lock.unlock()
return result
}
func compactMap<ElementOfResult>(_ transform: (Element) -> ElementOfResult?) -> [ElementOfResult] {
var result = [ElementOfResult]()
lock.lock()
result = self.privateArray.compactMap(transform)
lock.unlock()
return result
}
func map<ElementOfResult>(_ transform: (Element) -> ElementOfResult) -> [ElementOfResult] {
var result = [ElementOfResult]()
lock.lock()
result = self.privateArray.map(transform)
lock.unlock()
return result
}
func forEach(_ body: (Element) -> Void) {
lock.lock()
self.privateArray.forEach(body)
lock.unlock()
}
func contains(where predicate: (Element) -> Bool) -> Bool {
var result = false
lock.lock()
result = self.privateArray.contains(where: predicate)
lock.unlock()
return result
}
}
public extension LockableArray {
func append( _ element: Element) {
lock.lock()
self.privateArray.append(element)
lock.unlock()
}
func append( _ elements: [Element]) {
lock.lock()
self.privateArray += elements
lock.unlock()
}
func insert( _ element: Element, at index: Int) {
lock.lock()
self.privateArray.insert(element, at: index)
lock.unlock()
}
func remove(at index: Int, completion: ((Element) -> Void)? = nil) {
lock.lock()
let element = self.privateArray.remove(at: index)
DispatchQueue.main.async {
completion?(element)
}
lock.unlock()
}
func remove(where predicate: @escaping (Element) -> Bool, completion: ((Element) -> Void)? = nil) {
lock.lock()
guard let index = self.privateArray.index(where: predicate) else { return }
let element = self.privateArray.remove(at: index)
DispatchQueue.main.async {
completion?(element)
}
lock.unlock()
}
func removeAll(completion: (([Element]) -> Void)? = nil) {
lock.lock()
let elements = self.privateArray
self.privateArray.removeAll()
DispatchQueue.main.async {
completion?(elements)
}
lock.unlock()
}
}
public extension LockableArray {
subscript(index: Int) -> Element? {
get {
var result: Element?
lock.lock()
guard self.privateArray.startIndex ..< self.privateArray.endIndex ~= index else { return nil }
result = self.privateArray[index]
lock.unlock()
return result
}
set {
guard let newValue = newValue else { return }
lock.lock()
self.privateArray[index] = newValue
lock.unlock()
}
}
}
public extension LockableArray where Element: Equatable {
func contains(_ element: Element) -> Bool {
var result = false
lock.lock()
result = self.privateArray.contains(element)
lock.unlock()
return result
}
}
public extension LockableArray {
static func +=(left: inout LockableArray, right: Element) {
left.append(right)
}
static func +=(left: inout LockableArray, right: [Element]) {
left.append(right)
}
}
extension LockableArray: Sequence {
public func makeIterator() -> Iterator {
return Iterator(self.array)
}
public struct Iterator: IteratorProtocol {
private var index: Int
private var arr: [Element]?
init(_ array: [Element]?) {
self.arr = array
index = 0
}
mutating public func next() -> Element? {
guard let arr = self.arr, arr.count > index else { return nil }
let returnValue = arr[index]
index += 1
return returnValue
}
}
}