Apple Developer Documentation

애니메이션 repeat 처리

private func addIdleAnimation(_ reversed: Bool = false, view: UIView, move: CGFloat) {
    animator = UIViewPropertyAnimator(duration: 2.0, curve: .linear)
    animator?.addAnimations {
        let centerY = view.center.y
        view.center.y = centerY - CGFloat(move)
    } 
    animator?.addCompletion({ _ in
        self.addIdleAnimation(!reversed, view: view, move: -move)
    })
    animator?.startAnimation(afterDelay: Double.random(in: 0.0...1.5))
}

옵션이 안먹혀서 컴플릿트 핸들러에 저렇게 추가를 했더니, CPU를 100퍼센트, 에너지 임팩트 High로 잡아먹어서 수정이 필요. 이렇게 접근하면 안되나봄. 이게 그 콜백지옥이구나, 결국 핸들러에 걸어버리면 stop으로 정확하게 애니메이션이 멈추지를 않네

<aside> 💡 핸들러에 적절한 처리를 해줘서 repeat조건을 걸고 반복시켜줘야할 듯

</aside>

solution

private func addIdleAnimation(view: UIView, move: CGFloat) {
    let index = self.currentIndex
        
    animator = UIViewPropertyAnimator(duration: 2.0, curve: .linear)
    animator?.addAnimations {
        let centerY = view.center.y
        view.center.y = centerY - CGFloat(move)
    } 
    animator?.addCompletion({ pos in
        if index == self.currentIndex {
            self.addIdleAnimation(view: view, move: -move)
        }
        switch pos {
        case .end:
            print("end \\(index), \\(self.currentIndex)")
        default:
            print("default")
        }
    })
    animator?.startAnimation(afterDelay: Double.random(in: 0.0...1.5))
}

현재 애니메이션의 인덱스와 핸들러가 종료한 시점의 인덱스를 비교해서 같을 경우에만 애니메이션을 리핏하도록 설정했다. 인덱스를 변경했을 때, 발생했던 현상(.end print가 무지막지하게 찍히는 현상)은 일어나지 않았다.

⚠️ Background → foreground

NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification,
                                       object: nil,
                                       queue: .main) {
    [unowned self] notification in
    // background에서 foreground로 돌아오는 경우 실행 될 코드
    animate(command: "start")
}

백그라운드에서 포그라운드 상태로 돌아왔을 때, 애니메이션 동작이 안할 때, 노티를 사용해서 동작

⚠️ 무한루프 dismiss, background 이슈

animator?.addCompletion({ pos in
	  if index == self.currentIndex && !self.willDisappear {
	      if UIApplication.shared.applicationState == .active {
	          self.addIdleAnimation(view: view, move: -move)
	      }
	  }
		...

애니메이션 반복을 실행하는 조건이 잘못된 느낌

급하게 추가한 조건은 뷰컨트롤러가 사라지지 않는 상태이며, 현재 앱 상태가 active일 때만 애니메이션을 반복하게 설정

<aside> 💡 Repeat 에러를 처리하기 위해 총 3가지 조건을 추가했다. 콜렉션 뷰의 인덱스 비교, 컨트롤러가 didappear상태, 앱이 액티브상태일 때, 그리고 기존의 stop애니메이션을 무한 루프에는 적용시키지 않았다.

</aside>

TestFlight에서만 Crash 나는 현상

UIViewPropertyAnimator crashes on dealloc after calling finishAnimation(at:)

The reason that this happened for me was a timing issue with completion blocks:

It means that UIViewPropertyAnimator.state (UIViewAnimatingState) is in an invalid state. Since this is just an Objective C enum it can have any raw value beyond what is defined in the cases. In the case of my crash the value was 5.

I was doing a bunch of chained animations that referenced each other and had something like this: