title: Need help to make iOS 14 Widget show content from from REST api
body: <p>The original question is at Apple forum but no one can help.
  <a href="https://developer.apple.com/forums/thread/654967?answerId=622833022#622833022" rel="noreferrer">https://developer.apple.com/forums/thread/654967?answerId=622833022#622833022</a></p>
  <p>I decided to ask on SO.</p>
  <h1>Problem</h1>
  <p>I'm developing a widget extension that show content from REST api.
  It show the updated following stock info.</p>
  <p><a href="https://i.stack.imgur.com/U2ay1.jpg" rel="noreferrer"><img src="https://i.stack.imgur.com/U2ay1.jpg" alt="My widget UI" /></a></p>
  <p><a href="https://developer.apple.com/videos/play/wwdc2020/10036" rel="noreferrer">Widgets Code-along, part 3: Advancing timelines</a> doesn't help me.</p>
  <p>Investigation brings me a though &quot;it is a bug of iOS beta&quot;:</p>
  <pre><code>public func timeline(
      for configuration: ConfigurationIntent,
      with context: Context,
      completion: @escaping (Timeline&lt;Entry&gt;) -&gt; ()
    ) {
      print(&quot;Provider.timeline: &quot;)
  
      var entries: [SimpleEntry] = []
  
      let currentDate = Date()
      entries.append(SimpleEntry(
        date: Calendar.current.date(byAdding: .second, value: 15, to: currentDate)!,
        configuration: configuration
      ))
      
      let timeline = Timeline(entries: entries, policy: reloadPolicy)
  
      completion(timeline)
    }
  </code></pre>
  <p>Above code print <code>Provider.timeline: </code> 14-&gt;19 times in just 1 second.</p>
  <hr />
  <p>Here's my code to work with network request without success:</p>
  <pre><code>public func timeline(
      for configuration: ConfigurationIntent,
      with context: Context,
      completion: @escaping (Timeline&lt;Entry&gt;) -&gt; ()
    ) {
      print(&quot;Provider.timeline: &quot;)
      
      fetchStocks { (stocks: [Stock], error: Bool) in
        print(&quot;fetchStocks: stocks: &quot;, stocks) 
        completion(getTimeLineFromStocks(stocks: stocks, for: configuration, with: context, reloadPolicy: .atEnd))
      }
  }
  
  func getTimeLineFromStocks(
      stocks: [Stock],
      for configuration: ConfigurationIntent,
      with context: Context,
      reloadPolicy: TimelineReloadPolicy
    ) -&gt; Timeline&lt;Entry&gt; {
      var entries: [SimpleEntry] = []
      let currentDate = Date()
      entries.append(SimpleEntry(
        date: Calendar.current.date(byAdding: .second, value: 15, to: currentDate)!,
        configuration: configuration,
        stocks: stocks
      ))
      
      let timeline = Timeline(entries: entries, policy: reloadPolicy)
      
      return timeline
    }
  
  
    func fetchStocks(completion: @escaping ([Stock], Bool) -&gt; Void) {
      // Fetch stocks info from API    
      myStockService.getSearchResults(searchTerm: &quot;FIT&quot;, perPage: 5) { results, errorMessage in
        if !errorMessage.isEmpty {
          print(&quot;--&gt; Search error: &quot; + errorMessage)
          completion([], true)
        } else if results == nil {
          print(&quot;--&gt; Search result with ERROR: nil results&quot;)
          completion([], true)
        } else {
          print(&quot;--&gt; searchResults: &quot;, results)
          completion(results!, false)
          // reloadTimeline()
        }
      }
    }
  
  
  
  // ------- MyStockService.swift -------
  // If I set breakpoint I can see the list of stocks
  func getSearchResults(searchTerm: String,  perPage: Int, completion: @escaping QueryResult) {
      // 1
      dataTask?.cancel()
      
      // 2
      if var urlComponents = URLComponents(string: &quot;https://****************/my-stocks&quot;) {
        urlComponents.query = &quot;foo=bar&quot;
  
        // 3
        guard let url = urlComponents.url else {
          return
        }
      
        // 4
        dataTask = defaultSession.dataTask(with: url) { [weak self] data, response, error in
          defer {
            self?.dataTask = nil
          }
          
          // 5
          if let error = error {
            self?.errorMessage += &quot;DataTask error: &quot; + error.localizedDescription + &quot;\n&quot;
          } else if
            let data = data,
            let response = response as? HTTPURLResponse,
            response.statusCode == 200 {
            
              // update the: self?.resultItems, self?.errorMessage
              self?.updateSearchResults(data, perPage: perPage)
            
            // 6
            DispatchQueue.main.async {
              completion(self?.resultItems, self?.errorMessage ?? &quot;&quot;)
            }
          }
        }
        
        // 7
        dataTask?.resume()
      }
    }
  
    func updateSearchResults(....) {
       ... This fn convert data to [Stock] and assign it to resultItems 
    }
  
  </code></pre>
  <p>I got the log:</p>
  <pre><code>Provider.timeline: 
  Provider.timeline: 
  Provider.timeline: 
  Provider.timeline: 
  Provider.timeline: 
  Provider.timeline: 
  Provider.timeline: 
  --&gt; Search error: DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  
  fetchStocks: stocks:  []
  --&gt; Search error: DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  
  fetchStocks: stocks:  []
  2020-07-23 18:06:38.131476+0700 my-widgetExtension[5315:1272323] libMobileGestalt MobileGestaltCache.c:166: Cache loaded with 4563 pre-cached in CacheData and 53 items in CacheExtra.
  --&gt; Search error: DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  
  fetchStocks: stocks:  []
  Provider.timeline: 
  Provider.timeline: 
  Provider.timeline: 
  --&gt; Search error: DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  
  fetchStocks: stocks:  []
  --&gt; Search error: DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  DataTask error: cancelled
  
  fetchStocks: stocks:  []
  2020-07-23 18:06:39.751035+0700 my-widgetExtension[5315:1272388] [connection] nw_resolver_start_query_timer_block_invoke [C1] Query fired: did not receive all answers in time for api-t19.24hmoney.vn:443
  2020-07-23 18:06:51.891582+0700 my-widgetExtension[5315:1272323] [widget] No intent in timeline(for:with:completion:)
  </code></pre>
  <p>Above code doesn't update or show Stock to the widget UI, it sometimes has some strange crashed.</p>
  <p>Anyone can help me to make it work?</p>