DispatchQueue, index out of range, tableView

Please can you help me with this problem 😟


I'm pressing a button that segue into a second view controller ( modal sheet) that trigger an intensive calcucaltion process using viewDidLoad.


The first problem was that once I press the button in the first view controller it freezes ( or get stuck) for 3 to 4 seconds ( going through the clauclation loops) before it segue into the second view controller and show the results of the calculation in a tableView.


So I had to put an activity indicator and place the caclucaltion process in the background thread using Dispatchqueue, then put UI activity in the main thread to avoid the button freezing.


The outcome if this was pressing the button in the first view controller, the second view controller ( modal sheet) pops up instantly with an activity indicator spinning and then calculation results gets viewed in the tableview!!


Everything seems to be perfect, so I tried to test it again by dismissing the modal sheet by pulling it down to get back to the first view controller and press the button once more, at this moment it crashes showing : "fatal error: index out of range" and it keeps doing it each time I run it again!


if I remove the dispatch queue and the activity indicator ( spinner), everything works but with a freezed button for 3-4 seconds and then get the results. I can do this multiple times with no crash or index out or range. Only when I put the disptachQueue, it works one time then it crashes the second time.


Sometime it works twice or three times then it crashes again, I realy can't get my head around it !!!


It feels to me that somehow the backgorund thread is keeping some memory and not clearing the table after dismissing the modal sheet but I can't find any clue how to fix this or to prove it.


below is sample of the code :



  // THE SECOND VIEW CONTROLLER 
  
class PressurePipeResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {


  @IBOutlet weak var spinner: UIActivityIndicatorView!


     func startSpinner () {
        spinner.startAnimating()
    }
    
    
    func stopSpinner () {
        spinner.stopAnimating()
    }


  func fillVC () {
        
        let PW = round((PumpPowerkW(flow: finalFlow, p: density, dp: PdTotal, ef: finalEff))*100)/100
      
        PumpPower.text = String ("Pump Power = \(PW) kw @ \(finalEff) % eff ")
      
        PressurePipeHead.text = ("\(PdTotal) bar")
        
        PressurePipeFlow.text = String("\(finalFlow) litre/min")
    
        
    }





  //below function is filling the result table
    
     func numberOfSections(in tableView: UITableView) -> Int {
           return 1
           
       }

       
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
              return PdArray.count
              
          }
       
       
       
       
       func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
           let cell = tableView.dequeueReusableCell(withIdentifier: "ResultCell", for: indexPath)
           // row filler
        let Pd = PdArray[indexPath.row]
        let Fname = FittingName [indexPath.row]
        let Fnumber = FittingNo [indexPath.row]
           // to translate the value of friction to material name through a loop in dictionary

           cell.textLabel?.text = "\(Fname) " + "\(Fnumber) " + "ΔP: \(Pd) bar"
         
         
           return cell
         
       }
    



  override func viewDidLoad() {
        super.viewDidLoad()
       
     
        startSpinner()
     
    
     
      DispatchQueue.global(qos: .background).async {
           // list of the matrix claculations to be triggered in sequence
            self.matEquation1 ()
            self.matEquation2 ()
            self.matEquation3 ()
            self.efmatEquation1()
            self.efmatEquation2()
            self.efmatEquation3()
            self.pipelyKitAlgorithmCHECK ()
            self.effeciencyValue ()
         
          
        
       DispatchQueue.main.async {
           // presenting the results of the calculation into the UI
                self.fillVC() 
                self.tableview.reloadData()
                self.hideKeyboardWhenTappedAround()
             
               
                self.stopSpinner()
                
                        }
        
       
                 }
        
         
           }

}

Accepted Reply

- the calucaltion should be over when I dismiss the modal sheet

I cannot find any code to prevent dismissing while calculating.


once the calculation is over the results are used by the table view

I cannot find any code to prevent the table view to access the Arrays while calculating


This last PdArray version gets used in the tableview.

I cannot find any code that forces the tableview to use only the last version.


Once you invoke a background task, your app gets in a multi-threaded environment and Swift Arrays are not thread-safe.

iOS would call numberOfRowsInSection while old values filled in PdArray, and later call cellForRowAt just after `PdArray.removeAll()`.


I recommend you not to access the same Array from both the main thread and the background thread.

