user8822312
user8822312

Reputation: 275

swift: recursive animation

In my app I want to animate an array of Strings to give some instruction to users. My expectation is the first string fades in, maintains for seconds and fades out then the first string is removed from the array and the next shows and so on until the array gets empty. There is something wrong with my implementation however it's hard to debug (it seems the program would not be executed line by line), here is my code:

var text = [Text.text1, Text.text2]
@IBOutlet weak var paragraph: UILabel!
override func viewDidLoad() {
    super.viewDidLoad()
    paragraph.alpha = 0
    showText(text: text)
}

private func showText(text: [String]) {
    if text.first == nil {
        return
    } else {
        paragraph.text = text.first
        UIView.animate(withDuration: 1.5, delay: 1.5, options: .curveEaseInOut, animations: {
            self.paragraph.alpha = 1
        }, completion: { (_) in
            UIView.animate(withDuration: 1.5, delay: 0.5, options: .curveEaseInOut, animations: {
                self.paragraph.alpha = 0
            }, completion: { (_) in
                self.text.remove(at: 0)
                self.showText(text: text)
            })
        })
    }
}

The problem is the first string shows three times and then I get an index out of range error. When I try setting breakpoints and click step over, it will skip the animation and completion blocks, and I don't know how to debug a function with a block as its parameter. And also even though I have

paragraph.text = text.first

after the first round, paragraph.text has been the second string but still the first string shows. Similarly, it seems my terminate condition doesn't work: after two iterations, I've noticed the count of the self.text array has become 0, but the function didn't return, it goes to else...

if text.count == 0 {
            return
        } else { ... }

I'm a newbie and don't know how to debug blocks...

Upvotes: 1

Views: 349

Answers (1)

rmaddy
rmaddy

Reputation: 318774

The problem is subtle and it's all in the second completion block. You have:

self.text.remove(at: 0)
self.showText(text: text)

You update the text property but you then pass the local text parameter which hasn't been changed.

Change the 2nd line to pass self.text instead of just text.

But referencing self.text inside showText negates to need to even have the text parameter. Either write showText to only use the text property of the class or better, only reference the text parameter. The latter has the advantage of not modifying the property.

To implement the latter option, change the two lines in the second completion block from:

self.text.remove(at: 0)
self.showText(text: text)

to just:

self.showText(text: Array(text[1...]))

Upvotes: 1

Related Questions