Alexey Savchenko
Alexey Savchenko

Reputation: 890

Strange duplicating UIView during addSubview

I have encountered strange behavior of UIViews. I have an empty 'container' UIView - WaveformPlot that is expected to be filled with child subviews.

class WaveformPlot: UIView {

  
  
  var normalColor: UIColor?
  var progressColor: UIColor?
  
  var waveforms: [UIView]?

  override init(frame: CGRect) {

    super.init(frame: frame)

  }
  
  required init?(coder aDecoder: NSCoder) {

    super.init(coder: aDecoder)
    waveforms = []
  
  }
  


  //MARK: Populate plot with data 
  
  func populateWithData(from dataSet: [Float]){
    
    DispatchQueue.main.async {
      
      var offset: CGFloat = 0
      
      for index in 0..<dataSet.count {
        
        let barView = UIView(frame: CGRect(x: offset,
                                        y:   self.frame.height / 2,
                                        width: self.frame.width / CGFloat(dataSet.count),
                                        height: -(CGFloat)((dataSet[index]))))

        
        
        

        barView.backgroundColor = self.normalColor
        barView.layer.borderColor = UIColor.black.cgColor
        barView.layer.borderWidth = 0.25
        
        //Append barView to parent 'container' view
        self.addSubview(barView)
        //Append barView to an array for future processing
        self.waveforms?.append(barView)

        offset += self.frame.width / CGFloat(dataSet.count)

      }
     
    }
  }
  
  func updateColorOfBars(with currentTime: Double, of totalDuration: Double){
    
    let percentagePlayed = currentTime / totalDuration
    
    print("Percerntage played - \((percentagePlayed * 100) / 100)")
    
    let quantityOfBarsToBeUpdated = Double((self.waveforms?.count)!) * percentagePlayed
    
    for item in self.waveforms!{
      if (self.waveforms?.index(of: item)!)! <= Int(quantityOfBarsToBeUpdated * percentagePlayed) {
        print("index processing - \(self.waveforms?.index(of: item))")
        item.backgroundColor = self.progressColor
      }
    }
  }
  
  func clearPlot(){
  
    for item in self.subviews{
      
      item.removeFromSuperview()
      
    }
  
  }
}

Then I initiate this WaveformPlot in ViewController with 64 values in "data" [Float] array:

class ViewController: UIViewController {

  var data: [Float] = [13, 37, 2, 3, 64, 62, 31, 50, 60, 17, 48, 56, 24, 25, 45, 8, 32, 1, 39, 26, 42, 10, 4, 27, 51, 40, 11, 12, 35, 41, 46, 21, 55, 36, 20, 14, 34, 47, 6, 9, 5, 59, 30, 54, 23, 49, 19, 0, 58, 61, 57, 28, 29, 15, 44, 16, 63, 18, 22, 43, 7, 33, 53, 38]

  @IBOutlet weak var waveformView: WaveformPlot!
  @IBOutlet weak var playButton: UIButton!
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
  }
  
  override func viewDidLayoutSubviews() {
    
    waveformView.normalColor = UIColor.blue
    waveformView.progressColor = UIColor.orange
    waveformView.populateWithData(from: data)
    
  }
}

This results in this ->

Screen

But during visual debugging I have discovered that there are 128 views instead of 64. Under each barView there is another bar. Details on this screenshot.

Screen

Please help me deal with this issue. Why additional bar is being attached during original one?

Upvotes: 0

Views: 43

Answers (1)

Infinity James
Infinity James

Reputation: 4735

viewDidLayoutSubviews will be called as many times as is appropriate. You are create the bars every time it is called. You should iterate over the views and remove them before create new ones:

for view in waveForms { view.removeFromSuperview. } self.waveForms.removeAll()

Upvotes: 1

Related Questions