Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
366 views
in Technique[技术] by (71.8m points)

ios - Swift Dispatch Main sync messes UIView animation up

I am facing an issue where my UIView with a Lottie-Animation is not being correctly displayed. I am using a lot of Dispatch.main.async and I a pretty sure that is messing everything up.

1. User taps on a Button and instantly my UIVIew("coverView")+ Animation ("loadingAnimation") should be displayed (calling setupLoadingAnimation)

ScreenVideo

But it is not, it is only being displayed after a another function is finished.

How and where do I have to call animation.play() and view.isHidden = false so it is being displayed right after the button was tapped?

This is my structure:

@objc func addWishButtonTapped() {

    print("tapped 1")
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }

        // ...
        self.setUpLoadingAnimation()
        // ...
        
        print("tapped 2")
        
        self.crawlWebsite {
            print("tapped 3")
            self.hideLoadingView()
            print("tapped 4")
        }

    }
}

The view is not being setup and it stops printing after print("tapped 2") and only print print(tapped 3"). That is when the view+ loadingAnimatino become visible.

Setup Loading Animation:

    //MARK: setupLoadingAnimation
func setUpLoadingAnimation(){
    
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        self.view.addSubview(self.coverView)
        self.coverView.topAnchor.constraint(equalTo: self.wishView.topAnchor).isActive = true
        self.coverView.leadingAnchor.constraint(equalTo: self.wishView.leadingAnchor).isActive = true
        self.coverView.trailingAnchor.constraint(equalTo: self.wishView.trailingAnchor).isActive = true
        self.coverView.bottomAnchor.constraint(equalTo: self.wishView.bottomAnchor).isActive = true
        
        self.loadingAnimation.contentMode = .scaleAspectFit
        self.loadingAnimation.translatesAutoresizingMaskIntoConstraints = false
        self.coverView.addSubview(self.loadingAnimation)
        
        self.loadingAnimation.centerXAnchor.constraint(equalTo: self.coverView.centerXAnchor).isActive = true
        self.loadingAnimation.centerYAnchor.constraint(equalTo: self.coverView.centerYAnchor).isActive = true
        self.loadingAnimation.heightAnchor.constraint(equalToConstant: 100).isActive = true
        self.loadingAnimation.widthAnchor.constraint(equalToConstant: 100).isActive = true
        self.loadingAnimation.loopMode = .loop
        self.loadingAnimation.play()
    }
    
}

crawlWebsite:

    //MARK: crawlWebsite
func crawlWebsite(finished: @escaping () -> Void){
    
    var html: String?
    guard let url = self.url else { return }
    let directoryURL = url as NSURL
    let urlString: String = directoryURL.absoluteString! 
    // save url to wish
    self.wishView.link = urlString
 
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { finished(); return }
        html = self.getHTMLfromURL(url: url)
        self.getContentFromHTML(html: html, url: url)
        self.getOpenGraphData(urlString: urlString) {
            finished()
        }
    }
}

I know this is very messy so I hope everything is clear! Let me know if you have any questions! I am very stuck here...

question from:https://stackoverflow.com/questions/65836254/swift-dispatch-main-sync-messes-uiview-animation-up

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Seems that there are redundant DispatchQueue.main.async calls

  • Better is to remove DispatchQueue.main.async in all the function and call all these functions within DispatchQueue.main.async in addWishButtonTapped()

You can try with below changes:

@objc func addWishButtonTapped() {
  print("tapped 1")
  DispatchQueue.main.async { [weak self] in
    guard let self = self else { return }

     // ...
     self.setUpLoadingAnimation()
     // ...
    
    print("tapped 2")
    
    self.crawlWebsite {
        print("tapped 3")
        self.hideLoadingView()
        print("tapped 4")
       }
    }
}

and in setUpLoadingAnimation() remove DispatchQueue.main.async as this function is already called in main thread. Also you can do view.isHidden = false in this function

//MARK: setupLoadingAnimation
func setUpLoadingAnimation(){  
    self.view.addSubview(self.coverView)
    self.coverView.topAnchor.constraint(equalTo: self.wishView.topAnchor).isActive = true
    self.coverView.leadingAnchor.constraint(equalTo: self.wishView.leadingAnchor).isActive = true
    self.coverView.trailingAnchor.constraint(equalTo: self.wishView.trailingAnchor).isActive = true
    self.coverView.bottomAnchor.constraint(equalTo: self.wishView.bottomAnchor).isActive = true
    
    self.loadingAnimation.contentMode = .scaleAspectFit
    self.loadingAnimation.translatesAutoresizingMaskIntoConstraints = false
    self.coverView.addSubview(self.loadingAnimation)
    
    self.loadingAnimation.centerXAnchor.constraint(equalTo: self.coverView.centerXAnchor).isActive = true
    self.loadingAnimation.centerYAnchor.constraint(equalTo: self.coverView.centerYAnchor).isActive = true
    self.loadingAnimation.heightAnchor.constraint(equalToConstant: 100).isActive = true
    self.loadingAnimation.widthAnchor.constraint(equalToConstant: 100).isActive = true
    self.loadingAnimation.loopMode = .loop
    self.loadingAnimation.play()

    self.view.isHidden = false
}

and crawlWebsite you can keep is as is :

//MARK: crawlWebsite
func crawlWebsite(finished: @escaping () -> Void){

var html: String?
guard let url = self.url else { return }
let directoryURL = url as NSURL
let urlString: String = directoryURL.absoluteString! 
// save url to wish
self.wishView.link = urlString

DispatchQueue.main.async { [weak self] in
    guard let self = self else { finished(); return }
    html = self.getHTMLfromURL(url: url)
    self.getContentFromHTML(html: html, url: url)
    self.getOpenGraphData(urlString: urlString) {
        finished()
    }
  }
}

I hope this could solve the issue you are facing.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...