How can I tell if my timer is staying on schedule? - ios

I understand it is reentrant and will not overrun itself, but I need to know if it's getting bogged down.
init() {
checkMoveTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: true, block: { _ in
self.timeToMoveGroundTroups()
})
}
func timeToMoveGroundTroups() {
if gamePaused {
return
}
for (_, vCache) in data.groundActive {
data.groundObjects[vCache.index].next()
}
}

Save off the timestamp on every call to your action (timeToMoveGroundTroups) into an instance property and (before you do so) compare the current timestamp with that. If the difference is too great, you can take action of some sort (log, fatalError, whatever).
Another approach would be to take advantage of the new os_signpost logging to graph what's happening in Instruments.
Two additional comments on the code you showed:
Your timer will actually behave better if you provide a tolerance, typically about ten percent of the interval
You have a retain cycle that's going to cause memory issues down the line; self needs to be declared unowned in your anonymous function

if !checkMoveTimer.valid {
//TODO:
}
If I understood you correctly.

Related

async/await, Task and [weak self]

Okay so we all know that in traditional concurrency in Swift, if you are performing (for example) a network request inside a class, and in the completion of that request you reference a function that belongs to that class, you must pass [weak self] in, like this:
func performRequest() {
apiClient.performRequest { [weak self] result in
self?.handleResult(result)
}
}
This is to stop us strongly capturing self in the closure and causing unnecessary retention/inadvertently referencing other entities that have dropped out of memory already.
How about in async/await? I'm seeing conflicting things online so I'm just going to post two examples to the community and see what you think about both:
class AsyncClass {
func function1() async {
let result = await performNetworkRequestAsync()
self.printSomething()
}
func function2() {
Task { [weak self] in
let result = await performNetworkRequestAsync()
self?.printSomething()
}
}
func function3() {
apiClient.performRequest { [weak self] result in
self?.printSomething()
}
}
func printSomething() {
print("Something")
}
}
function3 is straightforward - old fashioned concurrency means using [weak self].
function2 I think is right, because we're still capturing things in a closure so we should use [weak self].
function1 is this just handled by Swift, or should I be doing something special here?
Bottom line, there is often little point in using [weak self] capture lists with Task objects. Use cancelation patterns instead.
A few detailed considerations:
Weak capture lists are not required.
You said:
in traditional concurrency in Swift, if you are performing (for example) a network request inside a class, and in the completion of that request you reference a function that belongs to that class, you must pass [weak self] …
This is not true. Yes, it may be prudent or advisable to use the [weak self] capture list, but it is not required. The only time you “must” use a weak reference to self is when there is a persistent strong reference cycle.
For well-written asynchronous patterns (where the called routine releases the closure as soon as it is done with it), there is no persistent strong reference cycle risk. The [weak self] is not required.
Nonetheless, weak capture lists are useful.
Using [weak self] in these traditional escaping closure patterns still has utility. Specifically, in the absence of the weak reference to self, the closure will keep a strong reference to self until the asynchronous process finishes.
A common example is when you initiate a network request to show some information in a scene. If you dismiss the scene while some asynchronous network request is in progress, there is no point in keeping the view controller in memory, waiting for a network request that merely updates the associated views that are long gone.
Needless to say, the weak reference to self is really only part of the solution. If there’s no point in retaining self to wait for the result of the asynchronous call, there is often no point in having the asynchronous call continue, either. E.g., we might marry a weak reference to self with a deinit that cancels the pending asynchronous process.
Weak capture lists are less useful in Swift concurrency.
Consider this permutation of your function2:
func function2() {
Task { [weak self] in
let result = await apiClient.performNetworkRequestAsync()
self?.printSomething()
}
}
This looks like it should not keep a strong reference to self while performNetworkRequestAsync is in progress. But the reference to a property, apiClient, will introduce a strong reference, without any warning or error message. E.g., below, I let AsyncClass fall out of scope at the red signpost, but despite the [weak self] capture list, it was not released until the asynchronous process finished:
The [weak self] capture list accomplishes very little in this case. Remember that in Swift concurrency there is a lot going on behind the scenes (e.g., code after the “suspension point” is a “continuation”, etc.). It is not the same as a simple GCD dispatch. See Swift concurrency: Behind the scenes.
If, however, you make all property references weak, too, then it will work as expected:
func function2() {
Task { [weak self] in
let result = await self?.apiClient.performNetworkRequestAsync()
self?.printSomething()
}
}
Hopefully, future compiler versions will warn us of this hidden strong reference to self.
Make tasks cancelable.
Rather than worrying about whether you should use weak reference to self, one could consider simply supporting cancelation:
var task: Task<Void, Never>?
func function2() {
task = Task {
let result = await apiClient.performNetworkRequestAsync()
printSomething()
task = nil
}
}
And then,
#IBAction func didTapDismiss(_ sender: Any) {
task?.cancel()
dismiss(animated: true)
}
Now, obviously, that assumes that your task supports cancelation. Most of the Apple async API does. (But if you have written your own withUnsafeContinuation-style implementation, then you will want to periodically check Task.isCancelled or wrap your call in a withTaskCancellationHandler or other similar mechanism to add cancelation support. But this is beyond the scope of this question.)
if you are performing (for example) a network request inside a class, and in the completion of that request you reference a function that belongs to that class, you must pass [weak self] in, like this
This isn't quite true. When you create a closure in Swift, the variables that the closure references, or "closes over", are retained by default, to ensure that those objects are valid to use when the closure is called. This includes self, when self is referenced inside of the closure.
The typical retain cycle that you want to avoid requires two things:
The closure retains self, and
self retains the closure back
The retain cycle happens if self holds on to the closure strongly, and the closure holds on to self strongly — by default ARC rules with no further intervention, neither object can be released (because something has retained it), so the memory will never be freed.
There are two ways to break this cycle:
Explicitly break a link between the closure and self when you're done calling the closure, e.g. if self.action is a closure which references self, assign nil to self.action once it's called, e.g.
self.action = { /* Strongly retaining `self`! */
self.doSomething()
// Explicitly break up the cycle.
self.action = nil
}
This isn't usually applicable because it makes self.action one-shot, and you also have a retain cycle until you call self.action(). Alternatively,
Have either object not retain the other. Typically, this is done by deciding which object is the owner of the other in a parent-child relationship, and typically, self ends up retaining the closure strongly, while the closure references self weakly via weak self, to avoid retaining it
These rules are true regardless of what self is, and what the closure does: whether network calls, animation callbacks, etc.
With your original code, you only actually have a retain cycle if apiClient is a member of self, and holds on to the closure for the duration of the network request:
func performRequest() {
apiClient.performRequest { [weak self] result in
self?.handleResult(result)
}
}
If the closure is actually dispatched elsewhere (e.g., apiClient does not retain the closure directly), then you don't actually need [weak self], because there was never a cycle to begin with!
The rules are exactly the same with Swift concurrency and Task:
The closure you pass into a Task to initialize it with retains the objects it references by default (unless you use [weak ...])
Task holds on to the closure for the duration of the task (i.e., while it's executing)
You will have a retain cycle if self holds on to the Task for the duration of the execution
In the case of function2(), the Task is spun up and dispatched asynchronously, but self does not hold on to the resulting Task object, which means that there's no need for [weak self]. If instead, function2() stored the created Task, then you would have a potential retain cycle which you'd need to break up:
class AsyncClass {
var runningTask: Task?
func function4() {
// We retain `runningTask` by default.
runningTask = Task {
// Oops, the closure retains `self`!
self.printSomething()
}
}
}
If you need to hold on to the task (e.g. so you can cancel it), you'll want to avoid having the task retain self back (Task { [weak self] ... }).

Collecting stored variable property using withLatestFrom

I'm wondering if there is a way in RxSwift to observe value of stored variable property. Eg. in following example:
var updatedValue: Int = 0
var observedValue: Observable<Int> {
return Observable.create({ (observer) -> Disposable in
observer.onNext(updatedValue)
return Disposables.create()
})
}
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
updatedValue = updatedValue + 1;
}
let myObservable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.publish()
myObservable.connect()
myObservable
.withLatestFrom(observedValue)
.subscribe { (event) in
print(event)
}
We have variable property updatedValue and hot observable myObservable. We also increment value of updatedValue in Timer.scheduledTimer....
Flow here is pretty straight forward. When we subscribe, observedValue gets called, we get onNext from observedValue and then Disposables.create(). Then we print event onNext(0).
As myObservable is based on Observable.interval, same withLatestFrom value gets printed in onNext every second.
Question: Is there a way to print last value of updatedValue every time myObservable emits new event? So instead of 0,0,0... we get 0,1,2...
I'm aware that updatedValue could be declared as BehaviorRelay.
I'm also aware that we could use .map { } to capture self.updatedValue.
But I'm wondering if there is any way to create a Observable wrapper around standard variable property so it calls onNext with most recent value every time trigger sequence sends an event? Without capturing self or changing declaration on updatedValue.
Thanks for any comments and ideas!
RxCocoa has a handy wrapper around KVO. You should be able to use it from .rx extension on NSObject subclasses.
For your issue, I guess you can do something like:
let updatedValueObservable = self.rx.observe(Int.self, "updatedValue")
But I'm wondering if there is any way to create a Observable wrapper around standard variable property so it calls onNext with most recent value every time trigger sequence sends an event? Without capturing self or changing declaration on updatedValue.
The correct answer is, no. There is no way to do anything to updatedValue without involving self. One way of doing it would be with Observable<Int>.interval(1, scheduler: MainScheduler.instance).compactMap { [weak self] _ in self?.updatedValue }.distinctUntilChanged() (Your use of publish and connect is odd and unnecessary,) but that involves self.
Since your property is a value type, the only way to access it is through self, even if Rx wasn't involved at all.

