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