Move `task.taskCenter` management to Task.swift

This commit is contained in:
Quentin Jin 2019-04-04 18:10:24 +08:00
parent 3358f38ee9
commit a88a95ce13
3 changed files with 81 additions and 81 deletions

View File

@ -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)" +

View File

@ -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 = [:]
} }
} }

View File

@ -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() {