iOS with Swift Lab Learning Guide: Building an App with Form and Core Data

Learning Outcomes:
Create an IOS app with SWIFT to demonstrate the use of a form whose fields are written to and retrieved from the iOS Core Data framework
Resources: Big Nerd Ranch Guide

Room Database is an abstraction layer over SQLite for Android devices, providing a more convenient way to persist data locally. In iOS, the equivalent framework for persisting data locally is Core Data, which is provided and managed by Apple itself
. Core Data is commonly recommended for storing and accessing structured data in iOS applications

What is the difference between room and core data in ios
Room and Core Data are both frameworks used to manage the lifecycle of objects in a mobile application, often using SQLite as a local/on-device database
. However, they are designed for different operating systems: Room is for Android, while Core Data is for iOS.
Core Data is a powerful and flexible iOS framework that allows storing data in applications and devices. It works with such programming languages as Objective-C and Swift and remains in high demand among iOS developers
. Core Data is a framework for managing an object graph, which is a collection of interconnected objects. The framework is responsible for managing the life cycle of the objects in the object graph. It can optionally persist the object graph to disk and also offers a powerful interface for searching the object graph it manages. Core Data adds a number of other compelling features, such as input validation, data model versioning, and change tracking
On the other hand, Room is a part of Android's Jetpack suite of libraries and is an abstraction layer over SQLite, providing a more convenient way to persist data locally. It offers compile-time checks of SQL statements and can return RxJava, Flowable and LiveData observables, among other features. However, Room is not available for iOS development
In terms of comparison, both Room and Core Data are abstractions on top of a data store, but they take very different approaches
. Core Data is often considered to have a steeper learning curve but offers first-party security and reliability
. Some developers also find Core Data to be more memory-efficient
In conclusion, while Room and Core Data serve similar purposes, they are designed for different platforms and have different features and capabilities. Therefore, the choice between the two would largely depend on the platform (Android or iOS) you are developing for.

Write a fully functional iox xcode app which will take field data from a form and store it into core data

