Swift calling completion handler in from another file fails












0















I am calling a funciton with completio=n handler from one calss to another class



Called class:



class PVClass
{

var avgMonthlyAcKw:Double = 0.0

var jsonString:String!

func estimateMonthlyACkW (areaSqFt:Float, completion: @escaping(Double) -> () ){

var capacityStr:String = ""

let estimatedCapacity = Float(areaSqFt/66.0)
capacityStr = String(format: "%.2f", estimatedCapacity)

// Build some Url string
var urlString:String = "https://developer.nrel.gov/"
urlString.append("&system_capacity=")
urlString.append(capacityStr)

let pvURL = URL(string: urlString)
let dataTask = URLSession.shared.dataTask(with: pvURL!) { data, response, error in
do {

let _ = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
self.jsonString = String(data: data!, encoding: .utf8)!
print("JSON String:(String(describing: self.jsonString))")

if self.jsonString != nil {
let decoder = JSONDecoder()
let jsonData = try decoder.decode(PVClass.Top.self, from: data!)

// do some parsing here
var totalAcKw: Double = 0.0
let cnt2: Int = (jsonData.Outputs?.ACMonthly.count)!
for i in 0..<(cnt2-1) {
totalAcKw = totalAcKw + (jsonData.Outputs?.ACMonthly[i])!
}
self.avgMonthlyAcKw = Double(totalAcKw)/Double(cnt2)

// prints value
print("updated estimate: ", self.avgMonthlyAcKw)
}

} catch {
print("error: (error.localizedDescription)")

}
}
dataTask.resume()
completion(self.avgMonthlyAcKw)
}


Calling Class:



 func estimate() {
var estimatedSolarkWh:Double = 0.0
let aPVClass = PVClass()
aPVClass.estimateMonthlyACkW(areaSqFt: 100.0, completion: { (monthlyAckW) -> Void in

estimatedSolarkWh = monthlyAckW
self.view.setNeedsDisplay()
})
return
}
}


When I call the function estimate() the estimateMonthlyACkW function in the other PVClass is executed but it returns after the calling estimate() function is executed. So even though in the called function the URLsession is executed, json is parsed, and value is printed correctly - the value never gets gets transferred to the completion handler and the value never comes back to calling class. How can I fix this?










