title: Thread synchronization with loading splash
body: <p>I have this code:</p>
  
  <pre><code>struct ServerConnect {
      enum Result&lt;T&gt; {
          case succes(T)
          case error(String)
      }
  
      typealias completionHandler = (Result&lt;Data &gt;) -&gt; ()
  
      func getJsonFromServer(parameters: String, completion: @escaping completionHandler) {
          let fullUrlString = ApiConstans.fullPath + parameters
          guard let url = URL(string: fullUrlString) else {
              return completion(.error("ServerConnect01 - Error 100: Problem with url "))
          }
  
          URLSession.shared.dataTask(with: url) {  (data, response, error) in
              guard error == nil else {
                  return completion(.error("ServerConnect02 - Error 101: Problem with data "))
              }
  
              guard let data = data else {
                  return completion(.error("ServerConnect03 - Error 103: Problem with data "))
              }
  
              return completion(.succes(data))
              }.resume()
      }
  
      func checkUsersLogin(login: String?, password: String?, completion: @escaping completionHandler) {
          self.getJsonFromServer(parameters: "?action=LOGOWANIE&amp;login=\(login!)&amp;password=\(password!)", completion: completion)
      }
  
      func getJsonProducts( completion: @escaping completionHandler) {
          self.getJsonFromServer(parameters: "?action=GET_PRODUCTS&amp;lang=" + (AppGlobalManager.sharedManager.loggedUser?.selectedLanguage)! + "&amp;region=" + String((AppGlobalManager.sharedManager.loggedUser?.selectedRegion)!), completion: completion)
      }
  
      func getJsonRegions( completion: @escaping completionHandler) {
          self.getJsonFromServer(parameters: "?action=GET_REGIONS&amp;lang=" + (AppGlobalManager.sharedManager.loggedUser?.selectedLanguage)!, completion: completion)
      }
  
      func getJsonNews( completion: @escaping completionHandler) {
          self.getJsonFromServer(parameters: "?action=GET_KARTY_AKTUALNOSCI&amp;lang=" + (AppGlobalManager.sharedManager.loggedUser?.selectedLanguage)! + "&amp;region=" + String((AppGlobalManager.sharedManager.loggedUser?.selectedRegion)!)+"&amp;userType=" + (AppGlobalManager.sharedManager.loggedUser?.userType)! + "&amp;iOS", completion: completion)
      }
  }
              cms.getJsonProducts(completion: { (data) in
                      switch data {
                      case .succes(let data):
                          DispatchQueue.main.async {
                              EZLoadingActivity.show("LoadingMessage1".localized(), disableUI: true)
                          }
                          self.saveJsonFileToTheDiskProducts(path: (AppGlobalManager.sharedManager.loggedUser?.selectedLanguage)! + "/json",  downloadData: data)
                      case .error(let error):
                          self.errorLoginMessage(txt: "MainView - Error 101: Configuration files can not be created. \(error)", title: "Blad".localized())
                          break
                      }
                  })
  
                  cms.getJsonNews( completion: { (data) in
                      switch data {
                      case .succes(let data):
                          DispatchQueue.main.async {
                              EZLoadingActivity.show("LoadingMessage2".localized(), disableUI: true)
                          }
                          self.saveJsonFileToTheDiskNews(path: (AppGlobalManager.sharedManager.loggedUser?.selectedLanguage)! + "/json",  downloadData: data)
                      case .error(let error):
                          self.errorLoginMessage(txt: "MainView - Error 105: News files can not be created. \(error)", title: "Blad".localized())
                          break
                      }
                  })
  
                  cms.getJsonRegions(completion: { (data) in
                      switch data {
                      case .succes(let data):
                          DispatchQueue.main.async {
                              EZLoadingActivity.show("LoadingMessage3".localized(), disableUI: true)
                          }
                          self.saveJsonFileToTheDiskRegions(path: (AppGlobalManager.sharedManager.loggedUser?.selectedLanguage)! + "/json",  downloadData: data)
                      case .error(let error):
                          self.errorLoginMessage(txt: "MainView - Error 106: Regions files can not be created. \(error)", title: "Blad".localized())
                          break
                      }
                  })
  </code></pre>
  
  <p>In each function, displaying the loader:</p>
  
  <pre><code>DispatchQueue.main.async { EZLoadingActivity.show("LoadingMessage1".localized(), disableUI: true)
  }
  </code></pre>
  
  <p>I would like that after all three threads have been done (cms.getJsonProducts, cms.getJsonRegions, cms.getJsonNews) , the loader has been hidden. How to do it? How do you synchronize these 3 threads to hide this loader?</p>
  
  <p>Does anyone know how to do it?</p>