If variable is not set, wait for variable to be set

I have 2 delegate methods that are being called by notifications from a 3rd party library.
Method 1:
mediaContentWasUpdated()
Method 2:
adMediaDidBeginPlaying()
In Method 1, a key variable (adDuration) is set from a parameter that is passed in with the notification. As far as I can see this is the only place to get this information.
In Method 2, we check the adDuration and if it is greater than 0 then we update the UI to reflect that we are in fact play an ad.
A bug has appeared where sometimes these two methods are called in the wrong order. Meaning the adDuration is not set and Method 2 thinks there is no ad media to be played and does not update the UI accordingly.
My current attempt at a solution is to make adDuration optional and use an NSCondition to cause Method 2 to wait for Method 1 to set adDuration and then proceed.
var adDuration : Double?
let condition = NSCondition()
func mediaContentWasUpdated(notification: NSNotificiation) {
condition.lock()
if(notificationHasAdDurationInfo(notification)) {
self.adDuration = getAdDuration(notification)
condition.signal()
}
condition.unlock()
}
func adMediaDidBeginPlaying(notification: NSNotification) {
condition.lock()
while adDuration == nil {
condition.wait()
}
if adDuration! > Double(0) {
updateUIForAd()
}
condition.unlock()
}
This is my first time trying something like this and I worry I am doing something wrong. I also have some concerns about locking and unlocking threads needlessly (which would happen in a well timed run, or if there were no ad content to be played).
Outside factors are hindering my ability to test and I wanted to get some input to see if I am heading in the right direction while I wait for those issues to be resolved.
Your discussion of NSCondition got me on the same track with you, and I built two or three solutions using DispatchGroup (which is the better tool for this), but they always had little corner cases that could behave badly, and didn't really capture the intent.
(If you're interested in the DispatchGroup solutions, they're of the form: call .enter() in init, call .leave() when the duration comes in, call notify() when the playing starts. It works fine, but it introduces corner cases that can crash, just like NSCondition.)
Getting back to the real intent:
Update the UI when the duration is known and the ad has started playing.
There's no concurrency going on here. So pulling out GCD is not just overkill; it actually makes things worse because it introduces lots of complicated corner cases.
So I thought about how I'd have solved this back before GCD. And the answer is obvious: just check if you have the data you want, and then do the thing. (Reading through the comments, I see Paulw11 pointed this out as well.)
Personally I like to pull this kind of thing into its own type to make things more self-contained. I hate some of the names here, but the idea should be clear:
class AdPlayer {
private var readyToPlay = false
private var duration: Double = 0.0
private let completion: (Double) -> Void
func setDuration(from notification: Notification) {
if(notificationHasAdDurationInfo(notification)) {
duration = getAdDuration(notification)
}
playIfReady()
}
func play() {
readyToPlay = true
playIfReady()
}
private func playIfReady() {
if duration > 0 && readyToPlay {
completion(duration)
}
}
init(completion: #escaping (Double) -> Void) {
self.completion = completion
}
}
When you set each thing, see if you're ready to update, and if so, update. I've gotten rid of the optional as well, since I believe the intent is "0 duration is always wrong." But you could use an Optional so you could detect actually receiving a 0 from the notification.
With that, you just set up a player property:
player = AdPlayer(completion: updateUIForAd)
(Note that the above might be creating a retain loop, depending on what updateUIForAd is; you may need a [weak self] closure or the like here.)
And then update it as needed:
func mediaContentWasUpdated(notification: NSNotificiation) {
player.setDuration(from: notification)
}
func adMediaDidBeginPlaying(notification: NSNotification) {
player.play()
}
A big advantage of creating the AdPlayer type is that it's easy to reset the system when the ad is done (or if something goes wrong). Just throw away the whole object and create another one.