Something like this:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return mtPdArray.count
        
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "ResultCell", for: indexPath)
        // row filler
        let Pd = mtPdArray[indexPath.row]
        let Fname = mtFittingName[indexPath.row]
        let Fnumber = mtFittingNo[indexPath.row]
        // to translate the value of friction to material name through a loop in dictionary
        
        cell.textLabel?.text = "\(Fname) " + "\(Fnumber) " + "ΔP: \(Pd) bar"
        
        return cell
    }

    //...

    override func viewDidLoad() {
        super.viewDidLoad()
        
        startSpinner()
        
        DispatchQueue.global(qos: .background).async {
            // list of the matrix claculations to be triggered in sequence
            self.matEquation1()
            self.matEquation2()
            self.matEquation3()
            self.efmatEquation1()
            self.efmatEquation2()
            self.efmatEquation3()
            self.pipelyKitAlgorithmCHECK()
            self.effeciencyValue()
            
            DispatchQueue.main.async {
                // presenting the results of the calculation into the UI
                self.fillVC()
                //
                self.mtPdArray = self.PdArray
                self.mtFittingName = self.FittingName
                self.mtFittingNo = self.FittingNo
                //
                self.tableview.reloadData()
                self.hideKeyboardWhenTappedAround()
                
                self.stopSpinner()
            }
        }
    }

Prepare main-thread-only Arrays and update them only in the main thread. Please try and tell me what you get.

Replies

With a short glance I cannot find something wrong in your code, so please clarify a few things.


- When you are dismissing the modal sheet, the calculation is still going on? Or finished?

- How many other parts of your code do you use the calculation result? If any, please show all the parts.

- Does the calculation affect `PdArray`? Or any other Arrays accessed in the data source methods?

- the calucaltion should be over when I dismiss the modal sheet

- once the calculation is over the results are used by the table view only in this view controller. There is a button in the same view controller that segue to a third view controller and plot the results in a graph but it does not get triggered unless you press the button to segue to the graph

- yes PdArray is created by self.pipelyKitAlgorithmCHECK () at line 87, then this function calls another function that clears PdArray and refill it ( append it) with adjusted values. This last PdArray version gets used in the tableview.


the last function that spits out PdArray and gets called by self.pipelyKitAlgorithmCHECK () is this function and it not inside the DisptachQueue brackets :



