Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/DotLottie/Public/DotLottie.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
import Foundation

protocol DotLottie {
var dotLottieViewModel: DotLottieAnimation { get set }
var dotLottieViewModel: DotLottieAnimation { get }
}
22 changes: 18 additions & 4 deletions Sources/DotLottie/Public/DotLottieAnimationView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ public class DotLottieAnimationView: UIView, DotLottie {

super.init(frame: .zero)

dotLottieViewModel.$framerate.sink { value in
if self.mtkView != nil {
self.mtkView.preferredFramesPerSecond = dotLottieViewModel.framerate
dotLottieViewModel.$framerate.sink { [weak self] value in
if let self, mtkView != nil {
mtkView.preferredFramesPerSecond = dotLottieViewModel.framerate
}
}.store(in: &cancellableBag)

Expand All @@ -38,7 +38,7 @@ public class DotLottieAnimationView: UIView, DotLottie {
private func setupMetalView() {
mtkView = MTKView(frame: bounds)

self.coordinator = Coordinator(self, mtkView: mtkView)
self.coordinator = Coordinator(WeakWrapper(self), mtkView: mtkView)

if let metalDevice = MTLCreateSystemDefaultDevice() {
mtkView.device = metalDevice
Expand Down Expand Up @@ -72,6 +72,20 @@ public class DotLottieAnimationView: UIView, DotLottie {
public func subscribe(observer: Observer) {
self.dotLottieViewModel.subscribe(observer: observer)
}

private class WeakWrapper: DotLottie {
var dotLottieViewModel: DotLottieAnimation {
view?.dotLottieViewModel ?? initialDotLottieViewModel
}

private weak var view: DotLottieAnimationView?
private var initialDotLottieViewModel: DotLottieAnimation

init(_ view: DotLottieAnimationView) {
self.view = view
self.initialDotLottieViewModel = view.dotLottieViewModel
}
}
}

#endif
11 changes: 6 additions & 5 deletions Tests/DotLottieTests/DotLottieTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import XCTest
@testable import DotLottie

final class DotLottieTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
// XCTAssertEqual(DotLottie().text, "Hello, World!")
func testAnimationViewMemoryLeak() throws {
weak var view: DotLottieAnimationView? = testAnimation.view()
XCTAssertNil(view)
}
}

/// https://lottiefiles.com/free-animation/swipe-left-arrows-nIIJhfaFd3
let testAnimation = DotLottieAnimation(animationData: #"{"v":"5.5.9","fr":60,"ip":0,"op":151,"w":500,"h":500,"nm":"scroll_up 2","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[250,468,0],"to":[0,-36.333,0],"ti":[0,36.333,0]},{"t":79,"s":[250,250,0]}],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Path 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":62,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":108,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":126,"s":[100]},{"t":143,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":48,"s":[243.769,343.23,0],"to":[0,-11.5,0],"ti":[0,11.5,0]},{"t":99,"s":[243.769,274.23,0]}],"ix":2},"a":{"a":0,"k":[63.846,26.538,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[0,53.077],[65.384,0],[100.697,30.081],[127.692,53.077]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":18,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Path 1","parent":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":32,"s":[0]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":92,"s":[100]},{"i":{"x":[0.833],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":117,"s":[100]},{"t":132,"s":[1]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-5.231,-51.77,0],"ix":2},"a":{"a":0,"k":[63.846,26.538,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[0,53.077],[65.384,0],[100.697,30.081],[127.692,53.077]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":18,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Path 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":3600,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"scroll_up","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[249,250,0],"ix":2},"a":{"a":0,"k":[250,250,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"w":500,"h":500,"ip":0,"op":3600,"st":0,"bm":0}],"markers":[]}"#, config: .init())