Concern about memory when choosing between notification vs callback closure for network calls?

Many posts seem to advise against notifications when trying to synchronize functions, but there are also other posts which caution against closure callbacks because of the potential to inadvertently retain objects and cause memory issues.
Assume inside a custom view controller is a function, foo, that uses the Bar class to get data from the server.
class CustomViewController : UIViewController {
function foo() {
// Do other stuff
// Use Bar to get data from server
Bar.getServerData()
}
}
Option 1: Define getServerData to accept a callback. Define the callback as a closure inside CustomViewController.
Option 2: Use NSNotifications instead of a callback. Inside of getServerData, post a NSNotification when the server returns data, and ensure CustomViewController is registered for the notification.
Option 1 seems desirable for all the reasons people caution against NSNotification (e.g., compiler checks, traceability), but doesn't using a callback create a potential issue where CustomViewController is unnecessarily retained and therefore potentially creating memory issues?
If so, is the right way to mitigate the risk by using a callback, but not using a closure? In other words, define a function inside CustomViewController with a signature matching the getServerData callback, and pass the pointer to this function to getServerData?
I'm always going with Option 1 you just need to remember of using [weak self] or whatever you need to 'weakify' in order to avoid memory problems.
Real world example:
filterRepository.getFiltersForType(filterType) { [weak self] (categories) in
guard let strongSelf = self, categories = categories else { return }
strongSelf.dataSource = categories
strongSelf.filteredDataSource = strongSelf.dataSource
strongSelf.tableView?.reloadData()
}
So in this example you can see that I pass reference to self to the completion closure, but as weak reference. Then I'm checking if the object still exists - if it wasn't released already, using guard statement and unwrapping weak value.
Definition of network call with completion closure:
class func getFiltersForType(type: FilterType, callback: ([FilterCategory]?) -> ()) {
connection.getFiltersCategories(type.id).response { (json, error) in
if let data = json {
callback(data.arrayValue.map { FilterCategory(attributes: $0) } )
} else {
callback(nil)
}
}
}
I'm standing for closures in that case. To avoid unnecessary retains you just need to ensure closure has proper capture list defined.

