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

View File

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

View File

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