Bird
Raised Fist0
iOS Swiftmobile~20 mins

URLSession basics in iOS Swift - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Simple Fetch Screen
This screen fetches text data from a URL and shows it on screen.
Target UI
-------------------------
| Simple Fetch Screen    |
|-----------------------|
| [Fetch Data]          |
|                       |
|                       |
|                       |
|                       |
|                       |
|                       |
-------------------------
Add a button labeled 'Fetch Data'.
When tapped, fetch text from https://www.example.com using URLSession.
Show the fetched text below the button.
Show a loading indicator while fetching.
Show an error message if fetch fails.
Starter Code
iOS Swift
import SwiftUI

struct SimpleFetchScreen: View {
    @State private var fetchedText = ""
    @State private var isLoading = false
    @State private var errorMessage = ""

    var body: some View {
        VStack(spacing: 20) {
            Button("Fetch Data") {
                // TODO: Add fetch code here
            }
            if isLoading {
                ProgressView()
            }
            if !errorMessage.isEmpty {
                Text(errorMessage).foregroundColor(.red)
            }
            ScrollView {
                Text(fetchedText)
                    .padding()
            }
            Spacer()
        }
        .padding()
        .navigationTitle("Simple Fetch Screen")
    }
}

struct SimpleFetchScreen_Previews: PreviewProvider {
    static var previews: some View {
        SimpleFetchScreen()
    }
}
Task 1
Task 2
Task 3
Task 4
Task 5
Solution
iOS Swift
import SwiftUI

struct SimpleFetchScreen: View {
    @State private var fetchedText = ""
    @State private var isLoading = false
    @State private var errorMessage = ""

    var body: some View {
        VStack(spacing: 20) {
            Button("Fetch Data") {
                fetchData()
            }
            if isLoading {
                ProgressView()
            }
            if !errorMessage.isEmpty {
                Text(errorMessage).foregroundColor(.red)
            }
            ScrollView {
                Text(fetchedText)
                    .padding()
            }
            Spacer()
        }
        .padding()
        .navigationTitle("Simple Fetch Screen")
    }

    func fetchData() {
        isLoading = true
        errorMessage = ""
        fetchedText = ""
        guard let url = URL(string: "https://www.example.com") else {
            errorMessage = "Invalid URL."
            isLoading = false
            return
        }
        URLSession.shared.dataTask(with: url) { data, response, error in
            DispatchQueue.main.async {
                isLoading = false
                if let error = error {
                    errorMessage = "Error: \(error.localizedDescription)"
                    return
                }
                guard let data = data, let text = String(data: data, encoding: .utf8) else {
                    errorMessage = "Failed to load data."
                    return
                }
                fetchedText = text
            }
        }.resume()
    }
}

struct SimpleFetchScreen_Previews: PreviewProvider {
    static var previews: some View {
        SimpleFetchScreen()
    }
}

This solution uses URLSession.shared.dataTask to fetch data from the given URL asynchronously. We set isLoading to true before starting the fetch to show a loading spinner. When the fetch completes, we switch back to the main thread using DispatchQueue.main.async to update the UI states safely.

If there is an error, we show a red error message. If the data is successfully fetched, we convert it to a string and display it below the button. This simple pattern is the foundation for network calls in iOS apps.

Final Result
Completed Screen
-------------------------
| Simple Fetch Screen    |
|-----------------------|
| [Fetch Data]          |
|                       |
|    (loading spinner)   |
|                       |
| <fetched text shown>  |
|                       |
|                       |
-------------------------
User taps 'Fetch Data' button.
Loading spinner appears while data loads.
Fetched text from https://www.example.com appears below the button.
If fetch fails, a red error message appears instead.
Stretch Goal
Add a refresh button in the navigation bar to fetch data again.
💡 Hint
Use .toolbar modifier with a Button that calls fetchData() when tapped.

Practice

(1/5)
1. What is the main purpose of URLSession in Swift?
easy
A. To create user interface elements
B. To handle network requests and communicate with the internet
C. To manage local file storage
D. To perform mathematical calculations

Solution

  1. Step 1: Understand URLSession role

    URLSession is designed to manage network tasks like downloading or uploading data.
  2. Step 2: Compare with other options

    Creating UI, managing files, or math are unrelated to URLSession.
  3. Final Answer:

    To handle network requests and communicate with the internet -> Option B
  4. Quick Check:

    URLSession = network communication [OK]
Hint: Remember URLSession is for internet tasks only [OK]
Common Mistakes:
  • Confusing URLSession with UI components
  • Thinking URLSession manages local files
  • Assuming URLSession does math operations
