diff --git a/Sources/Schedule/Task.swift b/Sources/Schedule/Task.swift index 83c3272..092a12c 100644 --- a/Sources/Schedule/Task.swift +++ b/Sources/Schedule/Task.swift @@ -17,24 +17,22 @@ extension BagKey { open class Task { // MARK: - Private properties - - private let _lock = NSRecursiveLock() + + private let _lock = NSLock() private var _iterator: AnyIterator private let _timer: DispatchSourceTimer - private lazy var _actions = Bag() + private var _actions = Bag() - private lazy var _suspensionCount: Int = 0 - private lazy var _executionCount: Int = 0 + private var _suspensionCount = 0 + private var _executionCount = 0 - private lazy var _executionDates: [Date]? = nil - private lazy var _estimatedNextExecutionDate: Date? = nil + private var _executionDates: [Date]? + private var _estimatedNextExecutionDate: Date? - private weak var _taskCenter: TaskCenter? - private let _taskCenterLock = NSRecursiveLock() - - private var associateKey = 1 + private var _taskCenter: TaskCenter? + private var _tags: Set = [] // MARK: - Public properties @@ -99,31 +97,6 @@ open class Task { 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 @@ -164,7 +137,7 @@ open class Task { _suspensionCount -= 1 } - _taskCenter?.remove(self) + self.removeFromTaskCenter() } private func elapse() { @@ -208,11 +181,14 @@ open class Task { /// Reschedules this task with the new plan. public func reschedule(_ new: Plan) { - _lock.withLockVoid { - if _timer.isCancelled { return } - - _iterator = new.makeIterator() + _lock.lock() + if _timer.isCancelled { + _lock.unlock() + return } + + _iterator = new.makeIterator() + _lock.unlock() scheduleNextExecution() } @@ -269,6 +245,29 @@ open class Task { _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 { @@ -280,6 +279,6 @@ extension Task: Hashable { /// Returns a boolean value indicating whether two tasks are equal. public static func == (lhs: Task, rhs: Task) -> Bool { - return lhs === rhs + return lhs.id == rhs.id } } diff --git a/Sources/Schedule/TaskCenter.swift b/Sources/Schedule/TaskCenter.swift index d847f59..54be368 100644 --- a/Sources/Schedule/TaskCenter.swift +++ b/Sources/Schedule/TaskCenter.swift @@ -1,7 +1,5 @@ import Foundation -private let _default = TaskCenter() - extension TaskCenter { private class TaskBox: Hashable { @@ -27,6 +25,8 @@ extension TaskCenter { } } +private let _default = TaskCenter() + /// A task center that enables batch operation. open class TaskCenter { @@ -41,29 +41,32 @@ open class TaskCenter { } /// Adds the given task to this center. + /// + /// Please note: task center will not retain tasks. open func add(_ task: Task) { task.addToTaskCenter(self) - + } + + func addSimply(_ task: Task) { lock.withLockVoid { let box = TaskBox(task) self.tasks[box] = [] } } - - /// Removes the given task from this center. - open func remove(_ task: Task) { - task.removeFromTaskCenter(self) - + + func removeSimply(_ task: Task) { lock.withLockVoid { let box = TaskBox(task) - if let tags = self.tasks[box] { - for tag in tags { - self.tags[tag]?.remove(box) - if self.tags[tag]?.count == 0 { - self.tags[tag] = nil - } + guard let tags = self.tasks[box] else { + return + } + + self.tasks[box] = nil + for tag in tags { + self.tags[tag]?.remove(box) + if self.tags[tag]?.count == 0 { + 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. open func addTags(_ tags: [String], to task: Task) { - guard task.taskCenter === self else { return } - lock.withLockVoid { let box = TaskBox(task) + guard self.tasks[box] != nil else { + return + } + for tag in tags { - tasks[box]?.insert(tag) + self.tasks[box]?.insert(tag) if self.tags[tag] == nil { self.tags[tag] = [] } @@ -104,10 +109,12 @@ open class TaskCenter { /// /// If the task is not in this center, do nothing. open func removeTags(_ tags: [String], from task: Task) { - guard task.taskCenter === self else { return } - lock.withLockVoid { let box = TaskBox(task) + guard self.tasks[box] != nil else { + return + } + for tag in tags { self.tasks[box]?.remove(tag) self.tags[tag]?.remove(box) @@ -122,8 +129,6 @@ open class TaskCenter { /// /// If the task is not in this center, return an empty array. open func tags(forTask task: Task) -> [String] { - guard task.taskCenter === self else { return [] } - return lock.withLock { Array(tasks[TaskBox(task)] ?? []) } @@ -152,9 +157,8 @@ open class TaskCenter { /// Removes all tasks from this center. open func removeAll() { - lock.withLockVoid { - tasks = [:] - tags = [:] + allTasks.forEach { + $0.removeFromTaskCenter() } } diff --git a/Tests/ScheduleTests/TaskCenterTests.swift b/Tests/ScheduleTests/TaskCenterTests.swift index 7474067..8e4fcc3 100644 --- a/Tests/ScheduleTests/TaskCenterTests.swift +++ b/Tests/ScheduleTests/TaskCenterTests.swift @@ -40,7 +40,7 @@ final class TaskCenterTests: XCTestCase { let tag = UUID().uuidString center.addTag(tag, to: task) - center.remove(task) + task.removeFromTaskCenter() XCTAssertFalse(center.allTasks.contains(task)) XCTAssertFalse(center.allTags.contains(tag)) diff --git a/Tests/ScheduleTests/TaskTests.swift b/Tests/ScheduleTests/TaskTests.swift index adb4c0a..36bcc7a 100644 --- a/Tests/ScheduleTests/TaskTests.swift +++ b/Tests/ScheduleTests/TaskTests.swift @@ -53,10 +53,7 @@ final class TaskTests: XCTestCase { let task = Plan.never.do { } XCTAssertTrue(task.taskCenter === TaskCenter.default) - task.removeFromTaskCenter(TaskCenter()) - XCTAssertNotNil(task.taskCenter) - - task.removeFromTaskCenter(task.taskCenter!) + task.removeFromTaskCenter() XCTAssertNil(task.taskCenter) let center = TaskCenter()