Improve the implementaion of task center

This commit is contained in:
Quentin Jin 2019-07-11 11:05:46 +08:00
parent e008b0671a
commit 4bb334fda4
4 changed files with 72 additions and 72 deletions

View File

@ -18,23 +18,21 @@ open class Task {
// MARK: - Private properties // MARK: - Private properties
private let _lock = NSRecursiveLock() private let _lock = NSLock()
private var _iterator: AnyIterator<Interval> private var _iterator: AnyIterator<Interval>
private let _timer: DispatchSourceTimer private let _timer: DispatchSourceTimer
private lazy var _actions = Bag<Action>() private var _actions = Bag<Action>()
private lazy var _suspensionCount: Int = 0 private var _suspensionCount = 0
private lazy var _executionCount: Int = 0 private var _executionCount = 0
private lazy var _executionDates: [Date]? = nil private var _executionDates: [Date]?
private lazy var _estimatedNextExecutionDate: Date? = nil private var _estimatedNextExecutionDate: Date?
private weak var _taskCenter: TaskCenter? private var _taskCenter: TaskCenter?
private let _taskCenterLock = NSRecursiveLock() private var _tags: Set<String> = []
private var associateKey = 1
// MARK: - Public properties // MARK: - Public properties
@ -99,31 +97,6 @@ open class Task {
return _lock.withLock { _taskCenter } return _lock.withLock { _taskCenter }
} }
// MARK: - Task center
/// Adds this task to the given task center.
func addToTaskCenter(_ center: TaskCenter) {
_taskCenterLock.lock()
defer { _taskCenterLock.unlock() }
if _taskCenter === center { return }
let c = _taskCenter
_taskCenter = center
c?.remove(self)
}
/// Removes this task from the given task center.
func removeFromTaskCenter(_ center: TaskCenter) {
_taskCenterLock.lock()
defer { _taskCenterLock.unlock() }
if _taskCenter !== center { return }
_taskCenter = nil
center.remove(self)
}
// MARK: - Init // MARK: - Init
@ -164,7 +137,7 @@ open class Task {
_suspensionCount -= 1 _suspensionCount -= 1
} }
_taskCenter?.remove(self) self.removeFromTaskCenter()
} }
private func elapse() { private func elapse() {
@ -208,11 +181,14 @@ open class Task {
/// Reschedules this task with the new plan. /// Reschedules this task with the new plan.
public func reschedule(_ new: Plan) { public func reschedule(_ new: Plan) {
_lock.withLockVoid { _lock.lock()
if _timer.isCancelled { return } if _timer.isCancelled {
_lock.unlock()
return
}
_iterator = new.makeIterator() _iterator = new.makeIterator()
} _lock.unlock()
scheduleNextExecution() scheduleNextExecution()
} }
@ -269,6 +245,29 @@ open class Task {
_actions.removeAll() _actions.removeAll()
} }
} }
/// Adds this task to the given task center.
func addToTaskCenter(_ center: TaskCenter) {
_lock.lock(); defer { _lock.unlock() }
if _taskCenter === center { return }
let c = _taskCenter
_taskCenter = center
c?.removeSimply(self)
center.addSimply(self)
}
/// Removes this task from the given task center.
public func removeFromTaskCenter() {
_lock.lock(); defer { _lock.unlock() }
guard let center = self._taskCenter else {
return
}
_taskCenter = nil
center.removeSimply(self)
}
} }
extension Task: Hashable { extension Task: Hashable {
@ -280,6 +279,6 @@ extension Task: Hashable {
/// Returns a boolean value indicating whether two tasks are equal. /// Returns a boolean value indicating whether two tasks are equal.
public static func == (lhs: Task, rhs: Task) -> Bool { public static func == (lhs: Task, rhs: Task) -> Bool {
return lhs === rhs return lhs.id == rhs.id
} }
} }

View File

@ -1,7 +1,5 @@
import Foundation import Foundation
private let _default = TaskCenter()
extension TaskCenter { extension TaskCenter {
private class TaskBox: Hashable { private class TaskBox: Hashable {
@ -27,6 +25,8 @@ extension TaskCenter {
} }
} }
private let _default = TaskCenter()
/// A task center that enables batch operation. /// A task center that enables batch operation.
open class TaskCenter { open class TaskCenter {
@ -41,30 +41,33 @@ open class TaskCenter {
} }
/// Adds the given task to this center. /// Adds the given task to this center.
///
/// Please note: task center will not retain tasks.
open func add(_ task: Task) { open func add(_ task: Task) {
task.addToTaskCenter(self) task.addToTaskCenter(self)
}
func addSimply(_ task: Task) {
lock.withLockVoid { lock.withLockVoid {
let box = TaskBox(task) let box = TaskBox(task)
self.tasks[box] = [] self.tasks[box] = []
} }
} }
/// Removes the given task from this center. func removeSimply(_ task: Task) {
open func remove(_ task: Task) {
task.removeFromTaskCenter(self)
lock.withLockVoid { lock.withLockVoid {
let box = TaskBox(task) let box = TaskBox(task)
if let tags = self.tasks[box] { guard let tags = self.tasks[box] else {
return
}
self.tasks[box] = nil
for tag in tags { for tag in tags {
self.tags[tag]?.remove(box) self.tags[tag]?.remove(box)
if self.tags[tag]?.count == 0 { if self.tags[tag]?.count == 0 {
self.tags[tag] = nil self.tags[tag] = nil
} }
} }
self.tasks[box] = nil
}
} }
} }
@ -79,12 +82,14 @@ open class TaskCenter {
/// ///
/// If the task is not in this center, do nothing. /// If the task is not in this center, do nothing.
open func addTags(_ tags: [String], to task: Task) { open func addTags(_ tags: [String], to task: Task) {
guard task.taskCenter === self else { return }
lock.withLockVoid { lock.withLockVoid {
let box = TaskBox(task) let box = TaskBox(task)
guard self.tasks[box] != nil else {
return
}
for tag in tags { for tag in tags {
tasks[box]?.insert(tag) self.tasks[box]?.insert(tag)
if self.tags[tag] == nil { if self.tags[tag] == nil {
self.tags[tag] = [] self.tags[tag] = []
} }
@ -104,10 +109,12 @@ open class TaskCenter {
/// ///
/// If the task is not in this center, do nothing. /// If the task is not in this center, do nothing.
open func removeTags(_ tags: [String], from task: Task) { open func removeTags(_ tags: [String], from task: Task) {
guard task.taskCenter === self else { return }
lock.withLockVoid { lock.withLockVoid {
let box = TaskBox(task) let box = TaskBox(task)
guard self.tasks[box] != nil else {
return
}
for tag in tags { for tag in tags {
self.tasks[box]?.remove(tag) self.tasks[box]?.remove(tag)
self.tags[tag]?.remove(box) self.tags[tag]?.remove(box)
@ -122,8 +129,6 @@ open class TaskCenter {
/// ///
/// If the task is not in this center, return an empty array. /// If the task is not in this center, return an empty array.
open func tags(forTask task: Task) -> [String] { open func tags(forTask task: Task) -> [String] {
guard task.taskCenter === self else { return [] }
return lock.withLock { return lock.withLock {
Array(tasks[TaskBox(task)] ?? []) Array(tasks[TaskBox(task)] ?? [])
} }
@ -152,9 +157,8 @@ open class TaskCenter {
/// Removes all tasks from this center. /// Removes all tasks from this center.
open func removeAll() { open func removeAll() {
lock.withLockVoid { allTasks.forEach {
tasks = [:] $0.removeFromTaskCenter()
tags = [:]
} }
} }

View File

@ -40,7 +40,7 @@ final class TaskCenterTests: XCTestCase {
let tag = UUID().uuidString let tag = UUID().uuidString
center.addTag(tag, to: task) center.addTag(tag, to: task)
center.remove(task) task.removeFromTaskCenter()
XCTAssertFalse(center.allTasks.contains(task)) XCTAssertFalse(center.allTasks.contains(task))
XCTAssertFalse(center.allTags.contains(tag)) XCTAssertFalse(center.allTags.contains(tag))

View File

@ -53,10 +53,7 @@ final class TaskTests: XCTestCase {
let task = Plan.never.do { } let task = Plan.never.do { }
XCTAssertTrue(task.taskCenter === TaskCenter.default) XCTAssertTrue(task.taskCenter === TaskCenter.default)
task.removeFromTaskCenter(TaskCenter()) task.removeFromTaskCenter()
XCTAssertNotNil(task.taskCenter)
task.removeFromTaskCenter(task.taskCenter!)
XCTAssertNil(task.taskCenter) XCTAssertNil(task.taskCenter)
let center = TaskCenter() let center = TaskCenter()