func pipelyKitAlgorithemFinal () {
      
        density = selectedProject!.density
        viscosity = selectedProject!.viscosity
        temp = selectedProject!.temperature
         
        finalFlow = flow
        PdArray.removeAll()
        FittingName.removeAll()
        FittingNo.removeAll()
        Pcount = 0
        repeat {
            
            let  pipe = pipesArray[Pcount]
             
            let A = Area(D: pipe.diameter, Pi: Double.pi)
                  
                  let V = velocity (Q:finalFlow ,A: A)
                 

                  let Re = Renolds (p:density , V:V, D: pipe.diameter, u: viscosity)
            
              
            // reducer and expansion fitting
                      if Pcount > 0 {
                          let  prepipe = pipesArray[Pcount-1]
                          
                          let preA = Area(D: prepipe.diameter, Pi: Double.pi)
                                 
                          let preV = velocity (Q:flow ,A: preA)
                                
                          let preRe = Renolds (p:density , V:preV, D: prepipe.diameter, u: viscosity)
                          
                          prefd = Prefd(Re: preRe, D: prepipe.diameter, p: density, V: preV, L: prepipe.length, e: prepipe.material)
                          
                             if (pipe.diameter - prepipe.diameter) != 0 {
                                
                                 if pipe.diameter < prepipe.diameter {
                                     
                                  PdReduction = round((reduction(D: prepipe.diameter, D1: pipe.diameter, V: preV, p: density, Re: preRe, fd: prefd, no: 1))*100)/100
                                  PdArray.append (PdReduction)
                                  FittingName.append ("P\(Pcount+1), Reducer from d\(prepipe.diameter) to d\(pipe.diameter)")
                                  FittingNo.append ("")
                                 }
                                 
                                 
                                 if pipe.diameter > prepipe.diameter {
                                   
                                  PdExpansion = round((expansion(D: prepipe.diameter, D1: pipe.diameter, V: preV, p: density, Re: preRe, fd: prefd, no: 1))*100)/100
                                  PdArray.append (PdExpansion)
                                  FittingName.append ("P\(Pcount+1), expansion from d\(prepipe.diameter) to d\(pipe.diameter)")
                                  FittingNo.append ("")
                                     
                                 }
                                 
                             }
                      }
            
            
            
            
                  
             
            pipeFrictionLoss = round ((fPipeFrictionLoss(Re: Re, D: pipe.diameter, p: density, V: V, L: pipe.length, e: pipe.material))*100)/100
            PdArray.append (pipeFrictionLoss)
            FittingName.append ("P\(Pcount+1), ID\(Int64(pipe.diameter)),")
            FittingNo.append ("L:\(pipe.length)m, V:\(round(V*10)/10)m/s, ")
            
           
            PdElev = round((Elev(El1: pipe.pElev1, El2: pipe.pElev2, p: density))*100)/100
            PdArray.append(PdElev)
            FittingName.append ("P\(Pcount+1), Pipe level ΔH:\(pipe.pElev2-pipe.pElev1)m, ")
            FittingNo.append ("")
          
            
            
            
            if pipe.elbow90degNo > 0 {
            PdElbow90deg =  round((fPdElbow90TH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.elbow90degNo))*100)/100
            PdArray.append (PdElbow90deg)
            FittingName.append ("P\(Pcount+1), Elbow 90°,")
            FittingNo.append ("Qty: \(pipe.elbow90degNo), ")
            }

            
            if pipe.elbow45degNo > 0 {
            PdElbow45deg = round((fPdElbow45TH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.elbow45degNo))*100)/100
            PdArray.append (PdElbow45deg)
            FittingName.append ("P\(Pcount+1), Elbow 45°,")
            FittingNo.append ("Qty: \(pipe.elbow45degNo), ")
            }
            
            if pipe.bend90degNo > 0 {
            PdBend90deg = round((fPdBend90TH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.bend90degNo))*100)/100
            PdArray.append (PdBend90deg)
            FittingName.append ("P\(Pcount+1), Bend 90°,")
            FittingNo.append ("Qty: \(pipe.bend90degNo), ")
                           }
            
            
            
            if pipe.equalTee90degNo > 0 {
                  PdTeeElbow = round ((fPdTeeTH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.equalTee90degNo))*100)/100
                  PdArray.append(PdTeeElbow)
                  FittingName.append ("P\(Pcount+1), Tee90° elbow flow,")
                  FittingNo.append ("Qty: \(pipe.equalTee90degNo), ")
                      
                  }
                
                  if pipe.ballValveNo > 0 {
                  PdBallValve = round ((fPdballValve(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.ballValveNo))*100)/100
                  PdArray.append(PdBallValve)
                  FittingName.append ("P\(Pcount+1), Ball valve,")
                  FittingNo.append ("Qty: \(pipe.ballValveNo), ")
                      
                  }
                
                  if pipe.diaphragmValveNo > 0 {
                  PdDiaphragmValve = round ((fPdDiaphragm(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.diaphragmValveNo))*100)/100
                  PdArray.append(PdDiaphragmValve)
                  FittingName.append ("P\(Pcount+1), Diaphragm valve,")
                  FittingNo.append ("Qty: \(pipe.diaphragmValveNo), ")
                  
                  }
                  
                  if pipe.threeWayValveLportedNo > 0 {
                  PdThreeWayValve = round ((fPd3WayPlugValve(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.threeWayValveLportedNo))*100)/100
                  PdArray.append(PdThreeWayValve)
                  FittingName.append ("P\(Pcount+1), 3 Way Plug Valve,")
                  FittingNo.append ("Qty: \(pipe.threeWayValveLportedNo), ")
                  }
                  
                  if pipe.angleValveNo > 0 {
                  PdAngleValve = round ((fPdAngleValve45(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.angleValveNo))*100)/100
                  PdArray.append(PdAngleValve)
                  FittingName.append ("P\(Pcount+1), Angle Valve,")
                  FittingNo.append ("Qty: \(pipe.angleValveNo), ")
                  }
                  
                  if pipe.butterFlyValveNo > 0 {
                  PdButterFlyValve = round ((fPdButterfly(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.butterFlyValveNo))*100)/100
                  PdArray.append(PdButterFlyValve)
                  FittingName.append ("P\(Pcount+1), ButterFly Valve,")
                  FittingNo.append ("Qty: \(pipe.butterFlyValveNo), ")
                  }
                  
                  if pipe.gateValveNo > 0 {
                  PdButterFlyValve = round ((fPdGateValve(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.gateValveNo))*100)/100
                  PdArray.append(PdButterFlyValve)
                  FittingName.append ("P\(Pcount+1), Gate Valve,")
                  FittingNo.append ("Qty: \(pipe.gateValveNo), ")
                      
                  }
                  
                  if pipe.checkValveNo > 0 {
                      if pipe.checkValveType == 2.0 {
                      PdCheckValve = round ((fPdSwingCV(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.checkValveNo))*100)/100
                      PdArray.append(PdCheckValve)
                      FittingName.append ("P\(Pcount+1), Swing Check Valve,")
                      FittingNo.append ("Qty: \(pipe.checkValveNo), ")
                      }
                 
                      if pipe.checkValveType == 3.0 {
                      PdCheckValve = round ((fPdLiftCV(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.checkValveNo))*100)/100
                      PdArray.append(PdCheckValve)
                      FittingName.append ("P\(Pcount+1), Lift Check Valve,")
                      FittingNo.append ("Qty: \(pipe.checkValveNo), ")
                      
                      }
                      
                      if pipe.checkValveType == 4.0 {
                      PdCheckValve = round ((fPdTiltingDiskCV(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.checkValveNo))*100)/100
                      PdArray.append(PdCheckValve)
                      FittingName.append ("P\(Pcount+1), Disk Check Valve,")
                      FittingNo.append ("Qty: \(pipe.checkValveNo), ")
                      }
                      
                  }
                  
                  if pipe.reducerFittingNo > 0 {
                  PdOrifice = round ((Orifice(Q: flow, Pi: Double.pi, D: pipe.diameter, D1: pipe.reducingPipeD1, L1: pipe.reducingPipeL1, V: V, p: density, Re: Re, no: pipe.reducerFittingNo, e: pipe.material, u: viscosity))*100)/100
                  PdArray.append(PdOrifice)
                  FittingName.append ("P\(Pcount+1), Orifice,")
                  FittingNo.append ("Qty: \(pipe.reducerFittingNo), ")
                      
                  }
                  
                  
                  if pipe.customAfittingNo > 0 {
               
                      if pipe.ecmA == false {
                        PdCustomA = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customAfittingValue*0.5, yf2: 0.5, xf3: pipe.customAfittingValue, yf3: 1.0, cflow: flow, no: pipe.customAfittingNo, p:density))*100)/100
                      PdArray.append(PdCustomA)
                     if pipe.customAfittingType == 0 {
                      FittingName.append ("P\(Pcount+1), Cust. fit. A-KV,")
                                    }
                      if pipe.customAfittingType == 1 {
                      FittingName.append ("P\(Pcount+1), Cust. fit. A-CV,")
                                    }
                      FittingNo.append ("Qty: \(pipe.customAfittingNo), ")
                      
                      }
                      
                      if pipe.ecmA == true {
                        
                        PdCustomA = round ((customFitting(xf1: pipe.customFlowA1, yf1: pipe.customHeadA1, xf2: pipe.customFlowA2, yf2: pipe.customHeadA2, xf3: pipe.customFlowA3, yf3: pipe.customHeadA3, cflow: flow, no: pipe.customAfittingNo, p:density))*100)/100
                      PdArray.append(PdCustomA)
                      FittingName.append ("P\(Pcount+1), Cust. fit. A-CURVE,")
                      FittingNo.append ("Qty: \(pipe.customAfittingNo), ")
                          
                      }
                      
                      
                  }
                  
                  if pipe.customBfittingNo > 0 {
                          
                             if pipe.ecmB == false {
                               
                                PdCustomB = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customBfittingValue*0.5, yf2: 0.5, xf3: pipe.customBfittingValue, yf3: 1.0, cflow: flow, no: pipe.customBfittingNo, p: density))*100)/100
                             PdArray.append(PdCustomB)
                                if pipe.customBfittingType == 0 {
                             FittingName.append ("P\(Pcount+1), Cust. fit. B-KV,")
                                }
                                if pipe.customBfittingType == 1 {
                            FittingName.append ("P\(Pcount+1), Cust. fit. B-CV,")
                                }
                             FittingNo.append ("Qty: \(pipe.customBfittingNo), ")
                                
                             }
                             
                             if pipe.ecmB == true {
                                PdCustomB = round ((customFitting(xf1: pipe.customFlowB1, yf1: pipe.customHeadB1, xf2: pipe.customFlowB2, yf2: pipe.customHeadB2, xf3: pipe.customFlowB3, yf3: pipe.customHeadB3, cflow: flow, no: pipe.customBfittingNo, p: density))*100)/100
                             PdArray.append(PdCustomB)
                             FittingName.append ("P\(Pcount+1), Cust. fit. B-CURVE,")
                             FittingNo.append ("Qty: \(pipe.customBfittingNo), ")
                             }
                             
                             
                         }
                  
                  
                        
                  if pipe.customCfittingNo > 0 {
                   
                      if pipe.ecmC == false {
                        PdCustomC = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customCfittingValue*0.5, yf2: 0.5, xf3: pipe.customCfittingValue, yf3: 1.0, cflow: flow, no: pipe.customCfittingNo, p: density))*100)/100
                      PdArray.append(PdCustomC)
                      if pipe.customCfittingType == 0 {
                      FittingName.append ("P\(Pcount+1), Cust. fit. C-KV,")
                                    }
                      if pipe.customCfittingType == 1 {
                      FittingName.append ("P\(Pcount+1), Cust. fit. C-CV,")
                                    }
                     FittingNo.append ("Qty: \(pipe.customCfittingNo), ")
                      
                      }
                      
                      if pipe.ecmC == true {
                        PdCustomC = round ((customFitting(xf1: pipe.customFlowC1, yf1: pipe.customHeadC1, xf2: pipe.customFlowC2, yf2: pipe.customHeadC2, xf3: pipe.customFlowC3, yf3: pipe.customHeadC3, cflow: flow, no: pipe.customCfittingNo, p: density))*100)/100
                      PdArray.append(PdCustomC)
                      FittingName.append ("P\(Pcount+1), Cust. fit. C-CURVE,")
                      FittingNo.append ("Qty: \(pipe.customCfittingNo), ")
                          
                      }
                      
                      
                  }
                  
                  
                  if pipe.customDfittingNo > 0 {
                                        
                        if pipe.ecmD == false {
                            PdCustomD = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customDfittingValue*0.5, yf2: 0.5, xf3: pipe.customDfittingValue, yf3: 1.0, cflow: flow, no: pipe.customDfittingNo, p: density))*100)/100
                        PdArray.append(PdCustomD)
                       if pipe.customDfittingType == 0 {
                        FittingName.append ("P\(Pcount+1), Cust. fit. D-KV,")
                                      }
                        if pipe.customDfittingType == 1 {
                        FittingName.append ("P\(Pcount+1), Cust. fit. D-CV,")
                                      }                        FittingNo.append ("Qty: \(pipe.customDfittingNo), ")
                                           
                                           }
                                           
                        if pipe.ecmD == true {
                            PdCustomD = round ((customFitting(xf1: pipe.customFlowD1, yf1: pipe.customHeadD1, xf2: pipe.customFlowD2, yf2: pipe.customHeadD2, xf3: pipe.customFlowD3, yf3: pipe.customHeadD3, cflow: flow, no: pipe.customDfittingNo, p: density))*100)/100
                        PdArray.append(PdCustomD)
                        FittingName.append ("P\(Pcount+1), Cust. fit. D-CURVE,")
                        FittingNo.append ("Qty: \(pipe.customDfittingNo), ")
                                               
                                           }
                                           
                                           
                                       }
            
           
          
            
              Pcount += 1
              
              } while Pcount < pipesArray.count
              
                        PdTotal = round(PdArray.reduce(0,+)*100)/100
        finalFlow = round(finalFlow*10)/10
        
    }
   