2. Which of the following is the correct way to create a data task with URLSession?
easy
A. let task = URLSession.dataTask(url) { data, error in }
B. let task = URLSession.shared.dataTask(url)
C. let task = URLSession.shared.downloadTask(url)
D. let task = URLSession.shared.dataTask(with: url) { data, response, error in }

Solution

  1. Step 1: Check correct method signature

    The correct method is dataTask(with:completionHandler:) on URLSession.shared.
  2. Step 2: Validate options

    let task = URLSession.shared.dataTask(with: url) { data, response, error in } matches the correct syntax with closure parameters data, response, error. Others have wrong method names or missing parameters.
  3. Final Answer:

    let task = URLSession.shared.dataTask(with: url) { data, response, error in } -> Option D
  4. Quick Check:

    Correct dataTask syntax = let task = URLSession.shared.dataTask(with: url) { data, response, error in } [OK]
Hint: Look for shared session and closure with three parameters [OK]
Common Mistakes:
  • Using dataTask without shared session
  • Missing response parameter in closure
  • Using downloadTask instead of dataTask
3. What will the following code print if the network request succeeds and returns data?
let url = URL(string: "https://example.com")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
  if let data = data {
    print("Data received: \(data.count) bytes")
  } else {
    print("No data")
  }
}
task.resume()
medium
A. Data received: [number] bytes
B. Syntax error
C. No data
D. Data received: 0 bytes

Solution

  1. Step 1: Analyze dataTask completion handler

    If the request succeeds, data contains the downloaded bytes, so data.count is a positive number.
  2. Step 2: Check print statements

    The code prints "Data received: \(data.count) bytes" if data exists, otherwise "No data".
  3. Final Answer:

    Data received: [number] bytes -> Option A
  4. Quick Check:

    Successful dataTask prints data size [OK]
Hint: If data exists, print shows byte count, not zero [OK]
Common Mistakes:
  • Assuming data is always nil
  • Confusing data.count with zero
  • Thinking code has syntax errors
4. Identify the error in this code snippet:
let url = URL(string: "https://example.com")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
  if let data = data {
    DispatchQueue.main.async {
      print("Data length: \(data.count)")
    }
  }
}
// Missing task.resume()
medium
A. Missing call to task.resume() to start the request
B. Incorrect URL string format
C. DispatchQueue.main.async should not be used here
D. Closure parameters are incorrect

Solution

  1. Step 1: Check for starting the task

    URLSession tasks are created suspended. You must call task.resume() to start the network request.
  2. Step 2: Validate other parts

    URL string is valid, closure parameters are correct, and updating UI on main thread is good practice.
  3. Final Answer:

    Missing call to task.resume() to start the request -> Option A
  4. Quick Check:

    Always call resume() to run URLSession tasks [OK]
Hint: Remember to call resume() after creating a data task [OK]
Common Mistakes:
  • Forgetting to call task.resume()
  • Misusing DispatchQueue for UI updates
  • Incorrect closure parameters
5. You want to fetch JSON data from a URL and update a label with the result. Which approach correctly ensures the UI updates happen on the main thread?
let url = URL(string: "https://api.example.com/data")!
let task = URLSession.shared.dataTask(with: url) { data, response, error in
  guard let data = data else { return }
  let text = String(data: data, encoding: .utf8) ?? "No data"
  // Update label here
}
task.resume()
Options:
hard
A. Call label.text = text before task.resume()
B. Update label.text directly inside the closure without DispatchQueue
C. Use DispatchQueue.main.async { label.text = text } inside the closure
D. Use a background thread to update label.text

Solution

  1. Step 1: Understand threading in URLSession

    The completion handler runs on a background thread, so UI updates must be dispatched to the main thread.
  2. Step 2: Check each option

    Use DispatchQueue.main.async { label.text = text } inside the closure correctly uses DispatchQueue.main.async to update the label safely. Update label.text directly inside the closure without DispatchQueue risks UI bugs. Call label.text = text before task.resume() updates UI before data is fetched. Use a background thread to update label.text wrongly uses background thread for UI.
  3. Final Answer:

    Use DispatchQueue.main.async { label.text = text } inside the closure -> Option C
  4. Quick Check:

    UI updates on main thread = Use DispatchQueue.main.async { label.text = text } inside the closure [OK]
Hint: Always update UI on main thread with DispatchQueue.main.async [OK]
Common Mistakes:
  • Updating UI on background thread
  • Updating UI before data arrives
  • Ignoring thread safety for UI changes
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard