Data Management & Optimization

Apr 4 2025 · Swift 5.10, iOS 17.0, Xcode 15.4

Lesson 01: Data Caching & Optimization

Demo

Episode complete

Play next episode

Next
Transcript

In this demo, you’ll update TheMet app to use an NSCache to speed up network requests and AppStorage to store the last query term.

Open TheMet app in the Starter folder.

You’ll notice that the app first loads a collection of items from a query using the term rhino. If you were to request this term again, what do you think would happen? Try it out.

First, open the TheMetService class and drop a breakpoint in getObject. Then, in the app, tap the “Search the met” button at the top right. In the alert, enter the term “rhino,” then tap search.

You should see the breakpoint is being triggered multiple times. If you look at the contents of the function, you can see it’s making a network request for each object. Even though it just made the same requests when the app loads.

Improve the app so it no longer needs to request the same information by using NSCache. At the top of TheMetService, near the other properties, add a NSCache.

private let cache = NSCache<NSString, Object>()

Next, read and write to the NSCache by updating the getObject function.

func getObject(from objectID: Int) async throws -> Object? {
  if let object = cache.object(forKey: objectID.codingKey.stringValue as NSString) {
    return object
  } else {
    let object: Object?

    let objectURLString = baseURLString + "objects/\(objectID)"
    guard let objectURL = URL(string: objectURLString) else { return nil }
    let objectRequest = URLRequest(url: objectURL)

    let (data, response) = try await session.data(for: objectRequest)
    if let response = response as? HTTPURLResponse {
      let statusCode = response.statusCode
      if !(200..<300).contains(statusCode) {
        print(">>> getObject response \(statusCode) outside bounds")
        print(">>> \(objectURLString)")
        return nil
      }
    }

    do {
      object = try decoder.decode(Object.self, from: data)
      if let object = object {
        cache.setObject(object, forKey: objectID.codingKey.stringValue as NSString)
      }
    } catch {
      print(error)
      return nil
    }

    return object
  }
}

The function now checks first to see if the objectID matches an objectID stored in the NSCache before deciding to make a network request. If it does, then it retrieves the object and returns it straight away.

If there’s no matching objectID, it makes the request and checks that the response code is ok. Then, it decodes the object and stores it in the NSCache, using the objectID as the key. Finally, it returns the object to be used by the app.

Drop a breakpoint inside the code where you read and write the cache to, then run the app again. Search for rhino once, and then twice.

Can you see the cache being used here? You’ve just saved your app vital seconds from needing to request data!

To finish off, use App Storage to save the last search term used so the user doesn’t forget it.

Open TheMetView file, and at the top, add an AppStorage property wrapper.

@AppStorage("lastquery") private var lastQuery = "rhino"

Then, delete the query property. Finally, update all the references in the file to query so it uses lastQuery instead.

Run the app and try to search for a new term. Then, force quit the app and launch it again.

Can you see the app saving the last term you added? This shows that App Storage is working!

See forum comments
Cinema mode Download course materials from Github
Previous: Understanding Caching Next: Conclusion