0

I am getting an error which seems to be more of that the request did not go through correctly. I say that because when I reload the app it works fine

The part of the code causing the error is:

 let post = try! JSONDecoder().decode(Post.self, from: data!)
             

the error is:

Fatal error: Unexpectedly found nil while unwrapping an Optional value

the full code:

func getShows(station:String,completion: @escaping ([Program]) -> ()) {
        guard let url = URL(string: "https://api.drn1.com.au/api-access/programs/\(station)") else { return }
          
          URLSession.shared.dataTask(with: url) { (data, _, _) in
              // Based on the updated structs, you would no
              // longer be decoding an array
              let post = try! JSONDecoder().decode(Post.self, from: data!)
              DispatchQueue.main.async{
                  // The array is stored under programs now
                  completion(post.programs)
              }              
          }
      .resume()
      }

Is there away instead of crashing the app, it just tries to run again?

RussellHarrower
  • 6,470
  • 21
  • 102
  • 204
  • Does this answer your question? [What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?](https://stackoverflow.com/questions/32170456/what-does-fatal-error-unexpectedly-found-nil-while-unwrapping-an-optional-valu) – EmilioPelaez May 02 '21 at 13:04
  • @EmilioPelaez Not really, because I am asking how could I re-run the code as it is correct and does work - it seems its a network issue that causes the issue. – RussellHarrower May 02 '21 at 13:05
  • You're ignoring the `error` parameter by using an underscore and you're bypassing Swift's safety features and ignoring useful debug information by using `try!` and `data!`. The answer I linked has an incredibly comprehensive answer and information on how to correctly handle optionals, which you're not doing because your app is crashing. – EmilioPelaez May 02 '21 at 14:15

2 Answers2

1

(Answering your question in the last sentence)

Yes, don't force-unwrap "data", don't force-resolve the "try". Doing either will result in a crash if either data is null (which, for network calls is a reasonable expectation), or if the JSONDecoder cannot parse the data correctly.

How often you call this method is up to you (e.g., as soon as a view is loaded).

`

      URLSession.shared.dataTask(with: url) { (data, response, error) in
          guard let actualData = data, 
                let urlResponse = response as? URLResponse,
                urlResponse.status == 200 //or whatever
                else { return } 


          if let post = try? JSONDecoder().decode(Post.self, from:actualData){
              completion(post.programs)  
          }         
      }
  .resume()
  }`
a_hausb
  • 161
  • 1
  • 9
0

If your app is for iOS 13+, and you can use Combine, then your method could be rewritten like this

/// add this var somewhere in your class
var subscriptions: Set<AnyCancellable> = .init()

func getShows(station: String, retries: Int = 3, completion: @escaping ([Program]) -> Void) {
    guard let url = URL(string: "https://api.drn1.com.au/api-access/programs/\(station)") else { return }

    let result = URLSession.shared.dataTaskPublisher(for: url)
        .map { $0.0 }
        .decode(type: Post.self, decoder: JSONDecoder())
        .retry(retries)

    result.sink { _ in } receiveValue: { post in
        completion(post.programs)
    }
    .store(in: &subscriptions)
}
Alex Antonyuk
  • 161
  • 1
  • 8