Create a new project in Xcode: Open Xcode and create a new iOS project based on the Single View App template. Make sure the "Use Core Data" option is checked
Create a Core Data Model: The first step in working with Core Data is to create a data model file to define the structure of your app's objects, including their object types, properties, and relationships
. To create a data model, choose File > New > File and select iOS > Core Data > Data Model
Design the User Interface: Design the form that will take the user input. This could be done using SwiftUI or UIKit, depending on your preference. The form should have fields corresponding to the properties of the objects in your Core Data model.
Save Data to Core Data: When the user submits the form, you should create a new instance of your Core Data object, set its properties based on the form input, and save it to the Core Data context. Here's a simplified example of how you might do this in Swift:
Explainlet managedContext = persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "YourEntity", in: managedContext)!
let newObject = NSManagedObject(entity: entity, insertInto: managedContext)
newObject.setValue(inputField.text, forKeyPath: "yourProperty")
do {
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")

In this code, persistentContainer is an instance of NSPersistentContainer, which is part of the Core Data stack that Xcode automatically generates for you when you create a new project with Core Data
. YourEntity and yourProperty should be replaced with the name of your Core Data entity and the property you want to set, respectively. inputField.text should be replaced with the text input from your form.
Fetch and Display Data: You can fetch data from Core Data using a NSFetchRequest. Once you have fetched the data, you can display it in your app's user interface. Here's a simplified example of how you might fetch data:
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "YourEntity")
do {
let objects = try managedContext.fetch(fetchRequest)
// Update your user interface with the fetched objects.
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")

In this code, YourEntity should be replaced with the name of your Core Data entity.
Please note that this is a simplified overview of the process. Depending on the complexity of your app, you might need to handle errors more robustly, perform more complex queries, manage relationships between objects, etc. For a more detailed guide, you might want to check out some tutorials or documentation on Core Data


In this lab, students will build an iOS application using Swift that demonstrates creating a user interface with a form, and persisting form data using Core Data. Core Data is a framework provided by Apple for managing the model layer of your application in a way that's both efficient and scalable.


By the end of this lab, students will be able to:
Design a user interface with a form in Swift.
Integrate Core Data into an iOS application.
Write code to save data from form fields into Core Data.
Fetch and display persisted data from Core Data.


To participate in this lab, students should:
Have basic knowledge of Swift and iOS development.
Be familiar with Xcode and Interface Builder.
Understand the Model-View-Controller (MVC) design pattern.

Tools and Materials Needed

Mac with the latest version of Xcode installed.
iOS simulator or a physical iOS device for testing.

Lab Structure

Section 1: Setting Up the Project

Creating a new Xcode project with the "Use Core Data" option enabled.
Exploring the project structure and autogenerated Core Data stack components.

Section 2: Designing the Form Interface

Discussing UI components like UITextField, UILabel, and UIButton.
Designing a form using Storyboard with the aforementioned UI components.
Configuring Auto Layout constraints for responsive design.

Implementation Instructions for UI Components and Form Design using Storyboard

Below you'll find step-by-step instructions to create a basic form in an iOS application using Swift. You will learn how to implement UI components (UITextField, UILabel, and UIButton), design the form using Storyboard, and use Auto Layout constraints to ensure the form is responsive across different device sizes.

Step 1: Open Xcode and Create a New Project

Launch Xcode and select "Create a new Xcode project."
Choose "App" under iOS as your template and click "Next."
Enter your Product Name, Team, Organization Name, and select Swift as the language. Make sure "Use Core Data" is unchecked for now.
Choose where to save your project and click "Create."

Step 2: Design the User Interface

In the Project Navigator, select Main.storyboard to open the Interface Builder.
From the Object Library (usually found at the bottom right of Xcode), drag a UITextField, UILabel, and UIButton onto the View Controller.

Step 3: Configure UI Components

Click on the UITextField and, in the Attributes Inspector, set placeholder text such as "Enter text here."
Click on the UILabel, and change the text to "Your Label" or similar descriptive text.
For the UIButton, set the title to "Submit" or "Save."

Step 4: Setting Up Auto Layout Constraints

Select the UITextField, click the "Add New Constraints" button (it looks like a tie/fan shape) at the bottom of the Interface Builder.
Add constraints for leading, trailing, and top space to the nearest neighbor (make sure the "Constrain to margins" checkbox is checked).
Set specific values (e.g., standard spacing) that define the distance from the UITextField to its neighboring elements.
Select the UILabel, and add constraints similarly to keep it positioned below the UITextField.
For the UIButton, add constraints that position it below the UILabel. You may also add a horizontal centering constraint to align it in the center.

Step 5: Enable Auto Layout and Stack View (Optional)

To manage complex layouts, use "Stack View" to group elements together.
Select your UITextField, UILabel, and UIButton.
Click the "Stack" button (looks like a stack of rectangles) in the bottom right corner.
Set the Stack View's alignment, distribution, and spacing attributes in the Attributes Inspector.

Step 6: Create Outlets and Actions in the View Controller

Open the Assistant Editor (two overlapping circles in the top-right of Xcode) to have Main.storyboard on one side and ViewController.swift on the other.
Ctrl-drag from the UITextField into the ViewController.swift and create an outlet named textField.
Do the same for the UILabel and UIButton, creating an outlet for the label (e.g., label) and an action for the button (e.g., submitButtonTapped).
class ViewController: UIViewController {

@IBOutlet weak var textField: UITextField!
@IBOutlet weak var label: UILabel!
@IBAction func submitButtonTapped(_ sender: UIButton) {
// Code to handle button tap
// Rest of the ViewController class

Step 7: Handle the Button Tap to Read Text Field Input

Implement the button action in ViewController.swift.
@IBAction func submitButtonTapped(_ sender: UIButton) {
// Read the text from the textField and set it to the label
label.text = textField.text

Step 8: Finalize the Form and Test

Return to the standard editor view.
With Main.storyboard open, ensure all components are correctly placed and constraints are set.
Run the application using the iOS Simulator (select an iOS device from the toolbar and click the "Run" button).
Test each of the UI components to make sure text can be entered, the button updates the label, and the view looks good on different device sizes.
By following these steps, you will have created a simple form interface with responsive design using Auto Layout in Storyboard. Remember to save your work frequently and test on various simulators to ensure the layout looks correct on all devices.

Section 3: Implementing the Form Logic

Understanding the delegation pattern for managing text input.
Implementing the UITextFieldDelegate protocols.
Writing functions to handle user interactions (e.g., saving data).

Section 3: Implementing the Form Logic

Understanding the Delegation Pattern for Managing Text Input

The delegation pattern is a core principle in iOS where one object acts on behalf of, or in coordination with, another object. When dealing with text input in UITextField, the delegation pattern allows us to define behaviors for different user actions such as editing began, changed text, and editing ended.
The UITextField has a delegate property that expects an object that conforms to the UITextFieldDelegate protocol. This protocol includes a number of optional methods that you can implement to handle text field events.

Implementing the UITextFieldDelegate Protocols

To use the UITextFieldDelegate protocols, follow these steps:

Step 1: Conform to UITextFieldDelegate

First, indicate that your ViewController conforms to the UITextFieldDelegate protocol. This can be done within the class interface declaration in your ViewController.swift file:
class ViewController: UIViewController, UITextFieldDelegate {
// Rest of the ViewController class

Step 2: Assign the Delegate

Next, in your ViewController setup or viewDidLoad method, assign the view controller as the delegate of the UITextField:
override func viewDidLoad() {
// Assign the text field's delegate property to self (the view controller)
textField.delegate = self

Step 3: Implement Delegate Methods

Implement the needed UITextFieldDelegate methods to handle text input. Commonly used delegate methods include:

func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Called when the user taps the return key on the keyboard
// Dismiss the keyboard
// Return false if you do not want the text field to perform default behavior, such as inserting a new line character
return true

func textFieldDidBeginEditing(_ textField: UITextField) {
// Called when the text field starts being edited

func textFieldDidEndEditing(_ textField: UITextField) {
// Called when the text field resigns first responder status (editing ends)

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// Called each time the user types or deletes a character
// You can use this to limit the number of characters, restrict input to certain characters, etc.
// Return true to allow the text change or false to prevent it
return true

Writing Functions to Handle User Interactions

Apart from handling text field specific interactions, we're also interested in handling general user interactions such as a button tap to save data.

Step 4: Write Action for Button Tap

Within your ViewController, implement the logic for when the button is tapped. Below we assume the button's action is linked to a function named submitButtonTapped:

@IBAction func submitButtonTapped(_ sender: UIButton) {
// Triggered when the user taps the submit button
// Optional: Validate the input text
guard let inputText = textField.text, !inputText.isEmpty else {
// Handle the case where the text field is empty
// Could show an alert or a warning label
// Use the text to perform an action, such as saving it to a variable or calling another function
// For now, let's just print the text
print("Submitted text: \(inputText)")
// Clear the text field if needed
textField.text = ""
// Dismiss the keyboard if it's still up
This method captures the text in the form's text field when the submit button is tapped, optionally validates the text, and then performs an action with the text.
Remember to wire up this action to your UIButton in the Storyboard by right-clicking the button and dragging to the "Touch Up Inside" event trigger, then selecting submitButtonTapped.

Final Tips

Don't forget to call resignFirstResponder() on the text field to dismiss the keyboard when appropriate, such as after tapping the submit button or when the user presses the return key on the keyboard.
Always validate text field input to prevent unexpected values from being processed or saved.
By implementing the UITextFieldDelegate protocols and handling user interactions like button taps, you've completed the logic for a functional form within your iOS application. This form can now be extended to save data to Core Data, send information to a server, or perform other tasks as required by your app's functionality.

Section 4: Integrating Core Data

Overview of Core Data and its benefits.
Reviewing the Core Data Model and creating entities and attributes for the form data.
Writing the NSManagedObject subclass.

Section 4: Integrating Core Data

Overview of Core Data and Its Benefits

Core Data is Apple’s object graph and persistence framework that manages the model layer in applications. It provides automatic and seamless data management, making it efficient for developers to handle data storage and retrieval without writing extensive boilerplate code.
Benefits of Core Data:
Data Modeling: It allows developers to visually design a model, resulting in better understanding and management of the data relationships.
Performance Optimizations: Core Data optimize memory usage and disk performance by loading objects on demand and caching intelligently.
Relational Data: It manages object graphs which can include one-to-many and many-to-many relationships.
Versioning and Migration: Core Data supports data model versioning and automatic database migration.
Querying: Core Data makes complex data queries simple with NSPredicate and can efficiently handle sorting and filtering of data.

Reviewing the Core Data Model and Creating Entities and Attributes

Step 1: Create or Review Core Data Model File

When creating a new project with Core Data enabled, Xcode automatically creates a .xcdatamodeld file; otherwise, you need to add one manually:
Select File > New > File… (or press ⌘N).
Choose Data Model from the Core Data section and click Next.
Name the model and save it.
After creating or selecting your .xcdatamodeld file, you may define your entities and attributes that will represent the form’s data.

Step 2: Define Entities and Attributes

Open the .xcdatamodeld file from the Project Navigator in Xcode.
Click the Add Entity button (+) at the bottom of the model editor to create a new entity, which corresponds to a table in the database.
With the entity selected, in the Data Model Inspector on the right, set the entity's name to match the conceptual data model (e.g., FormData).
Now, add attributes to the entity by clicking the Add Attribute button. Attributes are akin to columns in a table. Each attribute should have a name and a type (e.g., String, Date, Int, etc.). For example, you might add attributes like userName (String), age (Int), submitDate (Date) to store the data from your form.

Step 3: Create NSManagedObject Subclass

After your entity and its attributes have been defined, you need to generate NSManagedObject subclasses that Xcode uses to create instances of your entities. To do so:
Select the entity in your .xcdatamodeld file.
In the Xcode menu, go to Editor > Create NSManagedObject Subclass...
Follow the prompts to generate class files for your entities in your selected language (Swift).
Now you should have two new files for each entity: FormData+CoreDataClass.swift and FormData+CoreDataProperties.swift.
In FormData+CoreDataClass.swift:
import Foundation
import CoreData

public class FormData: NSManagedObject {
// The class is intentionally empty. It serves as a placeholder for Core Data to insert its properties.
In FormData+CoreDataProperties.swift:

import Foundation
import CoreData

extension FormData {

@nonobjc public class func fetchRequest() -> NSFetchRequest<FormData> {
return NSFetchRequest<FormData>(entityName: "FormData")

// Attributes
@NSManaged public var userName: String?
@NSManaged public var age: Int16 // Note: Using Int16 as a placeholder for numerical data.
@NSManaged public var submitDate: Date?

// Custom logic can go here. For instance, computed properties or convenience initializers.
By following these steps, you will have integrated Core Data into your iOS application and created an entity to represent the form data. Subsequently, you'll be able to instantiate FormData objects, manage them using Core Data's context, and store them persistently in the SQLite database on the user's device.

Section 5: Saving Data to Core Data

Discussing the NSManagedObjectContext and its role in Core Data.
Writing code to create an instance of the managed object and save form data.
Handling possible errors during data persistence.

Section 5: Saving Data to Core Data

Discussing the NSManagedObjectContext and Its Role in Core Data

The NSManagedObjectContext in Core Data serves as an in-memory “scratchpad” where you can create and manage your managed objects. You can think of it as a buffer between the objects you're working with in your application and the underlying database. Any changes you make to managed objects are only committed to the database once you save the associated context.
In a typical Core Data stack, there is usually at least one managed object context. It keeps track of all changes to the objects it manages, and when you're ready, it can commit those changes to the persistent store, which might be an SQLite database, binary file, or any other Core Data-supported store type.

Writing Code to Create an Instance of the Managed Object and Save Form Data

Assuming you have a FormData entity with attributes that match the form in your app, let's create an instance of FormData and save it when the user taps the submit button.
First, access your managed object context from your AppDelegate or the PersistenceController if using SwiftUI. The generated project with Core Data support includes code that sets up this context for you.
In your ViewController.swift:

import UIKit
import CoreData

class ViewController: UIViewController {
@IBOutlet var textField: UITextField!
// reference to Core Data context
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext

override func viewDidLoad() {
textField.delegate = self
// Other code...
@IBAction func submitButtonTapped(_ sender: UIButton) {
// Optional: Validate the input text

// Create a new instance of FormData
let newFormData = FormData(context: context)
// Assign values from the form to the attributes
newFormData.userName = textField.text
// Set other attribute values as needed
newFormData.submitDate = Date()
// Call saveContext() to save the form data
// Function to save the context and persist data
func saveContext() {
if context.hasChanges {
do {
// Save the context
print("Data saved successfully")
} catch {
// Handle error by printing to the console,
// you can also provide user feedback with an alert
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")

Handling Possible Errors During Data Persistence

In the code above, the save operation is performed within a do-catch statement to handle any errors that might occur while saving the context. If an error occurs, it will be caught by the catch block, preventing the app from crashing and allowing you to handle the error appropriately.
When handling errors, here are a couple of strategies to consider:
Logging: Always log the error so you can debug and fix the issue. Use print(error) or a logging framework to document the problem.
User Feedback: Inform the user if a save operation fails. This could be through an alert or some form of in-app notification.
Retry Strategies: Implement a strategy to attempt to recover from the error or to retry the operation.
Remember, the actual error handling strategy will vary depending on your app's requirements and user experience guidelines.
By properly managing your NSManagedObjectContext and handling any errors appropriately, you will be able to reliably save form data with Core Data in your iOS application.

Section 6: Fetching and Displaying Data

Writing an NSFetchRequest to retrieve data stored with Core Data.
Implementing NSFetchedResultsController for efficient data management.
Using a UITableViewController to display the retrieved data.

Section 6: Fetching and Displaying Data

Writing an NSFetchRequest to Retrieve Data Stored with Core Data

The NSFetchRequest is the way you retrieve data from your persistent store in Core Data. You use it to specify the entity and, optionally, to filter and sort the data you're fetching.
Here's an example of how to fetch instances of FormData:

func fetchFormData() -> [FormData] {
// Get a reference to the managed object context
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
// Create the fetch request for the FormData entity
let fetchRequest: NSFetchRequest<FormData> = FormData.fetchRequest()
// Optionally add predicates and sort descriptors here
// let sortDescriptor = NSSortDescriptor(key: "submitDate", ascending: true)
// fetchRequest.sortDescriptors = [sortDescriptor]
do {
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
) instead.