QueueSafeValue 0.8

QueueSafeValue 0.8

Vasily Bodnarchuk 维护。



  • Vasily Bodnarchuk

QueueSafeValue

Build&Test Version License Platform

提供对值进行线程安全(队列安全)访问的框架。

优势

  1. 内嵌 DispatchSemaphore

    只需使用 QueueSafeValue 的特定访问函数(commands),无需考虑线程同步。

  2. 内置 scheduler

    调度器组织同步和异步 commands 的执行。

  3. 内嵌 Comand Queue优先队列

    指令队列用于组织指令的顺序。所有指令将按照优先级顺序逐一执行。

  4. 优先级指令执行

    能够优先更新或访问QueueSafeValue。这意味着某些指令将比其他指令运行得更快。

  5. 不会增加对象引用计数

  6. 始终返回结果并避免返回可选类型

    始终返回 Result<Value, QueueSafeValueError>

  7. 提供不同的值操作指令

    原子指令: queueSafeValue.wait.lowestPriority.get()

    闭包中的值处理指令: queueSafeValue.wait.lowestPriority.get { result in ... }

    闭包中的值访问指令: queueSafeValue.wait.lowestPriority.set { currentValue in currentVaule = newValue }

文档

命令的基本结构

queueSafeValue.{schedule}.{priority}.{command}

定义

🇨🇳🇴🇲🇦🇳🇩   🇶🇺🇪🇺🇪

  • 存储 commands 并按正确的优先级顺序执行它们
  • QueueSafeValue 内置 command queue (priority queue),所有 closures (commands) 都将被放置在其中并执行

🇨🇱🇴🇸🇺🇷🇪🇸

  • 是一个访问值的闭包内部
  • 从对 value 的并发访问中受到保护(作为 critical section,基于 DispatchGroup 的实现)

可用的命令闭包:

  • commandClosure - 提供对 value 的访问
  • accessClosure - 提供对值的直接访问(使用 inout 关键字)
  • commandCompletionClosure - 必须始终执行(如果作为属性位于 commandClosureaccessClosure 内部)的闭包。执行闭包通知 command queue 命令已完成。之后,command queue 将取消对值的阻塞并执行下一个命令,如果存在的话。

执行方法:

  • completion commandClosure/accessClosure - 期望在自身内部使用序列代码的闭包
  • manualCompletion commandClosure/accessClosure - 期望在自身内部使用序列/异步代码的闭包。此闭包必须手动调用 CommandCompletionClosure,将其作为属性放置在 commandClosureaccessClosure 内部

请求数据组件

🇸🇨🇭🇪🇩🇺🇱🇪

描述 func 将会以同步或异步方式执行

可选的计划:

  • wait - (同步)依次执行 commands。阻塞此代码运行的队列,直到任务完成
  • async - 异步执行被此函数调用的队列中的 command

🇵🇷🇮🇴🇷🇮🇹🇾

描述在 命令队列command 何时(按什么顺序)执行

可选的优先级:

  • lowestPriority - 级别最低的 command 将会被最后执行
  • highestPriority - 级别最高的 command 将被最先执行

🇨🇴🇵🇷🇸🇦🇳🇩

描述对 value 的处理(提供对 value 的访问)

可用的同步命令

1. get 同步获取值

  • 返回 CurrentValueQueueSafeValueError
  • 当只需要的返回 value(不处理 value)时使用
