Correct Handling/Cleanup/Etc of Cadisplaylink in Swift Custom Animation

Correct handling / cleanup / etc of CADisplayLink in Swift custom animation?

Here’s a simple example showing how I’d go about implementing a CADisplayLink (in Swift 5):

class C { /// your view class or whatever

private var displayLink: CADisplayLink?
private var startTime = 0.0
private let animationLength = 5.0

func startDisplayLink() {

stopDisplayLink() /// make sure to stop a previous running display link
startTime = CACurrentMediaTime() // reset start time

/// create displayLink and add it to the run-loop
let displayLink = CADisplayLink(target: self, selector: #selector(displayLinkDidFire))
displayLink.add(to: .main, forMode: .common)
self.displayLink = displayLink
}

@objc func displayLinkDidFire(_ displayLink: CADisplayLink) {

var elapsedTime = CACurrentMediaTime() - startTime

if elapsedTime > animationLength {
stopDisplayLink()
elapsedTime = animationLength /// clamp the elapsed time to the animation length
}

/// do your animation logic here
}

/// invalidate display link if it's non-nil, then set to nil
func stopDisplayLink() {
displayLink?.invalidate()
displayLink = nil
}
}

Points to note:

  • We’re using nil here to represent the state in which the display link isn’t running – as there’s no easy way of getting this information from an invalidated display link.
  • Instead of using removeFromRunLoop(), we’re using invalidate(), which will not crash if the display link hasn’t already been added to a run-loop. However this situation should never arise in the first place – as we’re always immediately adding the display link to the run-loop after creating it.
  • We’ve made the displayLink private in order to prevent outside classes from putting it in an unexpected state (e.g invalidating it but not setting it to nil).
  • We have a single stopDisplayLink() method that both invalidates the display link (if it is non-nil) and sets it to nil – rather than copy and pasting this logic.
  • We’re not setting paused to true before invalidating the display link, as this is redundant.
  • Instead of force unwrapping the displayLink after checking for non-nil, we’re using optional chaining e.g displayLink?.invalidate() (which will call invalidate() if the display link isn’t nil). While force unwrapping may be ‘safe’ in your given situation (as you’re checking for nil) – it’s potentially unsafe when it comes to future refactoring, as you may re-structure your logic without considering what impact this has on the force unwraps.
  • We’re clamping the elapsed time to the animation duration in order to ensure that the later animation logic doesn’t produce a value out of the expected range.
  • Our update method displayLinkDidFire(_:) takes a single argument of type CADisplayLink, as required by the documentation.

How to set CADisplayLink in Swift with weak reference between target and CADisplayLink instance

An better approach might be to invalidate the display link in
viewWill/DidDisappear, see also

  • Correct handling / cleanup / etc of CADisplayLink in Swift custom animation?

for useful information.

If that is not an option: Make the proxy object inherit from NSObject
instead of NSProxy. An Objective-C solution is for example
given here

  • CADisplayLink at iOS 6.0 not retaining target

and that can easily be translated to Swift 3:

class JAWeakProxy: NSObject {
weak var target: NSObjectProtocol?

init(target: NSObjectProtocol) {
self.target = target
super.init()
}

override func responds(to aSelector: Selector!) -> Bool {
return (target?.responds(to: aSelector) ?? false) || super.responds(to: aSelector)
}

override func forwardingTarget(for aSelector: Selector!) -> Any? {
return target
}
}

which can then be used as

displayLink = CADisplayLink(target: JAWeakProxy(target: self),
selector: #selector(didRefresh(dpLink:)))

Your approach

weak var weakSelf = self    
displayLink = CADisplayLink(target: weakSelf!, selector: #selector(displayDidRefresh(dpLink:)))

does not work because it unwraps weakSelf when the CADisplayLink
is initialized and passes a strong reference to self as the target.

Change the speed of setContentOffset:animated:?

There is no a direct way of doing this, nor doing the way you wrote it. The only way I can accomplish this is by making the movement/animation by my own.

For example move 1px every 1/10 second should simulate a very slow scroll animation. (Since its a linear animation maths are very easy!)

If you want to get more realistic or fancy and simulate easy-in easy-off effect then you need some maths to calculate a bezier path so you can know the exact position at every 1/10 second, for example

At least the first approach shouldn't be that difficult.
Just use or -performSelector:withObject:afterDelay or NSTimerswith

-[UIScrollView setContentOffset:(CGPoint*)];`

Hope it helps

.net 3.5SP1 on a .net 3.0 Server - Is it possible to use the /bin Folder in ASP.net?

I'm pretty sure you can't do this, but googling on the following blogs may get you the definitive answer:

ScottGu
ScottHa
BradA

The problems would be, I think:

You want to load system.dll. Where does it look? does the GAC take precidence? (I think it does), therefore you get 2.0. So you have system.dll v2.0, and you try to use a DLL (eg system.web.mvc) which is bound to system.dll v3.5, but is only in you /bin.... it should explode loudly, not having the same contracts and the like.

Personally, I wouldn't try it, especially on production. But if you can take the site down for a while, give it a go. Worst case, you have to delete the files and re-upload the old site.

YMMV :)

Find two consecutive rows

Assuming the rows have sequential IDs, something like this may be what you're looking for:

select top 1 * 
from
Bills b1
inner join Bills b2 on b1.id = b2.id - 1
where
b1.IsEstimate = 1 and b2.IsEstimate = 1
order by
b1.BillDate desc


Related Topics



Leave a reply



Submit