Which line do you get the crash on wrong index ?

The crash happens inside this function : self.pipelyKitAlgorithmCHECK ()


Below is the function code and the crash is happening at line (267) where I print "RUN2" as a way to detect the crash position.


Some times I get run2 : 2 , 3 or 4 of Run2 and some times I don't get run2 at all and this is without changing any input data.


When it works normally run2 should appear hundreds of times.


The most important thing is that when I remove the DisptachQueue, i dont get the index problem and everything works fine but ofcourse i get the annoying button freez





func pipelyKitAlgorithmCHECK () {
      
        density = selectedProject!.density
        viscosity = selectedProject!.viscosity
        temp = selectedProject!.temperature
        
        MaxFlow = selectedProject!.pumpFlowMax
      
        MaxFlowCount = 1000000
        
        flow = 0.000001
    
    
        flowCount = 0
    repeat {

        PdArray.removeAll()
    
        
         Pcount = 0
      repeat {
        
      
        
        let  pipe = pipesArray[Pcount]
        
       
     
        let A = Area(D: pipe.diameter, Pi: Double.pi)
        
        let V = velocity (Q:flow ,A: A)
       

        let Re = Renolds (p:density , V:V, D: pipe.diameter, u: viscosity)
        
        // reducer and expansion fitting
           if Pcount > 0 {
         
               let  prepipe = pipesArray[Pcount-1]
               
               let preA = Area(D: prepipe.diameter, Pi: Double.pi)
                      
               let preV = velocity (Q:flow ,A: preA)
                     
               let preRe = Renolds (p:density , V:preV, D: prepipe.diameter, u: viscosity)
               
               prefd = Prefd(Re: preRe, D: prepipe.diameter, p: density, V: preV, L: prepipe.length, e: prepipe.material)
               
                  if (pipe.diameter - prepipe.diameter) != 0 {
                     
                      if pipe.diameter < prepipe.diameter {
                          
                       PdReduction = round((reduction(D: prepipe.diameter, D1: pipe.diameter, V: preV, p: density, Re: preRe, fd: prefd, no: 1))*100)/100
                       PdArray.append (PdReduction)
                      }
                      
                      
                      if pipe.diameter > prepipe.diameter {
                        
                       PdExpansion = round((expansion(D: prepipe.diameter, D1: pipe.diameter, V: preV, p: density, Re: preRe, fd: prefd, no: 1))*100)/100
                       PdArray.append (PdExpansion)
                          
                      }
                      
                  }
           }
       
       
        pipeFrictionLoss = round((fPipeFrictionLoss(Re: Re, D: pipe.diameter, p: density, V: V, L: pipe.length, e: pipe.material))*100)/100
        PdArray.append (pipeFrictionLoss)
        
        if Pcount > 0 {
        PdElev = round((Elev(El1: pipe.pElev1, El2: pipe.pElev2, p: density))*100)/100
        PdArray.append(PdElev)
        }
   
        
        if pipe.elbow90degNo > 0 {
        PdElbow90deg =  round ((fPdElbow90TH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.elbow90degNo))*100)/100
        PdArray.append (PdElbow90deg)
         }

        if pipe.elbow45degNo > 0 {
        PdElbow45deg = round((fPdElbow45TH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.elbow45degNo))*100)/100
        PdArray.append (PdElbow45deg)
         }
        
        
        if pipe.bend90degNo > 0 {
        PdBend90deg = round((fPdBend90TH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.bend90degNo))*100)/100
        PdArray.append (PdBend90deg)
                }
        
        
        
        if pipe.equalTee90degNo > 0 {
        PdTeeElbow = round ((fPdTeeTH(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.equalTee90degNo))*100)/100
        PdArray.append(PdTeeElbow)
            
        }
      
        if pipe.ballValveNo > 0 {
        PdBallValve = round ((fPdballValve(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.ballValveNo))*100)/100
        PdArray.append(PdBallValve)
            
        }
      
        if pipe.diaphragmValveNo > 0 {
        PdDiaphragmValve = round ((fPdDiaphragm(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.diaphragmValveNo))*100)/100
        PdArray.append(PdDiaphragmValve)
        
        }
        
        if pipe.threeWayValveLportedNo > 0 {
        PdThreeWayValve = round ((fPd3WayPlugValve(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.threeWayValveLportedNo))*100)/100
        PdArray.append(PdThreeWayValve)
        }
        
        if pipe.angleValveNo > 0 {
        PdAngleValve = round ((fPdAngleValve45(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.angleValveNo))*100)/100
        PdArray.append(PdAngleValve)
            
        }
        
        if pipe.butterFlyValveNo > 0 {
        PdButterFlyValve = round ((fPdButterfly(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.butterFlyValveNo))*100)/100
        PdArray.append(PdButterFlyValve)
        }
        
        if pipe.gateValveNo > 0 {
        PdButterFlyValve = round ((fPdGateValve(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.gateValveNo))*100)/100
        PdArray.append(PdButterFlyValve)
            
        }
         
        if pipe.checkValveNo > 0 {
           
            if pipe.checkValveType == 2.0 {
            PdCheckValve = round ((fPdSwingCV(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.checkValveNo))*100)/100
            PdArray.append(PdCheckValve)
            
            }
       
            if pipe.checkValveType == 3.0 {
            PdCheckValve = round ((fPdLiftCV(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.checkValveNo))*100)/100
            PdArray.append(PdCheckValve)
            
            }
            
            if pipe.checkValveType == 4.0 {
            PdCheckValve = round ((fPdTiltingDiskCV(V: V, p: density, Re: Re, D: pipe.diameter, no: pipe.checkValveNo))*100)/100
            PdArray.append(PdCheckValve)
                
            }
            
        }
        
        if pipe.reducerFittingNo > 0 {
        PdOrifice = round ((Orifice(Q: flow, Pi: Double.pi, D: pipe.diameter, D1: pipe.reducingPipeD1, L1: pipe.reducingPipeL1, V: V, p: density, Re: Re, no: pipe.reducerFittingNo, e: pipe.material, u: viscosity))*100)/100
        PdArray.append(PdOrifice)
            
        }
        
        
        if pipe.customAfittingNo > 0 {
         
            if pipe.ecmA == false {
                PdCustomA = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customAfittingValue*0.5, yf2: 0.5, xf3: pipe.customAfittingValue, yf3: 1.0, cflow: flow, no: pipe.customAfittingNo, p: density))*100)/100
            PdArray.append(PdCustomA)
            
            }
            
            if pipe.ecmA == true {
                PdCustomA = round ((customFitting(xf1: pipe.customFlowA1, yf1: pipe.customHeadA1, xf2: pipe.customFlowA2, yf2: pipe.customHeadA2, xf3: pipe.customFlowA3, yf3: pipe.customHeadA3, cflow: flow, no: pipe.customAfittingNo, p: density))*100)/100
            PdArray.append(PdCustomA)
                
            }
            
            
        }
        
        if pipe.customBfittingNo > 0 {
                
                   if pipe.ecmB == false {
                    PdCustomB = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customBfittingValue*0.5, yf2: 0.5, xf3: pipe.customBfittingValue, yf3: 1.0, cflow: flow, no: pipe.customBfittingNo, p: density))*100)/100
                   PdArray.append(PdCustomB)
                   
                   }
                   
                   if pipe.ecmB == true {
                    PdCustomB = round ((customFitting(xf1: pipe.customFlowB1, yf1: pipe.customHeadB1, xf2: pipe.customFlowB2, yf2: pipe.customHeadB2, xf3: pipe.customFlowB3, yf3: pipe.customHeadB3, cflow: flow, no: pipe.customBfittingNo, p: density))*100)/100
                   PdArray.append(PdCustomB)
                       
                   }
                   
                   
               }
        
        
              
        if pipe.customCfittingNo > 0 {
         
            if pipe.ecmC == false {
                PdCustomC = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customCfittingValue*0.5, yf2: 0.5, xf3: pipe.customCfittingValue, yf3: 1.0, cflow: flow, no: pipe.customCfittingNo, p: density))*100)/100
            PdArray.append(PdCustomC)
            
            }
            
            if pipe.ecmC == true {
                PdCustomC = round ((customFitting(xf1: pipe.customFlowC1, yf1: pipe.customHeadC1, xf2: pipe.customFlowC2, yf2: pipe.customHeadC2, xf3: pipe.customFlowC3, yf3: pipe.customHeadC3, cflow: flow, no: pipe.customCfittingNo, p: density))*100)/100
            PdArray.append(PdCustomC)
                
            }
            
            
        }
    
        
        if pipe.customDfittingNo > 0 {
                          
                                 if pipe.ecmD == false {
                                    PdCustomD = round ((customFitting(xf1: 0.0, yf1: 0.0, xf2: pipe.customDfittingValue*0.5, yf2: 0.5, xf3: pipe.customDfittingValue, yf3: 1.0, cflow: flow, no: pipe.customDfittingNo, p: density))*100)/100
                                 PdArray.append(PdCustomD)
                                 
                                 }
                                 
                                 if pipe.ecmD == true {
                                    PdCustomD = round ((customFitting(xf1: pipe.customFlowD1, yf1: pipe.customHeadD1, xf2: pipe.customFlowD2, yf2: pipe.customHeadD2, xf3: pipe.customFlowD3, yf3: pipe.customHeadD3, cflow: flow, no: pipe.customDfittingNo, p: density))*100)/100
                                 PdArray.append(PdCustomD)
                                     
                                 }
                                 
                                 
                             }
        
        
        
        
        
        Pcount += 1
        
        } while Pcount < pipesArray.count
            
                  TotalPd = round(PdArray.reduce(0,+)*10)/10
        
       if flow < x3  {
                      pumpPressure = a1 * pow(flow,2) + b1 * flow + c1
              }
        
        
        if flow >= x3 && flow <= x5 {
                pumpPressure = a2 * pow(flow,2) + b2 * flow + c2
        }
        
        if flow > x5 {
                       pumpPressure = a3 * pow(flow,2) + b3 * flow + c3
               }
        
                deltaP = (TotalPd - pumpPressure)
         
       
    
   
        
        flow = flow + 2
                flowCount += 1
        print ("RUN 2")
     
    } while  (deltaP <= 0.01 && flow <= MaxFlow && flowCount <= MaxFlowCount )
        
     
        if deltaP > 0.01 {
     print ("A SYSTEM SOLUTION HAS BEEN REACHED")
            flow = flow - 0.01
       
    pipelyKitAlgorithemFinal()
    print ( "check pressure = \(TotalPd) and final flow = \(finalFlow)")
       print ("flowCount : \(flowCount)")
           
        }
        
      
        
        if flow >  MaxFlow {
            maxFlowAlert()
        }
        
        if flowCount > MaxFlowCount {
           maxFlowCountAlert ()
        }
    }
   