func get() -> Result<CurrentValue, QueueSafeValueError>

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: true)
DispatchQueue.global(qos: .utility).async {
    let result = queueSafeValue.wait.lowestPriority.get()
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2
let queueSafeSyncedValue = QueueSafeSyncedValue(value: "a")
DispatchQueue.global(qos: .utility).async {
    let result = queueSafeSyncedValue.lowestPriority.get()
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

2. 在 commandClosure 中同步获取 get

  • commandClosure 内部返回 CurrentValueQueueSafeValueError
  • 当在 commandClosure 中对 value 进行处理时,需要保持对 value 的读取/写入时,用作 critical section
  • commandClosure 将自动完成
func get(completion commandClosure: ((Result<CurrentValue, QueueSafeValueError>) -> Void)?)

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: 6)
DispatchQueue.global(qos: .unspecified).async {
    queueSafeValue.wait.lowestPriority.get { result in
        switch result {
        case .failure(let error): print(error)
        case .success(let value): print(value)
        }
    }
}

// Option 2
let queueSafeSyncedValue = QueueSafeSyncedValue(value: [1,2,3])
DispatchQueue.global(qos: .utility).async {
    queueSafeSyncedValue.lowestPriority.get { result in
        switch result {
        case .failure(let error): print(error)
        case .success(let value): print(value)
        }
    }
}

3. 在 commandClosure 中手动完成同步获取 get

  • commandClosure 内部返回 CurrentValueQueueSafeValueErrorCommandCompletionClosure
  • 当在 commandClosure 中对 value 进行处理时,需要保持对 value 的读取/写入时,用作 critical section
  • 重要:必须通过执行(调用)CommandCompletionClosure 来手动完成 commandClosure
func get(manualCompletion commandClosure: ((Result<CurrentValue, QueueSafeValueError>,
                                            @escaping CommandCompletionClosure) -> Void)?)                                            

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: 4.44)
DispatchQueue.global(qos: .unspecified).async {
    queueSafeValue.wait.highestPriority.get { result, done in
        switch result {
        case .failure(let error): print(error)
        case .success(let value): print(value)
        }
        done() // Must always be executed (called). Can be called in another DispatchQueue.
    }
}

// Option 2
let queueSafeSyncedValue = QueueSafeSyncedValue(value: 4.45)
DispatchQueue.global(qos: .utility).async {
    queueSafeSyncedValue.highestPriority.get { result, done in
        switch result {
        case .failure(let error): print(error)
        case .success(let value): print(value)
        }
        done() // Must always be executed (called). Can be called in another DispatchQueue.
    }
}

4. 同步设置 set

  • 返回 UpdatedValueQueueSafeValueError
  • 当只需要设置 value(不需要对 value 进行处理)时使用
@discardableResult
func set(newValue: Value) -> Result<UpdatedValue, QueueSafeValueError>

代码示例