What is difference between self.timer = nil vs [self.timer invalidate] in iOS?

Can anyone explain me self.timer=nil vs [self.timer invalidate]?
What exactly happens at the memory location of self.timer?
In my code
self.timer=nil
doesn't stops the timer but
[self.timer invalidate]
stops the timer.
If you require my code I will update that too.
Once you have no need to run timer, invalidate timer object, after that no need to nullify its reference.
This is what Apple documentation says: NSTimer
Once scheduled on a run loop, the timer fires at the specified
interval until it is invalidated. A non-repeating timer invalidates
itself immediately after it fires. However, for a repeating timer, you
must invalidate the timer object yourself by calling its invalidate
method. Calling this method requests the removal of the timer from the
current run loop; as a result, you should always call the invalidate
method from the same thread on which the timer was installed.
Invalidating the timer immediately disables it so that it no longer
affects the run loop. The run loop then removes the timer (and the
strong reference it had to the timer), either just before the
invalidate method returns or at some later point. Once invalidated,
timer objects cannot be reused.
There is a key difference not mentioned in the other answers.
To test this, drop the following code in Playground.
1st Attempt:
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
class Person{
var age = 0
lazy var timer: Timer? = {
let _timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
return _timer
}()
init(age: Int) {
self.age = age
}
#objc func fireTimer(){
age += 1
print("age: \(age)")
}
deinit {
print("person was deallocated")
}
}
// attempt:
var person : Person? = Person(age: 0)
let _ = person?.timer
person = nil
So let me ask you a question. At the last line of the code, I just set person to nil. That means the person object is deallocated and all its properties are set to nil and removed from memory. Right?
An object is deallocated as long as no other object is holding a strong a reference to it. In our case the timer is still holding a strong reference to person, because the run-loop has a strong reference to the timer§ hence the person object will not get deallocated.
The result of the above code is that it still continues to execute!
Let's fix it.
2nd Attempt:
Let's set the timer to nil. This should remove the strong reference of timer pointing to person.
var person : Person? = Person(age: 0)
let _ = person?.timer
person?.timer = nil
person = nil
WRONG! We only removed our pointer to the timer. Yet the result of the above code is just like our initial attempt. It still continues to execute...because the run loop is still targeting/referencing self.
So what do we need to do?
Glad you asked. We must invalidate the timer!
3rd Attempt:
var person : Person? = Person(age: 0)
let _ = person?.timer
person?.timer = nil
person?.timer?.invalidate()
person = nil
This looks better, but it's still wrong. Can you guess why?
I'll give you a hint. See code below 👇.
4th Attempt (correct)
var person : Person? = Person(age: 0)
let _ = person?.timer
person?.timer?.invalidate()
person?.timer = nil
person = nil
// person was deallocated
Our 4th attempt was just like our 3rd attempt, just that the sequence of code was different.
person?.timer?.invalidate() removes the run loop's strong reference
to its target, i.e. self, and now if a pointer to person is removed...our person object gets deallocated!
The attempt below is also correct:
5th Attempt (correct)
var person : Person? = Person(age: 0)
let _ = person?.timer
person?.timer?.invalidate()
person = nil
// person was deallocated
Notice that in our 5th attempt we didn't set the timer to nil. But Apple recommends that we do such:
Once invalidated, timer objects cannot be reused.
See Task Management - Timer
Setting it to nil is also an indicator that for other parts of code. It helps up so that we can check against it and if it wasn't nil then we'd know the timer is still valid and also to not have a meaningless object around.
After invalidating the timer you should assign nil to the variable
otherwise the variable is left pointing to a useless timer. Memory
management and ARC have nothing to do with why you should set it to
nil. After invalidating the timer, self.timer is now referencing a
useless timer. No further attempts should be made to use that value. Setting it to nil ensures that any further attempts to access
self.timer will result in nil
from rmaddy's comment above
That being said I think isValid is a more meaningful approach just as isEmpty is more meaningful and efficient than doing array.count == 0...
So why is 3rd attempt not correct?
Because we need a pointer to the timer so we can invalidate it. If we set that pointer to nil then we loose our pointer to it. We lose it while the run-loop has still maintained its pointer to it! So if we ever wanted to turn off the timer we should invalidate it BEFORE we lose our reference to it (ie before we set its pointer to nil) otherwise it becomes an abandoned memory (not leak).
Conclusion:
To get stop a timer correctly you must use invalidate. Do not nil the timer before you invalidate it.
After you've invalidated a timer, set it to nil so it doesn't get reused.
Calling invalidate will remove the run loop's pointer to self. Only then the object containing the timer will be released.
So how does this apply when I'm actually building an application?
If your viewController has person property and then your popped this viewController off your navigation stack then your viewController will get deallocated. In its deinit method you must invalidate the person's timer. Otherwise your person instance is kept in memory because of the run loop and its timer action will still want to execute! This can lead to a crash!
Correction:
Thanks to Rob's answer
If you're dealing with repeating [NS]Timers, don't try to invalidate them in dealloc of the owner of the [NS]Timer because the dealloc obviously will not be called until the strong reference cycle is resolved. In the case of a UIViewController, for example, you might do it in viewDidDisappear
That being said viewDidDisappear may not always be the correct place since viewDidDisappear also gets called if you just push a new viewController on top of it. You should basically do it from a point that it's no longer needed. You get the idea...
§: Because the run loop maintains the timer, from the perspective of
object lifetimes there’s typically no need to keep a reference to a
timer after you’ve scheduled it. (Because the timer is passed as an
argument when you specify its method as a selector, you can invalidate
a repeating timer when appropriate within that method.) In many
situations, however, you also want the option of invalidating the
timer—perhaps even before it starts. In this case, you do need to
keep a reference to the timer, so that you can stop it whenever
appropriate.
With all the credit going to my colleague Brandon:
Pro Tip:
Even if you don't have a repeating timer, the Runloop [as mentioned within the docs] will hold a strong reference to your target if you use the selector function, until it fires, after that it will release it.
However if you use the block based function then as long as you point weakly to self inside your block then the runloop will not retain self. However it will continue to execute, due to the lack of calling invalidate
If you don't use [weak self] then the block based will act just like the selector kind, that it will deallocate self after it has been fired.
Paste the following code in Playground and see the difference. The selector version will be deallocated after it fires. The block base will be deallocated upon deallocation. Basically the lifecycle of one is governed by the runloop while for the other it's governed by the object itself
#objc class MyClass: NSObject {
var timer: Timer?
func startSelectorTimer() {
timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(MyClass.doThing), userInfo: nil, repeats: false)
}
func startBlockTimer() {
timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: false, block: { [weak self] _ in
self?.doThing()
})
}
#objc func doThing() {
print("Ran timer")
}
deinit {
print("My Class deinited")
}
}
var mySelectorClass: MyClass? = MyClass()
mySelectorClass?.startSelectorTimer()
mySelectorClass = nil // Notice that MyClass.deinit is not called until after Ran Timer happens
print("Should have deinited Selector timer here")
RunLoop.current.run(until: Date().addingTimeInterval(7))
print("---- NEW TEST ----")
var myBlockClass: MyClass? = MyClass()
myBlockClass?.startBlockTimer()
myBlockClass = nil // Notice that MyClass.deinit IS called before the timer finishes. No need for invalidation
print("Should have deinited Block timer here")
RunLoop.current.run(until: Date().addingTimeInterval(7))
First of all, invalidate is a method of NSTimer class which can use to stop currently running timer. Where when you assign nil to any object then, in an ARC environment the variable will release the object.
Its important to stop running timer when you don't longer need, so we write [timer invalidate] and then we write timer = nil; to make sure it'll loose its address from memory and later time you can recreate the timer.

Resources