Bird
Raised Fist0
iOS Swiftmobile~20 mins

Image loading from URL in iOS Swift - Mini App: Build & Ship

Choose your learning style10 modes available
Build: Image Loader
This screen loads and displays an image from a web URL. It shows a placeholder while loading and an error message if loading fails.
Target UI
-------------------------
|       Image Loader     |
|-----------------------|
|  [Placeholder Image]   |
|                       |
|  Loading image...      |
|                       |
|-----------------------|
|       Reload Button    |
-------------------------
Display an image loaded from a given URL.
Show a placeholder image while the image is loading.
Show a text message if the image fails to load.
Add a button labeled 'Reload' to retry loading the image.
Starter Code
iOS Swift
import SwiftUI

struct ImageLoaderView: View {
    // TODO: Add state variables here

    var body: some View {
        VStack {
            // TODO: Add image view here

            // TODO: Add status text here

            Button("Reload") {
                // TODO: Add reload action here
            }
            .padding()
        }
        .padding()
        .onAppear {
            // TODO: Load image when view appears
        }
    }
}

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

struct ImageLoaderView: View {
    @State private var image: UIImage? = nil
    @State private var isLoading = false
    @State private var errorMessage: String? = nil

    let imageUrl = URL(string: "https://picsum.photos/300")!

    var body: some View {
        VStack(spacing: 20) {
            if let uiImage = image {
                Image(uiImage: uiImage)
                    .resizable()
                    .scaledToFit()
                    .frame(maxWidth: 300, maxHeight: 300)
                    .cornerRadius(8)
                    .accessibilityLabel(Text("Loaded image from internet"))
            } else if isLoading {
                Image(systemName: "photo")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 100, height: 100)
                    .foregroundColor(.gray)
                    .accessibilityHidden(true)
                Text("Loading image...")
                    .accessibilityLabel(Text("Loading image"))
            } else if let error = errorMessage {
                Image(systemName: "exclamationmark.triangle")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 80, height: 80)
                    .foregroundColor(.red)
                    .accessibilityHidden(true)
                Text(error)
                    .foregroundColor(.red)
                    .accessibilityLabel(Text("Error loading image"))
            } else {
                Image(systemName: "photo")
                    .resizable()
                    .scaledToFit()
                    .frame(width: 100, height: 100)
                    .foregroundColor(.gray)
                    .accessibilityHidden(true)
                Text("No image loaded")
                    .accessibilityLabel(Text("No image loaded"))
            }

            Button("Reload") {
                loadImage()
            }
            .padding()
            .accessibilityLabel(Text("Reload image button"))
        }
        .padding()
        .onAppear {
            loadImage()
        }
    }

    func loadImage() {
        isLoading = true
        errorMessage = nil
        image = nil

        let task = URLSession.shared.dataTask(with: imageUrl) { data, response, error in
            DispatchQueue.main.async {
                isLoading = false
                if let error = error {
                    errorMessage = "Failed to load image: \(error.localizedDescription)"
                    return
                }
                guard let data = data, let uiImage = UIImage(data: data) else {
                    errorMessage = "Invalid image data"
                    return
                }
                image = uiImage
            }
        }
        task.resume()
    }
}

struct ImageLoaderView_Previews: PreviewProvider {
    static var previews: some View {
        ImageLoaderView()
    }
}

This SwiftUI view uses @State variables to track the image, loading state, and error message. When the view appears, it calls loadImage() which starts a URLSession data task to fetch the image data from the URL.

While loading, it shows a placeholder system image and a loading text. If loading fails, it shows an error icon and message. When the image loads successfully, it displays the image with a nice corner radius.

The Reload button calls loadImage() again to retry loading the image. Accessibility labels are added for screen readers. The UI is simple and responsive, showing clear states for loading, success, and error.

Final Result
Completed Screen
-------------------------
|       Image Loader     |
|-----------------------|
|   [Loaded Image]       |
|                       |
|                       |
|                       |
|-----------------------|
|       Reload Button    |
-------------------------
When the screen appears, the app starts loading the image from the URL.
While loading, a placeholder icon and 'Loading image...' text show.
If loading succeeds, the image appears in the center.
If loading fails, an error icon and message appear instead.
Tapping the 'Reload' button retries loading the image.
Stretch Goal
Add a progress indicator (spinner) while the image is loading.
💡 Hint
Use SwiftUI's ProgressView inside the loading state to show a spinner.

Practice

(1/5)
1. What is the main purpose of using URLSession when loading an image from a URL in Swift?
easy
A. To download data asynchronously from the internet
B. To display the image directly on the screen
C. To create a new UIImageView
D. To convert image data into a string