// Option 1
let queueSafeValue = QueueSafeValue<Int>(value: 1)
DispatchQueue.global(qos: .userInitiated).async {
    let result = queueSafeValue.wait.lowestPriority.set(newValue: 2)
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2
let queueSafeSyncedValue = QueueSafeSyncedValue(value: "b")
DispatchQueue.global(qos: .userInitiated).async {
    let result = queueSafeSyncedValue.lowestPriority.set(newValue: "b1")
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

5. 在 accessClosure 中同步设置 set

  • accessClosure 内部设置 CurrentValue
  • 当在一个闭包中需要同时读取和写入 value 时使用
  • 当在 accessClosure 处理 value 时需要保持对 value 的读取/写入时,用作 critical section
  • 注意:如果发生任何 QueueSafeValueError,则不会运行 accessClosure
@discardableResult
func set(completion accessClosure: ((inout CurrentValue) -> Void)?) -> Result<UpdatedValue, QueueSafeValueError>

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: 1)
DispatchQueue.main.async {
    let result = queueSafeValue.wait.lowestPriority.set { $0 = 3 }
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2
let queueSafeSyncedValue = QueueSafeSyncedValue(value: ["a":1])
DispatchQueue.main.async {
    let result = queueSafeSyncedValue.lowestPriority.set { $0["b"] = 2 }
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

6. 在 accessClosure 中同步设置值,并使用手动完成

  • accessClosure 内部设置 CurrentValue
  • 当在一个闭包中需要同时读取和写入 value 时使用
  • 当在 accessClosure 处理 value 时需要保持对 value 的读取/写入时,用作 critical section
  • 重要: accessClosure 必须通过执行(调用)CommandCompletionClosure 来手动完成
  • 注意: 若出现任何 QueueSafeValueError,将不会运行 accessClosure
@discardableResult
func set(manualCompletion accessClosure: ((inout CurrentValue, 
                                           @escaping CommandCompletionClosure) -> Void)?) -> Result<UpdatedValue, QueueSafeValueError>

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: "value 1")
DispatchQueue.main.async {
    let result = queueSafeValue.wait.lowestPriority.set { currentValue, done in
        currentValue = "value 2"
        done() // Must always be executed (called). Can be called in another DispatchQueue.
    }
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2
let queueSafeSyncedValue = QueueSafeSyncedValue(value: "value a")
DispatchQueue.main.async {
    let result = queueSafeSyncedValue.lowestPriority.set { currentValue, done in
        currentValue = "value b"
        done() // Must always be executed (called). Can be called in another DispatchQueue.
    }
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

7. 在 commandClosure 中同步映射值

  • commandClosure 中将 CurrentValue 映射到 MappedValue
  • 当在 commandClosure 中对 value 进行处理时,需要保持对 value 的读取/写入时,用作 critical section
func map<MappedValue>(completion commandClosure: ((CurrentValue) -> MappedValue)?) -> Result<MappedValue, QueueSafeValueError>

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: 5)
DispatchQueue.global(qos: .background).async {
    let result = queueSafeValue.wait.lowestPriority.map { "\($0)" }
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2
let queueSafeSyncedValue = QueueSafeSyncedValue(value: "1")
DispatchQueue.global(qos: .background).async {
    let result = queueSafeSyncedValue.lowestPriority.map { Int($0) }
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(String(describing: value))
    }
}

可用的异步命令

1. 在 commandClosure 中异步获取值

  • commandClosure 中返回 CurrentValueQueueSafeValueError
  • 当在 commandClosure 中对 value 进行处理时,需要保持对 value 的读取/写入时,用作 critical section
  • commandClosure 将自动完成
func get(completion commandClosure: ((Result<CurrentValue, QueueSafeValueError>) -> Void)?)

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: true)
queueSafeValue.async(performIn: .global(qos: .utility)).highestPriority.get { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2
let queueSafeAsyncedValue = QueueSafeAsyncedValue(value: true, queue: .global(qos: .utility))
queueSafeAsyncedValue.highestPriority.get { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

2. 在 commandClosure 中异步获取值,并使用手动完成

  • commandClosure 内部返回 CurrentValueQueueSafeValueErrorCommandCompletionClosure
  • 当在 commandClosure 中对 value 进行处理时,需要保持对 value 的读取/写入时,用作 critical section
  • 重要:必须通过执行(调用)CommandCompletionClosure 来手动完成 commandClosure
func get(manualCompletion commandClosure: ((Result<CurrentValue, QueueSafeValueError>,
                                            @escaping CommandCompletionClosure) -> Void)?)

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: "test")
queueSafeValue.async(performIn: .global(qos: .utility)).highestPriority.get { result, done in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
    done() // Must always be executed (called). Can be called in another DispatchQueue.
}

// Option 2
let queueSafeAsyncedValue = QueueSafeAsyncedValue(value: "super test", queue: .global(qos: .background))
queueSafeAsyncedValue.highestPriority.get { result, done in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
    done() // Must always be executed (called). Can be called in another DispatchQueue.
}

3. set value 同步

  • commandClosure 中返回 UpdatedValueQueueSafeValueError
  • 当只需要设置 value(不需要对 value 进行处理)时使用
func set(newValue: Value, completion commandClosure: ((Result<UpdatedValue, QueueSafeValueError>) -> Void)? = nil)

代码示例

// Option 1
let queueSafeValue = QueueSafeValue(value: 7)

// Without completion block
queueSafeValue.async(performIn: .main).highestPriority.set(newValue: 8)

// With completion block
queueSafeValue.async(performIn: .main).highestPriority.set(newValue: 9) { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2
let queueSafeAsyncedValue = QueueSafeAsyncedValue(value: 7, queue: .global())

// Without completion block
queueSafeAsyncedValue.highestPriority.set(newValue: 8)

// With completion block
queueSafeAsyncedValue.highestPriority.set(newValue: 9) { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

4. set value 同步在 accessClosure

  • accessClosure 内部设置 CurrentValue
  • 当在一个闭包中需要同时读取和写入 value 时使用
  • 当在 accessClosure 处理 value 时需要保持对 value 的读取/写入时,用作 critical section
  • 注意:如果发生任何 QueueSafeValueError,则不会运行 accessClosure
func set(accessClosure: ((inout CurrentValue) -> Void)?,
         completion commandClosure: ((Result<UpdatedValue, QueueSafeValueError>) -> Void)? = nil)

代码示例

// Option 1.
let queueSafeValue = QueueSafeValue(value: 1)

// Without completion block
queueSafeValue.async(performIn: .background).highestPriority.set { $0 = 10 }

// With completion block
queueSafeValue.async(performIn: .background).highestPriority.set { currentValue in
    currentValue = 11
} completion: { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2.
let queueSafeAsyncedValue = QueueSafeAsyncedValue(value: 1, queue: .global(qos: .userInteractive))

// Without completion block
queueSafeAsyncedValue.highestPriority.set { $0 = 10 }

// With completion block
queueSafeAsyncedValue.highestPriority.set { currentValue in
    currentValue = 11
} completion: { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

5. set value 同步在 accessClosure 中,带有手动完成

  • accessClosure 内部设置 CurrentValue
  • 当在一个闭包中需要同时读取和写入 value 时使用
  • 当在 accessClosure 处理 value 时需要保持对 value 的读取/写入时,用作 critical section
  • 重要: accessClosure 必须通过执行(调用)CommandCompletionClosure 来手动完成
  • 注意: 若出现任何 QueueSafeValueError,将不会运行 accessClosure
func set(manualCompletion accessClosure: ((inout CurrentValue, @escaping CommandCompletionClosure) -> Void)?,
         completion commandClosure: ((Result<UpdatedValue, QueueSafeValueError>) -> Void)? = nil) 

代码示例

// Option 1.
let queueSafeValue = QueueSafeValue(value: 999.1)

// Without completion block
queueSafeValue.async(performIn: .background).highestPriority.set { currentValue, done in
    currentValue = 999.2
    done() // Must always be executed (called). Can be called in another DispatchQueue.
}

// With completion block
queueSafeValue.async(performIn: .background).highestPriority.set { currentValue, done in
    currentValue = 999.3
    done() // Must always be executed (called). Can be called in another DispatchQueue.
} completion: { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

// Option 2.
let queueSafeAsyncedValue = QueueSafeAsyncedValue(value: 1000.1, queue: .global(qos: .userInteractive))

// Without completion block
queueSafeAsyncedValue.highestPriority.set { currentValue, done in
    currentValue = 1000.2
    done() // Must always be executed (called). Can be called in another DispatchQueue.
}

// With completion block
queueSafeAsyncedValue.highestPriority.set { currentValue, done in
    currentValue = 1000.3
    done() // Must always be executed (called). Can be called in another DispatchQueue.
} completion: { result in
    switch result {
    case .failure(let error): print(error)
    case .success(let value): print(value)
    }
}

需求

  • iOS 8.0+
  • Xcode 10+
  • Swift 5.1+

安装

步骤 1

QueueSafeValue 通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中

pod 'QueueSafeValue'

步骤 2

在项目根目录下运行 pod install

步骤 3

要使用已安装的 QueueSafeValue 框架,只需在你要应用它的 swift 文件中导入 QueueSafeValue

作者

瓦西里·博德纳尔丘克,https://www.linkedin.com/in/vasily-bodnarchuk/

许可证

QueueSafeValue 适用于 MIT 许可证。有关更多信息,请参阅 LICENSE 文件。