share|improve this question



























    0















    I am calling a funciton with completio=n handler from one calss to another class



    Called class:



    class PVClass
    {

    var avgMonthlyAcKw:Double = 0.0

    var jsonString:String!

    func estimateMonthlyACkW (areaSqFt:Float, completion: @escaping(Double) -> () ){

    var capacityStr:String = ""

    let estimatedCapacity = Float(areaSqFt/66.0)
    capacityStr = String(format: "%.2f", estimatedCapacity)

    // Build some Url string
    var urlString:String = "https://developer.nrel.gov/"
    urlString.append("&system_capacity=")
    urlString.append(capacityStr)

    let pvURL = URL(string: urlString)
    let dataTask = URLSession.shared.dataTask(with: pvURL!) { data, response, error in
    do {

    let _ = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
    self.jsonString = String(data: data!, encoding: .utf8)!
    print("JSON String:(String(describing: self.jsonString))")

    if self.jsonString != nil {
    let decoder = JSONDecoder()
    let jsonData = try decoder.decode(PVClass.Top.self, from: data!)

    // do some parsing here
    var totalAcKw: Double = 0.0
    let cnt2: Int = (jsonData.Outputs?.ACMonthly.count)!
    for i in 0..<(cnt2-1) {
    totalAcKw = totalAcKw + (jsonData.Outputs?.ACMonthly[i])!
    }
    self.avgMonthlyAcKw = Double(totalAcKw)/Double(cnt2)

    // prints value
    print("updated estimate: ", self.avgMonthlyAcKw)
    }

    } catch {
    print("error: (error.localizedDescription)")

    }
    }
    dataTask.resume()
    completion(self.avgMonthlyAcKw)
    }


    Calling Class:



     func estimate() {
    var estimatedSolarkWh:Double = 0.0
    let aPVClass = PVClass()
    aPVClass.estimateMonthlyACkW(areaSqFt: 100.0, completion: { (monthlyAckW) -> Void in

    estimatedSolarkWh = monthlyAckW
    self.view.setNeedsDisplay()
    })
    return
    }
    }


    When I call the function estimate() the estimateMonthlyACkW function in the other PVClass is executed but it returns after the calling estimate() function is executed. So even though in the called function the URLsession is executed, json is parsed, and value is printed correctly - the value never gets gets transferred to the completion handler and the value never comes back to calling class. How can I fix this?










    share|improve this question

























      0












      0








      0








      I am calling a funciton with completio=n handler from one calss to another class



      Called class:



      class PVClass
      {

      var avgMonthlyAcKw:Double = 0.0

      var jsonString:String!

      func estimateMonthlyACkW (areaSqFt:Float, completion: @escaping(Double) -> () ){

      var capacityStr:String = ""

      let estimatedCapacity = Float(areaSqFt/66.0)
      capacityStr = String(format: "%.2f", estimatedCapacity)

      // Build some Url string
      var urlString:String = "https://developer.nrel.gov/"
      urlString.append("&system_capacity=")
      urlString.append(capacityStr)

      let pvURL = URL(string: urlString)
      let dataTask = URLSession.shared.dataTask(with: pvURL!) { data, response, error in
      do {

      let _ = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
      self.jsonString = String(data: data!, encoding: .utf8)!
      print("JSON String:(String(describing: self.jsonString))")

      if self.jsonString != nil {
      let decoder = JSONDecoder()
      let jsonData = try decoder.decode(PVClass.Top.self, from: data!)

      // do some parsing here
      var totalAcKw: Double = 0.0
      let cnt2: Int = (jsonData.Outputs?.ACMonthly.count)!
      for i in 0..<(cnt2-1) {
      totalAcKw = totalAcKw + (jsonData.Outputs?.ACMonthly[i])!
      }
      self.avgMonthlyAcKw = Double(totalAcKw)/Double(cnt2)

      // prints value
      print("updated estimate: ", self.avgMonthlyAcKw)
      }

      } catch {
      print("error: (error.localizedDescription)")

      }
      }
      dataTask.resume()
      completion(self.avgMonthlyAcKw)
      }


      Calling Class:



       func estimate() {
      var estimatedSolarkWh:Double = 0.0
      let aPVClass = PVClass()
      aPVClass.estimateMonthlyACkW(areaSqFt: 100.0, completion: { (monthlyAckW) -> Void in

      estimatedSolarkWh = monthlyAckW
      self.view.setNeedsDisplay()
      })
      return
      }
      }


      When I call the function estimate() the estimateMonthlyACkW function in the other PVClass is executed but it returns after the calling estimate() function is executed. So even though in the called function the URLsession is executed, json is parsed, and value is printed correctly - the value never gets gets transferred to the completion handler and the value never comes back to calling class. How can I fix this?










      share|improve this question














      I am calling a funciton with completio=n handler from one calss to another class



      Called class:



      class PVClass
      {

      var avgMonthlyAcKw:Double = 0.0

      var jsonString:String!

      func estimateMonthlyACkW (areaSqFt:Float, completion: @escaping(Double) -> () ){

      var capacityStr:String = ""

      let estimatedCapacity = Float(areaSqFt/66.0)
      capacityStr = String(format: "%.2f", estimatedCapacity)

      // Build some Url string
      var urlString:String = "https://developer.nrel.gov/"
      urlString.append("&system_capacity=")
      urlString.append(capacityStr)

      let pvURL = URL(string: urlString)
      let dataTask = URLSession.shared.dataTask(with: pvURL!) { data, response, error in
      do {

      let _ = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers)
      self.jsonString = String(data: data!, encoding: .utf8)!
      print("JSON String:(String(describing: self.jsonString))")

      if self.jsonString != nil {
      let decoder = JSONDecoder()
      let jsonData = try decoder.decode(PVClass.Top.self, from: data!)

      // do some parsing here
      var totalAcKw: Double = 0.0
      let cnt2: Int = (jsonData.Outputs?.ACMonthly.count)!
      for i in 0..<(cnt2-1) {
      totalAcKw = totalAcKw + (jsonData.Outputs?.ACMonthly[i])!
      }
      self.avgMonthlyAcKw = Double(totalAcKw)/Double(cnt2)

      // prints value
      print("updated estimate: ", self.avgMonthlyAcKw)
      }

      } catch {
      print("error: (error.localizedDescription)")

      }
      }
      dataTask.resume()
      completion(self.avgMonthlyAcKw)
      }


      Calling Class:



       func estimate() {
      var estimatedSolarkWh:Double = 0.0
      let aPVClass = PVClass()
      aPVClass.estimateMonthlyACkW(areaSqFt: 100.0, completion: { (monthlyAckW) -> Void in

      estimatedSolarkWh = monthlyAckW
      self.view.setNeedsDisplay()
      })
      return
      }
      }


      When I call the function estimate() the estimateMonthlyACkW function in the other PVClass is executed but it returns after the calling estimate() function is executed. So even though in the called function the URLsession is executed, json is parsed, and value is printed correctly - the value never gets gets transferred to the completion handler and the value never comes back to calling class. How can I fix this?







      swift completionhandler






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Dec 29 '18 at 6:08









      vraovrao

      1662519




      1662519
























          1 Answer
          1






          active

          oldest

          votes


















          0














          You need to move completion(self.avgMonthlyAcKw) just after print statement like below:



             // prints value
          print("updated estimate: ", self.avgMonthlyAcKw)
          completion(self.avgMonthlyAcKw)


          Hope this will helps you :)






          share|improve this answer
























          • I did that and does not work. I dont know why

            – vrao
            Dec 29 '18 at 16:12











          • Updated comment: I did that the completion handler gets called I capture the return value in var estimatedSolarkWh. I make the assignment from the var estimatedSolarkWh to the UI, but the UI does not get updated . How to force the UI refresh based on the captured value?

            – vrao
            Dec 29 '18 at 16:40











          • Add UI stuff in DispatchQueue.main.async{ }

            – iVarun
            Dec 29 '18 at 16:43













          • @vrao did this work for you?

            – iVarun
            Dec 29 '18 at 16:53











          • Modified code still fails. DispatchQueue.main.async { [weak self] in guard case self = self else { return } print("monthlyAckW: ", monthlyAckW) self?.estimatedSolarkWh = Int(monthlyAckW * Double((12)/365 * (self?.numDays)!)) print("estimatedSolarkWh: ", self?.estimatedSolarkWh ?? 0) guard let val = self?.estimatedSolarkWh else { return } print("val: ", val) self?.estimatedSolarkWhLabel.text = String(val) self?.view.setNeedsDisplay()} })

            – vrao
            Dec 29 '18 at 16:56











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53967157%2fswift-calling-completion-handler-in-from-another-file-fails%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          0














          You need to move completion(self.avgMonthlyAcKw) just after print statement like below:



             // prints value
          print("updated estimate: ", self.avgMonthlyAcKw)
          completion(self.avgMonthlyAcKw)


          Hope this will helps you :)






          share|improve this answer
























          • I did that and does not work. I dont know why

            – vrao
            Dec 29 '18 at 16:12











          • Updated comment: I did that the completion handler gets called I capture the return value in var estimatedSolarkWh. I make the assignment from the var estimatedSolarkWh to the UI, but the UI does not get updated . How to force the UI refresh based on the captured value?

            – vrao
            Dec 29 '18 at 16:40











          • Add UI stuff in DispatchQueue.main.async{ }

            – iVarun
            Dec 29 '18 at 16:43













          • @vrao did this work for you?

            – iVarun
            Dec 29 '18 at 16:53











          • Modified code still fails. DispatchQueue.main.async { [weak self] in guard case self = self else { return } print("monthlyAckW: ", monthlyAckW) self?.estimatedSolarkWh = Int(monthlyAckW * Double((12)/365 * (self?.numDays)!)) print("estimatedSolarkWh: ", self?.estimatedSolarkWh ?? 0) guard let val = self?.estimatedSolarkWh else { return } print("val: ", val) self?.estimatedSolarkWhLabel.text = String(val) self?.view.setNeedsDisplay()} })

            – vrao
            Dec 29 '18 at 16:56
















          0














          You need to move completion(self.avgMonthlyAcKw) just after print statement like below:



             // prints value
          print("updated estimate: ", self.avgMonthlyAcKw)
          completion(self.avgMonthlyAcKw)


          Hope this will helps you :)






          share|improve this answer
























          • I did that and does not work. I dont know why

            – vrao
            Dec 29 '18 at 16:12











          • Updated comment: I did that the completion handler gets called I capture the return value in var estimatedSolarkWh. I make the assignment from the var estimatedSolarkWh to the UI, but the UI does not get updated . How to force the UI refresh based on the captured value?

            – vrao
            Dec 29 '18 at 16:40











          • Add UI stuff in DispatchQueue.main.async{ }

            – iVarun
            Dec 29 '18 at 16:43













          • @vrao did this work for you?

            – iVarun
            Dec 29 '18 at 16:53











          • Modified code still fails. DispatchQueue.main.async { [weak self] in guard case self = self else { return } print("monthlyAckW: ", monthlyAckW) self?.estimatedSolarkWh = Int(monthlyAckW * Double((12)/365 * (self?.numDays)!)) print("estimatedSolarkWh: ", self?.estimatedSolarkWh ?? 0) guard let val = self?.estimatedSolarkWh else { return } print("val: ", val) self?.estimatedSolarkWhLabel.text = String(val) self?.view.setNeedsDisplay()} })

            – vrao
            Dec 29 '18 at 16:56














          0












          0








          0







          You need to move completion(self.avgMonthlyAcKw) just after print statement like below:



             // prints value
          print("updated estimate: ", self.avgMonthlyAcKw)
          completion(self.avgMonthlyAcKw)


          Hope this will helps you :)






          share|improve this answer













          You need to move completion(self.avgMonthlyAcKw) just after print statement like below:



             // prints value
          print("updated estimate: ", self.avgMonthlyAcKw)
          completion(self.avgMonthlyAcKw)


          Hope this will helps you :)







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 29 '18 at 6:15









          iVaruniVarun

          3,66421325




          3,66421325













          • I did that and does not work. I dont know why

            – vrao
            Dec 29 '18 at 16:12











          • Updated comment: I did that the completion handler gets called I capture the return value in var estimatedSolarkWh. I make the assignment from the var estimatedSolarkWh to the UI, but the UI does not get updated . How to force the UI refresh based on the captured value?

            – vrao
            Dec 29 '18 at 16:40











          • Add UI stuff in DispatchQueue.main.async{ }

            – iVarun
            Dec 29 '18 at 16:43













          • @vrao did this work for you?

            – iVarun
            Dec 29 '18 at 16:53











          • Modified code still fails. DispatchQueue.main.async { [weak self] in guard case self = self else { return } print("monthlyAckW: ", monthlyAckW) self?.estimatedSolarkWh = Int(monthlyAckW * Double((12)/365 * (self?.numDays)!)) print("estimatedSolarkWh: ", self?.estimatedSolarkWh ?? 0) guard let val = self?.estimatedSolarkWh else { return } print("val: ", val) self?.estimatedSolarkWhLabel.text = String(val) self?.view.setNeedsDisplay()} })

            – vrao
            Dec 29 '18 at 16:56



















          • I did that and does not work. I dont know why

            – vrao
            Dec 29 '18 at 16:12











          • Updated comment: I did that the completion handler gets called I capture the return value in var estimatedSolarkWh. I make the assignment from the var estimatedSolarkWh to the UI, but the UI does not get updated . How to force the UI refresh based on the captured value?

            – vrao
            Dec 29 '18 at 16:40











          • Add UI stuff in DispatchQueue.main.async{ }

            – iVarun
            Dec 29 '18 at 16:43













          • @vrao did this work for you?

            – iVarun
            Dec 29 '18 at 16:53











          • Modified code still fails. DispatchQueue.main.async { [weak self] in guard case self = self else { return } print("monthlyAckW: ", monthlyAckW) self?.estimatedSolarkWh = Int(monthlyAckW * Double((12)/365 * (self?.numDays)!)) print("estimatedSolarkWh: ", self?.estimatedSolarkWh ?? 0) guard let val = self?.estimatedSolarkWh else { return } print("val: ", val) self?.estimatedSolarkWhLabel.text = String(val) self?.view.setNeedsDisplay()} })

            – vrao
            Dec 29 '18 at 16:56

















          I did that and does not work. I dont know why

          – vrao
          Dec 29 '18 at 16:12





          I did that and does not work. I dont know why

          – vrao
          Dec 29 '18 at 16:12













          Updated comment: I did that the completion handler gets called I capture the return value in var estimatedSolarkWh. I make the assignment from the var estimatedSolarkWh to the UI, but the UI does not get updated . How to force the UI refresh based on the captured value?

          – vrao
          Dec 29 '18 at 16:40





          Updated comment: I did that the completion handler gets called I capture the return value in var estimatedSolarkWh. I make the assignment from the var estimatedSolarkWh to the UI, but the UI does not get updated . How to force the UI refresh based on the captured value?

          – vrao
          Dec 29 '18 at 16:40













          Add UI stuff in DispatchQueue.main.async{ }

          – iVarun
          Dec 29 '18 at 16:43







          Add UI stuff in DispatchQueue.main.async{ }

          – iVarun
          Dec 29 '18 at 16:43















          @vrao did this work for you?

          – iVarun
          Dec 29 '18 at 16:53





          @vrao did this work for you?

          – iVarun
          Dec 29 '18 at 16:53













          Modified code still fails. DispatchQueue.main.async { [weak self] in guard case self = self else { return } print("monthlyAckW: ", monthlyAckW) self?.estimatedSolarkWh = Int(monthlyAckW * Double((12)/365 * (self?.numDays)!)) print("estimatedSolarkWh: ", self?.estimatedSolarkWh ?? 0) guard let val = self?.estimatedSolarkWh else { return } print("val: ", val) self?.estimatedSolarkWhLabel.text = String(val) self?.view.setNeedsDisplay()} })

          – vrao
          Dec 29 '18 at 16:56





          Modified code still fails. DispatchQueue.main.async { [weak self] in guard case self = self else { return } print("monthlyAckW: ", monthlyAckW) self?.estimatedSolarkWh = Int(monthlyAckW * Double((12)/365 * (self?.numDays)!)) print("estimatedSolarkWh: ", self?.estimatedSolarkWh ?? 0) guard let val = self?.estimatedSolarkWh else { return } print("val: ", val) self?.estimatedSolarkWhLabel.text = String(val) self?.view.setNeedsDisplay()} })

          – vrao
          Dec 29 '18 at 16:56


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53967157%2fswift-calling-completion-handler-in-from-another-file-fails%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Monofisismo

          Angular Downloading a file using contenturl with Basic Authentication

          Olmecas