- the calucaltion should be over when I dismiss the modal sheet

I cannot find any code to prevent dismissing while calculating.


once the calculation is over the results are used by the table view

I cannot find any code to prevent the table view to access the Arrays while calculating


This last PdArray version gets used in the tableview.

I cannot find any code that forces the tableview to use only the last version.


Once you invoke a background task, your app gets in a multi-threaded environment and Swift Arrays are not thread-safe.

iOS would call numberOfRowsInSection while old values filled in PdArray, and later call cellForRowAt just after `PdArray.removeAll()`.


I recommend you not to access the same Array from both the main thread and the background thread.

Something like this:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return mtPdArray.count
        
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "ResultCell", for: indexPath)
        // row filler
        let Pd = mtPdArray[indexPath.row]
        let Fname = mtFittingName[indexPath.row]
        let Fnumber = mtFittingNo[indexPath.row]
        // to translate the value of friction to material name through a loop in dictionary
        
        cell.textLabel?.text = "\(Fname) " + "\(Fnumber) " + "ΔP: \(Pd) bar"
        
        return cell
    }

    //...

    override func viewDidLoad() {
        super.viewDidLoad()
        
        startSpinner()
        
        DispatchQueue.global(qos: .background).async {
            // list of the matrix claculations to be triggered in sequence
            self.matEquation1()
            self.matEquation2()
            self.matEquation3()
            self.efmatEquation1()
            self.efmatEquation2()
            self.efmatEquation3()
            self.pipelyKitAlgorithmCHECK()
            self.effeciencyValue()
            
            DispatchQueue.main.async {
                // presenting the results of the calculation into the UI
                self.fillVC()
                //
                self.mtPdArray = self.PdArray
                self.mtFittingName = self.FittingName
                self.mtFittingNo = self.FittingNo
                //
                self.tableview.reloadData()
                self.hideKeyboardWhenTappedAround()
                
                self.stopSpinner()
            }
        }
    }

Prepare main-thread-only Arrays and update them only in the main thread. Please try and tell me what you get.

That was spot on thank you very much, I implemented your changes and it just worked like magic.

Thank you very much again for your valuable time and help