Next you'll use the generated model to create, update, query, and delete data. In this section you'll initialize DataStore, and then manipulate Todo items. ## Configure Amplify and DataStore First, you'll add the DataStore plugin and configure Amplify. 1. Open the main file of the application (`TodoApp.swift`) and **add the following** import statements at the top of the file: ```swift import Amplify import AWSDataStorePlugin ``` 1. In the same file, **create a function** to configure Amplify: ```swift func configureAmplify() { let dataStorePlugin = AWSDataStorePlugin(modelRegistration: AmplifyModels()) do { try Amplify.add(plugin: dataStorePlugin) try Amplify.configure() print("Initialized Amplify"); } catch { // simplified error handling for the tutorial print("Could not initialize Amplify: \(error)") } } ``` 1. Now **call the `configureAmplify()` function** in your App's initializer. ```swift @main struct TodoApp: App { // Add a default initializer and configure Amplify init() { configureAmplify() } // Additional functions... } ``` 1. **Build and run** the application. In the Xcode console window, you'll see a log line indicating success: ```console Initialized Amplify ``` Optionally, if you'd like to adjust the log level, you can do this by updating the `Amplify.Logging.logLevel` variable. For example, you can add the following line of code to the `configureAmplify()` function before calling `Amplify.configure()`: ```swift Amplify.Logging.logLevel = .info ``` Setting the log level to `.info`, re-building and re-running the application should render additional log statements: ```console [Amplify] Configuring Initialized Amplify ``` ## Manipulating data ### Create a Todo Next, you'll create a Todo and save it to DataStore. 1. Open `ContentView.swift` and **add the following** import statements at the top of the file: ```swift import Amplify ``` 1. In the same file (`ContentView.swift`), **update the body view** to call a function called `performOnAppear()` using the `.task()` modifier: ```swift var body: some View { Text("Hello, World!") .task { await performOnAppear() } } ``` 1. In the same file, **add an `async` function** called `performOnAppear()`: ```swift func performOnAppear() async { do { let item = Todo(name: "Build iOS Application", description: "Build an iOS application using Amplify") let savedItem = try await Amplify.DataStore.save(item) print("Saved item: \(savedItem.name)") } catch { print("Could not save item to DataStore: \(error)") } } ``` This code creates a Todo item with two properties: a name and a description, and then calls `Amplify.DataStore.save(:)` in order to store it on DataStore. 1. After making the preceding updates to the `ContentView.swift` file, your code should look like the following: ```swift import SwiftUI import Amplify struct ContentView: View { var body: some View { Text("Hello, World!") .task { await performOnAppear() } } func performOnAppear() async { do { let item = Todo(name: "Build iOS Application", description: "Build an iOS application using Amplify") let savedItem = try await Amplify.DataStore.save(item) print("Saved item: \(savedItem.name)") } catch { print("Could not save item to DataStore: \(error)") } } } ``` 1. **Build and run** the application. In the console output, you'll see an indication that the item was saved successfully: ```console Initialized Amplify Saved item: Build iOS Application ``` 1. **Replace the item** with a new Todo to save an additional item. Let's change the name and description, and add a priority: ```swift let item = Todo(name: "Finish quarterly taxes", priority: .high, description: "Taxes are due for the quarter next week") ``` 1. **Build and run** the application. In the console output, you'll see an indication that the item was saved successfully: ```console Initialized Amplify Saved item: Finish quarterly taxes ``` ### Query Todos Now that you have some data in DataStore, you can run queries to retrieve those records. 1. Edit your `performOnAppear()` method to remove the item creation and save operations, and replace it with the following code: ```swift do { let todos = try await Amplify.DataStore.query(Todo.self) for todo in todos { print("==== Todo ====") print("Name: \(todo.name)") if let description = todo.description { print("Description: \(description)") } if let priority = todo.priority { print("Priority: \(priority)") } } } catch { print("Could not query DataStore: \(error)") } ``` 1. **Build and run** the application. In the console output, you'll see both items returned: ```console Initialized Amplify ==== Todo ==== Name: Build an iOS application using Amplify Description: Build an iOS application using Amplify ==== Todo ==== Name: Finish quarterly taxes Description: Taxes are due for the quarter next week Priority: high ``` 1. Queries can also contain predicate filters. These will query for specific objects matching a certain condition. The following predicates are supported: **Strings** `eq` `ne` `le` `lt` `ge` `gt` `contains` `notContains` `beginsWith` `between` **Numbers** `eq` `ne` `le` `lt` `ge` `gt` `between` **Lists** `contains` `notContains` To use a predicate, pass an additional argument into your query. For example, you can use the following code to see all high priority items: ```swift let todos = try await Amplify.DataStore.query(Todo.self, where: Todo.keys.priority.eq(Priority.high)) ``` In the above code, notice the addition of the predicate parameter as the second argument. 1. Run the application. In the console output, you'll see only the high priority item returned: ```console Initialized Amplify ==== Todo ==== Name: Finish quarterly taxes Description: Taxes are due for the quarter next week Priority: high ``` ### Update a Todo You may want to change the contents of a record. Below, you'll query for a record, create a copy of it, modify it, and save it back to DataStore. 1. Edit your `performOnAppear()` method to remove anything related to DataStore and replace it with the following code: ```swift do { let todos = try await Amplify.DataStore.query(Todo.self, where: Todo.keys.name.eq("Finish quarterly taxes")) guard todos.count == 1, var updatedTodo = todos.first else { print("Did not find exactly one todo, bailing") return } updatedTodo.name = "File quarterly taxes" let savedTodo = try await Amplify.DataStore.save(updatedTodo) print("Updated item: \(savedTodo.name)") } catch { print("Unable to perform operation: \(error)") } ``` 1. **Build and run** the application. In your console output, you'll see an indication that the item was updated successfully: ```console Initialized Amplify Updated item: File quarterly taxes ``` ### Delete a Todo To round out CRUD operations, you'll query for a record and then delete it from DataStore. 1. Edit your `performOnAppear()` method to remove anything related to DataStore and replace it with the following code: ```swift do { let todos = try await Amplify.DataStore.query(Todo.self, where: Todo.keys.name.eq("File quarterly taxes")) guard todos.count == 1, let toDeleteTodo = todos.first else { print("Did not find exactly one todo, bailing") return } try await Amplify.DataStore.delete(toDeleteTodo) print("Deleted item: \(toDeleteTodo.name)") } catch { print("Unable to perform operation: \(error)") } ``` 1. **Build and run** the application. In the console output, you'll see an indication that the item was deleted successfully: ```console Initialized Amplify Deleted item: File quarterly taxes ``` ## Almost done You just reached a *very cool* checkpoint. You have a fully featured CRUD application that saves and retrieves data in the local device, which means the app **works without an AWS account and even without internet connection**. Next, let's connect it to AWS and make sure the data available in the cloud.