Solution

  1. Step 1: Understand URLSession's role

    URLSession is used to perform network tasks like downloading data asynchronously, so the app doesn't freeze.
  2. Step 2: Identify what happens when loading images

    When loading an image from a URL, URLSession downloads the image data in the background.
  3. Final Answer:

    To download data asynchronously from the internet -> Option A
  4. Quick Check:

    URLSession downloads data asynchronously [OK]
Hint: URLSession downloads data without blocking UI [OK]
Common Mistakes:
  • Thinking URLSession displays images directly
  • Confusing URLSession with UI components
  • Assuming URLSession converts data to images
2. Which of the following Swift code snippets correctly creates a URL from a string to load an image?
easy
A. let url = URL.create("https://example.com/image.png")
B. let url = URL("https://example.com/image.png")
C. let url = URL(string: "https://example.com/image.png")
D. let url = URL.load("https://example.com/image.png")

Solution

  1. Step 1: Recall URL initialization syntax

    The correct way to create a URL from a string is using the initializer URL(string:).
  2. Step 2: Check each option

    Only let url = URL(string: "https://example.com/image.png") uses the correct initializer syntax. Others are invalid or do not exist.
  3. Final Answer:

    let url = URL(string: "https://example.com/image.png") -> Option C
  4. Quick Check:

    URL(string:) creates URL from string [OK]
Hint: Use URL(string:) to create URLs from strings [OK]
Common Mistakes:
  • Using URL() without parameter label
  • Using non-existent URL methods
  • Forgetting to unwrap optional URL
3. Given the code below, what will be printed if the image data is successfully downloaded and converted?
let url = URL(string: "https://example.com/image.png")!
URLSession.shared.dataTask(with: url) { data, response, error in
  if let data = data, let image = UIImage(data: data) {
    print("Image loaded successfully")
  } else {
    print("Failed to load image")
  }
}.resume()
medium
A. Image loaded successfully
B. Failed to load image
C. Syntax error
D. No output

Solution

  1. Step 1: Analyze the dataTask closure

    The closure checks if data exists and can be converted to UIImage. If yes, it prints success.
  2. Step 2: Consider successful download scenario

    If the image data downloads correctly, the condition is true and prints "Image loaded successfully".
  3. Final Answer:

    Image loaded successfully -> Option A
  4. Quick Check:

    Successful data and UIImage means success message [OK]
Hint: Check if data and UIImage init succeed for success [OK]
Common Mistakes:
  • Assuming print runs on main thread
  • Confusing error with data presence
  • Ignoring optional unwrapping
4. Identify the error in the following Swift code for loading an image from a URL:
let url = URL(string: "https://example.com/image.png")
URLSession.shared.dataTask(with: url!) { data, response, error in
  let image = UIImage(data: data!)
  imageView.image = image
}.resume()
medium
A. URL is not unwrapped safely
B. UIImage cannot be created from data
C. Missing call to resume()
D. Updating UI on background thread

Solution

  1. Step 1: Check thread usage for UI update

    UI updates must happen on the main thread, but here imageView.image is set inside the background thread closure.
  2. Step 2: Confirm other parts

    URL is force unwrapped (not safe but not the main error here), resume() is called, and UIImage creation is valid if data exists.
  3. Final Answer:

    Updating UI on background thread -> Option D
  4. Quick Check:

    UI updates must be on main thread [OK]
Hint: Always update UI on main thread after data task [OK]
Common Mistakes:
  • Forgetting DispatchQueue.main.async for UI
  • Force unwrapping optionals unsafely
  • Not calling resume() on data task
5. You want to load an image from a URL and display it in a UIImageView safely, handling errors and updating UI correctly. Which code snippet correctly achieves this?
let url = URL(string: "https://example.com/image.png")
URLSession.shared.dataTask(with: url!) { data, response, error in
  if let data = data, let image = UIImage(data: data) {
    DispatchQueue.main.async {
      imageView.image = image
    }
  } else {
    print("Failed to load image")
  }
}.resume()
hard
A. This code misses calling resume() on data task
B. This code correctly loads image and updates UI on main thread
C. This code updates UI on background thread
D. This code does not handle optional URL safely

Solution

  1. Step 1: Check for safe image loading and UI update

    The code unwraps data and image safely, then updates the UIImageView inside DispatchQueue.main.async, which is correct.
  2. Step 2: Verify error handling and task start

    It prints an error message if loading fails and calls resume() to start the task.
  3. Final Answer:

    This code correctly loads image and updates UI on main thread -> Option B
  4. Quick Check:

    Safe unwrapping + main thread UI update = correct [OK]
Hint: Use DispatchQueue.main.async for UI updates after loading [OK]
Common Mistakes:
  • Not calling resume() to start task
  • Updating UI outside main thread
  • Ignoring optional unwrapping safety
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