Move `task.taskCenter` management to Task.swift
This commit is contained in:
parent
3358f38ee9
commit
a88a95ce13
|
@ -27,7 +27,6 @@ open class Task {
|
||||||
private var _timer: DispatchSourceTimer
|
private var _timer: DispatchSourceTimer
|
||||||
|
|
||||||
private lazy var _onElapseActions = Bag<Action>()
|
private lazy var _onElapseActions = Bag<Action>()
|
||||||
private lazy var _onDeinitActions = Bag<Action>()
|
|
||||||
|
|
||||||
private lazy var _suspensions: UInt64 = 0
|
private lazy var _suspensions: UInt64 = 0
|
||||||
private lazy var _timeline = Timeline()
|
private lazy var _timeline = Timeline()
|
||||||
|
@ -45,11 +44,39 @@ open class Task {
|
||||||
return timer
|
return timer
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
private weak var _taskCenter: TaskCenter?
|
||||||
|
|
||||||
/// The task center which this task currently in.
|
/// The task center which this task currently in.
|
||||||
open internal(set) weak var taskCenter: TaskCenter?
|
open var taskCenter: TaskCenter? {
|
||||||
|
return _taskCenter
|
||||||
|
}
|
||||||
|
|
||||||
/// The mutex used to guard task center operations.
|
/// The mutex used to guard task center operations.
|
||||||
let taskCenterMutex = NSRecursiveLock()
|
private let _taskCenterLock = NSRecursiveLock()
|
||||||
|
|
||||||
|
/// Adds this task to the given task center.
|
||||||
|
///
|
||||||
|
/// If this task is already in a task center, it will be removed from that center first.
|
||||||
|
func addToTaskCenter(_ center: TaskCenter) {
|
||||||
|
_taskCenterLock.lock()
|
||||||
|
defer { _taskCenterLock.unlock() }
|
||||||
|
|
||||||
|
if _taskCenter === center { return }
|
||||||
|
|
||||||
|
_taskCenter?.remove(self)
|
||||||
|
_taskCenter = center
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Removes this task from the given task center.
|
||||||
|
func removeFromTaskCenter(_ center: TaskCenter) {
|
||||||
|
_taskCenterLock.lock()
|
||||||
|
defer { _taskCenterLock.unlock() }
|
||||||
|
|
||||||
|
if _taskCenter !== center { return }
|
||||||
|
|
||||||
|
_taskCenter?.remove(self)
|
||||||
|
_taskCenter = nil
|
||||||
|
}
|
||||||
|
|
||||||
/// Initializes a normal task with specified plan and dispatch queue.
|
/// Initializes a normal task with specified plan and dispatch queue.
|
||||||
///
|
///
|
||||||
|
@ -81,16 +108,14 @@ open class Task {
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
for action in _onDeinitActions {
|
|
||||||
action(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
while _suspensions > 0 {
|
while _suspensions > 0 {
|
||||||
_timer.resume()
|
_timer.resume()
|
||||||
_suspensions -= 1
|
_suspensions -= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
|
taskCenter?.remove(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func scheduleNext() {
|
private func scheduleNext() {
|
||||||
|
@ -196,13 +221,6 @@ open class Task {
|
||||||
TaskCenter.default.remove(self)
|
TaskCenter.default.remove(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
|
||||||
open func onDeinit(_ body: @escaping Action) -> ActionKey {
|
|
||||||
return _mutex.withLock {
|
|
||||||
return _onDeinitActions.append(body).asActionKey()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Lifecycle
|
// MARK: - Lifecycle
|
||||||
|
|
||||||
/// The snapshot timeline of this task.
|
/// The snapshot timeline of this task.
|
||||||
|
@ -337,7 +355,6 @@ extension Task: CustomStringConvertible {
|
||||||
return "Task: { " +
|
return "Task: { " +
|
||||||
"\"isCancelled\": \(_timer.isCancelled), " +
|
"\"isCancelled\": \(_timer.isCancelled), " +
|
||||||
"\"countOfElapseActions\": \(_onElapseActions.count), " +
|
"\"countOfElapseActions\": \(_onElapseActions.count), " +
|
||||||
"\"countOfDeinitActions\": \(_onDeinitActions.count), " +
|
|
||||||
"\"countOfExecutions\": \(_countOfExecutions), " +
|
"\"countOfExecutions\": \(_countOfExecutions), " +
|
||||||
"\"lifeTime\": \(_lifetime), " +
|
"\"lifeTime\": \(_lifetime), " +
|
||||||
"\"timeline\": \(_timeline)" +
|
"\"timeline\": \(_timeline)" +
|
||||||
|
|
|
@ -8,7 +8,6 @@ extension TaskCenter {
|
||||||
|
|
||||||
weak var task: Task?
|
weak var task: Task?
|
||||||
|
|
||||||
// Used to find slot
|
|
||||||
let hash: Int
|
let hash: Int
|
||||||
|
|
||||||
init(_ task: Task) {
|
init(_ task: Task) {
|
||||||
|
@ -20,68 +19,52 @@ extension TaskCenter {
|
||||||
hasher.combine(hash)
|
hasher.combine(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used to find task
|
|
||||||
static func == (lhs: TaskBox, rhs: TaskBox) -> Bool {
|
static func == (lhs: TaskBox, rhs: TaskBox) -> Bool {
|
||||||
return lhs.task == rhs.task
|
return lhs.task == rhs.task
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A task mamanger that enables batch tasks operation.
|
/// A task center that enables batch operation.
|
||||||
open class TaskCenter {
|
open class TaskCenter {
|
||||||
|
|
||||||
private let mutex = NSLock()
|
private let lock = NSLock()
|
||||||
|
|
||||||
private var taskMap: [String: Set<TaskBox>] = [:]
|
private var tasksOfTag: [String: Set<TaskBox>] = [:]
|
||||||
private var tagMap: [TaskBox: Set<String>] = [:]
|
private var tagsOfTask: [TaskBox: Set<String>] = [:]
|
||||||
|
|
||||||
|
/// Default task center.
|
||||||
open class var `default`: TaskCenter {
|
open class var `default`: TaskCenter {
|
||||||
return _default
|
return _default
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a task to this center.
|
/// Adds the given task to this center.
|
||||||
///
|
///
|
||||||
/// Center won't retain the task.
|
/// Center won't retain the task.
|
||||||
open func add(_ task: Task) {
|
open func add(_ task: Task) {
|
||||||
task.taskCenterMutex.lock()
|
task.addToTaskCenter(self)
|
||||||
|
|
||||||
if let center = task.taskCenter {
|
lock.withLockVoid {
|
||||||
if center === self { return }
|
|
||||||
center.remove(task)
|
|
||||||
}
|
|
||||||
task.taskCenter = self
|
|
||||||
|
|
||||||
task.taskCenterMutex.unlock()
|
|
||||||
|
|
||||||
mutex.withLockVoid {
|
|
||||||
let box = TaskBox(task)
|
let box = TaskBox(task)
|
||||||
tagMap[box] = []
|
tagsOfTask[box] = []
|
||||||
}
|
|
||||||
|
|
||||||
task.onDeinit { [weak self] (t) in
|
|
||||||
guard let self = self else { return }
|
|
||||||
self.remove(t)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes a task from this center.
|
/// Removes the given task from this center.
|
||||||
open func remove(_ task: Task) {
|
open func remove(_ task: Task) {
|
||||||
task.taskCenterMutex.lock()
|
task.removeFromTaskCenter(self)
|
||||||
|
|
||||||
guard task.taskCenter === self else {
|
lock.withLockVoid {
|
||||||
return
|
|
||||||
}
|
|
||||||
task.taskCenter = nil
|
|
||||||
|
|
||||||
task.taskCenterMutex.unlock()
|
|
||||||
|
|
||||||
mutex.withLockVoid {
|
|
||||||
let box = TaskBox(task)
|
let box = TaskBox(task)
|
||||||
if let tags = self.tagMap[box] {
|
if let tags = self.tagsOfTask[box] {
|
||||||
for tag in tags {
|
for tag in tags {
|
||||||
self.taskMap[tag]?.remove(box)
|
self.tasksOfTag[tag]?.remove(box)
|
||||||
|
|
||||||
|
if self.tasksOfTag[tag]?.count == 0 {
|
||||||
|
self.tasksOfTag[tag] = nil
|
||||||
}
|
}
|
||||||
self.tagMap[box] = nil
|
}
|
||||||
|
self.tagsOfTask[box] = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,17 +82,17 @@ open class TaskCenter {
|
||||||
open func addTags(_ tags: [String], to task: Task) {
|
open func addTags(_ tags: [String], to task: Task) {
|
||||||
guard task.taskCenter === self else { return }
|
guard task.taskCenter === self else { return }
|
||||||
|
|
||||||
mutex.withLockVoid {
|
lock.withLockVoid {
|
||||||
let box = TaskBox(task)
|
let box = TaskBox(task)
|
||||||
if tagMap[box] == nil {
|
if tagsOfTask[box] == nil {
|
||||||
tagMap[box] = []
|
tagsOfTask[box] = []
|
||||||
}
|
}
|
||||||
for tag in tags {
|
for tag in tags {
|
||||||
tagMap[box]?.insert(tag)
|
tagsOfTask[box]?.insert(tag)
|
||||||
if taskMap[tag] == nil {
|
if tasksOfTag[tag] == nil {
|
||||||
taskMap[tag] = []
|
tasksOfTag[tag] = []
|
||||||
}
|
}
|
||||||
taskMap[tag]?.insert(box)
|
tasksOfTag[tag]?.insert(box)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,11 +110,11 @@ open class TaskCenter {
|
||||||
open func removeTags(_ tags: [String], from task: Task) {
|
open func removeTags(_ tags: [String], from task: Task) {
|
||||||
guard task.taskCenter === self else { return }
|
guard task.taskCenter === self else { return }
|
||||||
|
|
||||||
mutex.withLockVoid {
|
lock.withLockVoid {
|
||||||
let box = TaskBox(task)
|
let box = TaskBox(task)
|
||||||
for tag in tags {
|
for tag in tags {
|
||||||
tagMap[box]?.remove(tag)
|
tagsOfTask[box]?.remove(tag)
|
||||||
taskMap[tag]?.remove(box)
|
tasksOfTag[tag]?.remove(box)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,37 +125,37 @@ open class TaskCenter {
|
||||||
open func tagsForTask(_ task: Task) -> [String] {
|
open func tagsForTask(_ task: Task) -> [String] {
|
||||||
guard task.taskCenter === self else { return [] }
|
guard task.taskCenter === self else { return [] }
|
||||||
|
|
||||||
return mutex.withLock {
|
return lock.withLock {
|
||||||
Array(tagMap[TaskBox(task)] ?? [])
|
Array(tagsOfTask[TaskBox(task)] ?? [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all tasks that have the tag.
|
/// Returns all tasks that have the tag.
|
||||||
open func tasksForTag(_ tag: String) -> [Task] {
|
open func tasksForTag(_ tag: String) -> [Task] {
|
||||||
return mutex.withLock {
|
return lock.withLock {
|
||||||
taskMap[tag]?.compactMap { $0.task } ?? []
|
tasksOfTag[tag]?.compactMap { $0.task } ?? []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all tasks in this center.
|
/// Returns all tasks in this center.
|
||||||
open var allTasks: [Task] {
|
open var allTasks: [Task] {
|
||||||
return mutex.withLock {
|
return lock.withLock {
|
||||||
tagMap.compactMap { $0.key.task }
|
tagsOfTask.compactMap { $0.key.task }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all existing tags in this center.
|
/// Returns all existing tags in this center.
|
||||||
open var allTags: [String] {
|
open var allTags: [String] {
|
||||||
return mutex.withLock {
|
return lock.withLock {
|
||||||
taskMap.map { $0.key }
|
tasksOfTag.map { $0.key }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Removes all tasks in this center.
|
/// Removes all tasks from this center.
|
||||||
open func clear() {
|
open func removeAll() {
|
||||||
mutex.withLockVoid {
|
lock.withLockVoid {
|
||||||
tagMap = [:]
|
tagsOfTask = [:]
|
||||||
taskMap = [:]
|
tasksOfTag = [:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ final class TaskCenterTests: XCTestCase {
|
||||||
func testDefault() {
|
func testDefault() {
|
||||||
let task = makeTask()
|
let task = makeTask()
|
||||||
XCTAssertTrue(center.allTasks.contains(task))
|
XCTAssertTrue(center.allTasks.contains(task))
|
||||||
center.clear()
|
center.removeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAdd() {
|
func testAdd() {
|
||||||
|
@ -31,7 +31,7 @@ final class TaskCenterTests: XCTestCase {
|
||||||
c.add(task)
|
c.add(task)
|
||||||
XCTAssertEqual(c.allTasks.count, 1)
|
XCTAssertEqual(c.allTasks.count, 1)
|
||||||
|
|
||||||
center.clear()
|
center.removeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRemove() {
|
func testRemove() {
|
||||||
|
@ -53,7 +53,7 @@ final class TaskCenterTests: XCTestCase {
|
||||||
XCTAssertFalse(center.tasksForTag(tag).contains(task))
|
XCTAssertFalse(center.tasksForTag(tag).contains(task))
|
||||||
XCTAssertFalse(center.tagsForTask(task).contains(tag))
|
XCTAssertFalse(center.tagsForTask(task).contains(tag))
|
||||||
|
|
||||||
center.clear()
|
center.removeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAll() {
|
func testAll() {
|
||||||
|
@ -65,7 +65,7 @@ final class TaskCenterTests: XCTestCase {
|
||||||
XCTAssertEqual(center.allTags, [tag])
|
XCTAssertEqual(center.allTags, [tag])
|
||||||
XCTAssertEqual(center.allTasks, [task])
|
XCTAssertEqual(center.allTasks, [task])
|
||||||
|
|
||||||
center.clear()
|
center.removeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOperation() {
|
func testOperation() {
|
||||||
|
@ -84,7 +84,7 @@ final class TaskCenterTests: XCTestCase {
|
||||||
center.cancelByTag(tag)
|
center.cancelByTag(tag)
|
||||||
XCTAssertTrue(task.isCancelled)
|
XCTAssertTrue(task.isCancelled)
|
||||||
|
|
||||||
center.clear()
|
center.removeAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWeak() {
|
func testWeak() {
|
||||||
|
|
Loading…
Reference in New Issue