I have a value type for which a relatively long calculation is require to produce it (> 1s). I wrap this value type in an enumeration that expresses whether it is currently being calculated or is available:
enum Calculatable<T> {
case calculated(T), calculating
}
The problem is this value is persisted. This means after the long running calculation, when I have the updated value, I try to persist it first before changing the property visible to the business logic. If persistence succeeds, the property is updated, if it fails, I want to wait and then try to persist again; with a catch — if any other values have changed that the calculated one depends on, we throw away the previously calculated value — stop trying to persist it — and submit a new Calculation operation to the queue — starting all over again. My initial attempt at that looked something like this:
/// Wraps a value that takes a long time to be calculated.
public class CalculatedValueWrapper<T> {
/// The last submitted `Calculation` to the queue.
private weak var latestCalculation: Optional<Operation>
/// The long running calculation that produces the up to date, wrapped value.
private let longCalculation: (_ cancelIf: () -> Bool) -> T
/// Calculation queue.
private let queue: OperationQueue
/// The calculated value.
private var wrappedValue: Calculatable<T>
/// Update the wrapped value.
public func update() {
// Don't set if already being calculated.
if case .calculated(_)=self.wrappedValue { self.wrappedValue = .calculating }
// Initiate new calculation.
self.latestCalculation?.cancel()
self.latestCalculation={
let calc: Calculation = .init(self, self.longCalculation)
self.queue.addOperation(calc)
return calc
}()
}
}
/// Executes a long running calculation and persists the result once complete.
class Calculation<T>: Operation {
/// The calculation.
private let calculation: (_ cancelIf: () -> Bool) -> T
/// The owner of the wrapped value we're calculating.
private weak var owner: Optional<CalculatedValueWrapper<T>>
func main() {
let result=self.calculation(cancelIf: { [unowned self] in self.isCancelled })
let persist: () -> Bool={
// In case the persistence fails.
var didPersist=false
// Persist the result on the main thread.
DispatchQueue.main.sync { [unowned self] in
// The owner may have been deallocated between the time this dispatch item was submitted and the time it began executing.
guard let owner=self.owner else { self.cancel(); return }
// May have been cancelled.
guard !self.isCancelled else { return }
// Attempt to persist the calculated result.
if let _=try? owner.persist(result) {
didPersist=true
}
}
// Done.
return didPersist
}
// Persist the new result. If it fails, and we're not cancelled, keep trying until it succeeds.
while !self.isCancelled && !self.persist() {
usleep(500_000)
}
}
}
I would have stuck with this, but after further research I noticed a prevailing sentiment that it was bad practice to sleep the thread in DispatchQueue items and Operations. The alternative that seems to be considered better, in the case of DispatchQueue for example, was to initiate another DispatchQueue item using asyncAfter(deadline:execute:).
That solution appears more complicated in my case as being able to cancel a single operation that encapsulates everything that needs to be done makes cancelling easy. I can hold a reference to the last Calculation operation executed, and if another one is submitted on the main thread while one is in progress, I cancel the old one, add the new one, and with that I know the old value won't be persisted because it is done on the main thread after cancellation has already been performed; and a Calculation must not be cancelled in order for it to persist its result.
Is there something about DispatchQueues or OperationQueues that would make the alternative solution more straightforward to implement in this case? Or is sleeping here totally fine?
Make a RetryPersist NSOperation. Just before adding it to the queue, set its isReady to false. Have it do a dispatchAfter weakly capturing itself to set its isReady to true. Now you can cancel any RetryPersist operations in the queue, if the count of them where not ready, not cancelled is not zero you know there’s one waiting to go etc.
Related
I'm trying to unit test a property in a ViewModel (in Swift) that is dependent on a series of other properties being set, and having trouble doing so.
I have a viewModel which includes a timeLength, a timePeriod, and a listOfObjects that fits my time period.
These values depend on the previous one,
timeLength and timePeriod are both stored in the user's profile, and my code follows this flow:
Search for a timeLength in the profile.
If none is found, allow the user to select a timeLength
Once the timeLength is set, a didSet triggers a flow that searches for a matching timePeriod, (in a mock repository for time periods) or creates one if one doesn't exist.
Once the timePeriod exists, a didSet triggers a flow that searches a database to compile a listOfObjects that match that timePeriod (using a separate mockRepository for objects).
I'm trying to create a unit test that checks the list of objects once that code flow is completed, but every time I do so, the XCTAssertEqual method completes before the code flow is finished. I tried using XCTestExpectation, as described in Hacking with Swift, but I don't have a specific asynchronous method to call, since this is all triggered by a series of didSet calls.
I could create a timePeriod in the repository, which would trigger the listOfObjects to be set in the ViewModel, but then I'd be missing out on the full flow of this. Is there a way to just have the test complete after a few seconds?
(Or is this a bad test since I'm relying on the system to do multiple things at once in order to pass the test?)
Here's the specific test (right now it won't do anything since there's nothing to fulfill the asynchronous wait)
func testSeasonObjectsVM_loadData() {
// given
let exp = expectation(description: "loading Data")
sut.timeLength = .quarter
waitForExpectations(timeout: 20)
// when
let count = sut.listOfObjects.count
// assert
XCTAssertEqual(count, 2)
}
You can fire a notification from the final place that you know the process / series of didSets has been completed like following.
public extension Notification.Name {
static let UserProfileViewModelListOfObjectsLoaded =
Notification.Name(rawValue: "UserProfileViewModelListOfObjectsLoaded")
}
// Your viewModel's final didSet
var listOfObjects: [Any] {
didSet {
NotificationCenter.default.post(name: .UserProfileViewModelListOfObjectsLoaded, object: nil)
}
}
// In your test
self.expectation(forNotification: .UserProfileViewModelListOfObjectsLoaded, object: nil) { (notification) -> Bool in
return (sut.listOfObjects.count == 2)
}
I have a class Complicated, where (it's not a real code):
class BeReadyInSomeTime {
var someData: SomeData
var whenDone: () -> Void
var isDone: Bool = false
var highRes: [LongCountedStuff] = []
init(data:SomeData, whenDone: #escaping () - >Void) {
self.someData = someData
self.whenDone = whenDone
... prepare `highRes` in background...
{ makeHighRes() }
... and when done set `isDone` to `true`, fire `whenDone()`
}
func reset(data:SomeData) {
self.someData = someData
self.isDone = false
self.highRes = []
... forget **immediately** about job from init or reset, start again
{ makeHighRes() }
... and when done set `isDone` to `true`, fire `whenDone()`
}
var highResolution:AnotherType {
if isDone {
return AnotherType(from: highRes)
} else {
return AnotherType(from: someData)
}
}
func makeHighRes() {
var result = [LongCountedStuff]
// prepare data, fast
let some intermediateResult = almost ()
self.highRes = result
}
func almost() -> [LongCountedStuff] {
if isNice {
return countStuff(self.someData)
} else {
return []
}
func countStuff(stuff:[LongCountedStuff], deep:Int = 0) -> [LongCountedSuff] {
if deep == deep enough {
return stuff
} else {
let newStuff = stuff.work
count(newStuff, deep: deep+1)
}
}
Making highRes array is a recurrent function which calls itself many times and sometimes it takes seconds, but I need feedback as fast as possible (and it will be one of someData elements, so I'm safe). As far I know, I can only 'flag' DispatchWorkItem that's cancelled. If I deliver new data by reset few times per second (form mouse drag) whole block is counted in background as many times as data was delivered. How to deal with this kind of problem? To really break counting highRes?
If you have a routine that is constantly calling another framework and you want to stop it at the end of one iteration and before it starts the next iteration, then wrapping this in an Operation and checking isCancelled is a good pattern. (You can also use GCD and DispatchWorkItem and use its isCancelled, too, but I find operations do this more elegantly.)
But if you’re saying you not only want to cancel your loop, but also hope to stop the consuming call within that framework, then, no, you can’t do that (unless the framework provides some cancelation mechanism of its own). But there is no preemptive cancellation. You can’t just stop a time consuming calculation unless you add checks inside that calculation to check to see if it has been canceled.
I’d also ask whether the recursive pattern is right here. Do you really need the results of one calculation in order to start the next? If so, then a recursive (or iterative) pattern is fine. But if the recursive operation is just to pass the next unit of work, then a non-recursive pattern might be better, because it opens up the possibility of doing calculations in parallel.
For example, you might create a concurrent queue with a maxConcurrencyCount of some reasonable value (e.g. 4 or 6). Then wrap each individual processing task in its own Operation subclass and have each check its respective isCancelled. Then you can just add all the operations up front, and let the queue handle it from there. And when you want to stop them, you can tell the queue to cancelAllOperations. It’s a relative simple pattern, allows you to do calculations in parallel, and is cancelable. But this obviously only works if a given operations is not strictly dependent upon the results of the prior operation(s).
I have a process which runs for a long time and which I would like the ability to interrupt.
func longProcess (shouldAbort: #escaping ()->Bool) {
// Runs a long loop and periodically checks shouldAbort(),
// returning early if shouldAbort() returns true
}
Here's my class which uses it:
class Example {
private var abortFlag: NSObject? = .init()
private var dispatchQueue: DispatchQueue = .init(label: "Example")
func startProcess () {
let shouldAbort: ()->Bool = { [weak abortFlag] in
return abortFlag == nil
}
dispatchQueue.async {
longProcess(shouldAbort: shouldAbort)
}
}
func abortProcess () {
self.abortFlag = nil
}
}
The shouldAbort closure captures a weak reference to abortFlag, and checks whether that reference points to nil or to an NSObject. Since the reference is weak, if the original NSObject is deallocated then the reference that is captured by the closure will suddenly be nil and the closure will start returning true. The closure will be called repeatedly during the longProcess function, which is occurring on the private dispatchQueue. The abortProcess method on the Example class will be externally called from some other queue. What if someone calls abortProcess(), thereby deallocating abortFlag, at the exact same time that longProcess is trying to perform the check to see if abortFlag has been deallocated yet? Is checking myWeakReference == nil a thread-safe operation?
You can create the dispatched task as a DispatchWorkItem, which has a thread-safe isCancelled property already. You can then dispatch that DispatchWorkItem to a queue and have it periodically check its isCancelled. You can then just cancel the dispatched as such point you want to stop it.
Alternatively, when trying to wrap some work in an object, we’d often use Operation, instead, which encapsulates the task in its own class quite nicely:
class SomeLongOperation: Operation {
override func main() {
// Runs a long loop and periodically checks `isCancelled`
while !isCancelled {
Thread.sleep(forTimeInterval: 0.1)
print("tick")
}
}
}
And to create queue and add the operation to that queue:
let queue = OperationQueue()
let operation = SomeLongOperation()
queue.addOperation(operation)
And to cancel the operation:
operation.cancel()
Or
queue.cancelAllOperations()
Bottom line, whether you use Operation (which is, frankly, the “go-to” solution for wrapping some task in its own object) or roll-your-own with DispatchWorkItem, the idea is the same, namely that you don’t need to have your own state property to detect cancellation of the task. Both dispatch queues and operation queues already have nice mechanisms to simplify this process for you.
I saw this bug (Weak properties are not thread safe when reading SR-192) indicating that weak reference reads weren't thread safe, but it has been fixed, which suggests that (absent any bugs in the runtime), weak reference reads are intended to be thread safe.
Also interesting: Friday Q&A 2017-09-22: Swift 4 Weak References by Mike Ash
I feel that I've always misunderstood that when reference cycles are created. Before I use to think that almost any where that you have a block and the compiler is forcing you to write .self then it's a sign that I'm creating a reference cycle and I need to use [weak self] in.
But the following setup doesn't create a reference cycle.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution
class UsingQueue {
var property : Int = 5
var queue : DispatchQueue? = DispatchQueue(label: "myQueue")
func enqueue3() {
print("enqueued")
queue?.asyncAfter(deadline: .now() + 3) {
print(self.property)
}
}
deinit {
print("UsingQueue deinited")
}
}
var u : UsingQueue? = UsingQueue()
u?.enqueue3()
u = nil
The block only retains self for 3 seconds. Then releases it. If I use async instead of asyncAfter then it's almost immediate.
From what I understand the setup here is:
self ---> queue
self <--- block
The queue is merely a shell/wrapper for the block. Which is why even if I nil the queue, the block will continue its execution. They’re independent.
So is there any setup that only uses queues and creates reference cycles?
From what I understand [weak self] is only to be used for reasons other than reference cycles ie to control the flow of the block. e.g.
Do you want to retain the object and run your block and then release it? A real scenario would be to finish this transaction even though the view has been removed from the screen...
Or you want to use [weak self] in so that you can exit early if your object has been deallocated. e.g. some purely UI like stopping a loading spinner is no longer needed
FWIW I understand that if I use a closure then things are different ie if I do:
import PlaygroundSupport
import Foundation
PlaygroundPage.current.needsIndefiniteExecution
class UsingClosure {
var property : Int = 5
var closure : (() -> Void)?
func closing() {
closure = {
print(self.property)
}
}
func execute() {
closure!()
}
func release() {
closure = nil
}
deinit {
print("UsingClosure deinited")
}
}
var cc : UsingClosure? = UsingClosure()
cc?.closing()
cc?.execute()
cc?.release() // Either this needs to be called or I need to use [weak self] for the closure otherwise there is a reference cycle
cc = nil
In the closure example the setup is more like:
self ----> block
self <--- block
Hence it's a reference cycle and doesn't deallocate unless I set block to capturing to nil.
EDIT:
class C {
var item: DispatchWorkItem!
var name: String = "Alpha"
func assignItem() {
item = DispatchWorkItem { // Oops!
print(self.name)
}
}
func execute() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: item)
}
deinit {
print("deinit hit!")
}
}
With the following code, I was able to create a leak ie in Xcode's memory graph I see a cycle, not a straight line. I get the purple indicators. I think this setup is very much like how a stored closure creates leaks. And this is different from your two examples, where execution is never finished. In this example execution is finished, but because of the references it remains in memory.
I think the reference is something like this:
┌─────────┐─────────────self.item──────────────▶┌────────┐
│ self │ │workItem│
└─────────┘◀︎────item = DispatchWorkItem {...}───└────────┘
You say:
From what I understand the setup here is:
self ---> queue
self <--- block
The queue is merely a shell/wrapper for the block. Which is why even if I nil the queue, the block will continue its execution. They’re independent.
The fact that self happens to have a strong reference to the queue is inconsequential. A better way of thinking about it is that a GCD, itself, keeps a reference to all dispatch queues on which there is anything queued. (It’s analogous to a custom URLSession instance that won’t be deallocated until all tasks on that session are done.)
So, GCD keeps reference to the queue with dispatched tasks. The queue keeps a strong reference to the dispatched blocks/items. The queued block keeps a strong reference to any reference types they capture. When the dispatched task finishes, it resolves any strong references to any captured reference types and is removed from the queue (unless you keep your own reference to it elsewhere.), generally thereby resolving any strong reference cycles.
Setting that aside, where the absence of [weak self] can get you into trouble is where GCD keeps a reference to the block for some reason, such as dispatch sources. The classic example is the repeating timer:
class Ticker {
private var timer: DispatchSourceTimer?
func startTicker() {
let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".ticker")
timer = DispatchSource.makeTimerSource(queue: queue)
timer!.schedule(deadline: .now(), repeating: 1)
timer!.setEventHandler { // whoops; missing `[weak self]`
self.tick()
}
timer!.resume()
}
func tick() { ... }
}
Even if the view controller in which I started the above timer is dismissed, GCD keeps firing this timer and Ticker won’t be released. As the “Debug Memory Graph” feature shows, the block, created in the startTicker routine, is keeping a persistent strong reference to the Ticker object:
This is obviously resolved if I use [weak self] in that block used as the event handler for the timer scheduled on that dispatch queue.
Other scenarios include a slow (or indefinite length) dispatched task, where you want to cancel it (e.g., in the deinit):
class Calculator {
private var item: DispatchWorkItem!
deinit {
item?.cancel()
item = nil
}
func startCalculation() {
let queue = DispatchQueue(label: Bundle.main.bundleIdentifier! + ".calcs")
item = DispatchWorkItem { // whoops; missing `[weak self]`
while true {
if self.item?.isCancelled ?? true { break }
self.calculateNextDataPoint()
}
self.item = nil
}
queue.async(execute: item)
}
func calculateNextDataPoint() {
// some intense calculation here
}
}
All of that having been said, in the vast majority of GCD use-cases, the choice of [weak self] is not one of strong reference cycles, but rather merely whether we mind if strong reference to self persists until the task is done or not.
If we’re just going to update the the UI when the task is done, there’s no need to keep the view controller and its views in the hierarchy waiting some UI update if the view controller has been dismissed.
If we need to update the data store when the task is done, then we definitely don’t want to use [weak self] if we want to make sure that update happens.
Frequently, the dispatched tasks aren’t consequential enough to worry about the lifespan of self. For example, you might have a URLSession completion handler dispatch UI update back to the main queue when the request is done. Sure, we theoretically would want [weak self] (as there’s no reason to keep the view hierarchy around for a view controller that’s been dismissed), but then again that adds noise to our code, often with little material benefit.
Unrelated, but playgrounds are a horrible place to test memory behavior because they have their own idiosyncrasies. It’s much better to do it in an actual app. Plus, in an actual app, you then have the “Debug Memory Graph” feature where you can see the actual strong references. See https://stackoverflow.com/a/30993476/1271826.
I am writing unit tests for my class. This class preserves its state in some private variables (which I don't want to expose publicly). So the scenario is:
If I call a method, the first time it will keep that state in private properties and call a delegate method with some result.
When I call the same method a second time, the output will be different on the basis of the previous input.
I want to cover all the cases in my tests.
One easy way is to change my private properties to public so that I can mock the previous input in unit test.
The other way is to call the same method with different inputs in the same test twice. Where the first call will keep the state and the next call will be the actual test.
But both these ways seem awkward to me, and I am not sure of the best one.
What is the best way to write unit test for this class?
protocol ZoneUpdateDetectorOutput: class {
func updateZoneState(_ state: ZoneState)
}
class ZoneUpdateDetector {
var zoneChangeTimer: TimerProtocol?
weak var delegate: ZoneUpdateDetectorOutput?
private var previousZoneState: ZoneState?
private var expectedZoneState: ZoneState?
private func updateZoneState() {
// If `expectedZoneState` is not equal to `previousZoneState` then `delegate` will be called
// Otherwise it will just skip
if expectedZoneState != previousZoneState {
delegate?.updateZoneState(expectedZoneState!)
previousZoneState = expectedZoneState
}
}
private func runNotifyZoneStateTimer() {
guard zoneChangeTimer?.isValid() == false else {
return
}
zoneChangeTimer?.start(timeInterval: 5,
onFire: { [weak self] in
guard let strongSelf = self else {
return
}
// On timer fire, it will try to update the state
strongSelf.updateZoneState()
})
}
// When zone changes, this method is invoked
// I basically want to test this method
func zoneStateChanged(_ state: ZoneState) {
expectedZoneState = state
if state != .inZone {
runNotifyZoneStateTimer()
} else {
zoneChangeTimer?.stop()
}
}
}
You should never be testing internal state; you should only test externally (publically) visible behaviour. That way, you can change implementation details of your class without breaking any contracts, and thus without breaking any tests.
So the second option is the preferred one.
After researching and discussing with some experts, I come up with the solution that if we want to test a class which preserve it's state then the functionality which is preserving the state should go under a separate class. Which will serve the same purpose as setting the variables as private. So, ZoneUpdateDetector should have a dependency for example: ZoneUpdateStatePreserver and it should keep the state which was previously inside ZoneUpdateDetector