# Introduction

### Welcome to our iOS Course SPRING 2026!

TLDR: You will learn how to code for iOS apps!

* If you haven't already, fill out the course application [form](https://forms.gle/V6Q4b4ELf6GwhCB1A)!
  * :shushing\_face: required to be added to Ed Discussion and CMSX
* Enroll in student center, find us on [class roster](https://classes.cornell.edu/browse/roster/SP26/class/CS/1998), our class code is 16287 :smirk:
* **Lecture:** Mon-Wed 8:35-9:25 PM, **Gates G01**

### What is iOS Development?

iOS Development is a specialized version of mobile application development, pertaining specifically to iOS devices. iOS refers to the mobile operating system created by Apple and is what powers many of the company's devices, including the iPhone, iPad, MacOS, and iPod Touch.&#x20;

iOS development includes the construction of the user interface of an app, the handling of user interactions across the app, and the management of user data throughout the app. There are a number of ways to build iOS applications but the primary one is using Swift and in the Xcode IDE. The two native primary frameworks for building iOS applications are UIKit and SwiftUI.

### Why should you take this course?

With iOS capturing almost 60% of the mobile operating system market share in the United States, iOS devices have become a ubiquitous part of daily life. Every day, you use your phone to communicate with friends, navigate to places, and keep up with social media. iOS development sits at the heart of all of the apps that you use for these activities. By taking this course, you will learn how to build an application from the ground up and gain the skills to transform any application idea into a working product.

Moreover, the skills that you learn in this course are broadly applicable to understanding other front end frameworks as well. As a result, many students who have completed this course end up more prepared to recruit for internships and build out their own products.

### What will you learn in this course?

In this course, you will learn all the necessary components that comprise an iOS application. We begin with an introduction to Swift, the primary programming language for iOS. Then we will move on to teaching user interface development in UIKit, showing you how to build beautiful interfaces across all iOS mobile devices and how to visually organize data in applications.&#x20;

Afterwards, we will proceed with lectures on networking, teaching you how to integrate your application with backend services by pulling data from and saving data to backend services.&#x20;

From then on, we will delve in SwiftUI, a completely different (but equally useful) framework for building UI. Finally, we will learn advanced functionality such as creating push notifications, setting up authentication system. To put everything together, students will work on the Hack Challenge, a hackathon in which students from all AppDev courses build a full stack application from scratch. The winners will have their app features on the AppDev website!


# Getting Started

Spring 2026

### First Day Jitters

Here are some pointers for gearing up for our first class on March 11th, 2025!

1. Ensure you've read through the rest of this page and filled out all necessary forms.
2. Install XCode from the App Store! (P.S. it takes a while :smile:)
3. Join us on Ed, send us questions via email <cornellappdevcourses@gmail.com>, and get hyped!

### Prerequisites

CS 1110 is a **highly recommended** co/prerequisite, but not required. **You will also need access to a MacBook** (Intel - macOS Catalina 10.15.4+, Apple Silicon - macOS Big Sur 11+) **to participate in the course** (the Xcode IDE is only available for macOS).

### Enroll in the Course

1. Enroll in **CS 1998-601** in Student Center. This is a **2 credit S/U course**, but you may enroll for 1 credit to avoid going over the credit limit.

{% hint style="info" %}
**Lectures are Monday & Wednesday 8:35 - 9:25 PM in Gates G01**
{% endhint %}

### Ed Discussion

We will be using Ed Discussion for class communication and answering questions. Ed will be the main method of communication between students and course staff. You can join the Ed [here](https://edstem.org/us/join/2sBeUM).

### Install Xcode and Git

{% hint style="danger" %}
**Swift 5, Xcode 12.0+, and iOS 13.0+ is required!**
{% endhint %}

1. You can install Xcode through the [AppStore](https://itunes.apple.com/us/app/xcode/id497799835).
   * If you do not have the latest Mac version and cannot update, you can find older Xcode versions [here](https://xcodereleases.com/).
2. We will be using [Cornell Enterprise GitHub](https://github.coecis.cornell.edu/). Double check that you can log in.
3. Follow the Git Installation Guide:

{% content-ref url="/pages/2RIHHrQOs0nxMq8qqtgY" %}
[Git Installation](/resources/textbook/git-+-github/git-installation)
{% endcontent-ref %}

### Figma

We will be using [Figma](https://www.figma.com/) for app designs. You can create an account using your Cornell email.


# Introduction

Welcome to Intro to iOS! <br>

Thanks for waiting for the course, I know you are excited!

Course starts Wednesday March 11th.

For now. Fill out the course application: <https://forms.gle/V6Q4b4ELf6GwhCB1A>


# Changes & Notes

## ToDo: (pre-first lecture)

* [x] Make course calendar
* [x] Complete google slides Todos
* [x] Add people to ed
* [x] Add people to cmsx
* [x] Course grading changes (assignments are different)
* [x] New office hours section
* [x] New logistics section

later todos:

* [x] Make L5
* [ ] Make A2.5 + the new grading for it

TA emails:\
<cj384@cornell.edu>, <aly32@cornell.edu>, <arg286@cornell.edu>, <da547@cornell.edu>, <in76@cornell.edu>, <an585@cornell.edu>, <afm88@cornell.edu>, <gac232@cornell.edu>, <jj775@cornell.edu>, <klu6@cornell.edu>, <hw769@cornell.edu>, <asc337@cornell.edu>, <ako28@cornell.edu>, <aw895@cornell.edu>

## Assignments:

A1 Unchanged

* Swift basic&#x20;

A2 Unchanged

* Profile&#x20;

A2.5&#x20;

* <mark style="color:$danger;">Profile, add ui collection view component and more practice to delegation</mark>

A3 Same outcome (mock data), but in swiftUI

* Chatdev, swift UI, just UI

A3.5 Same outcome, same code ish

* chatdev - networking

A4 Same outcome but using mvvm

* ChefOS using MVVM

<mark style="color:$danger;">Change Grading</mark>

## Lectures

1. L1: Course Intro + Git + Swift Basics:
   1. add git + github section
2. L2: UIKit
   1. unchanged
3. L3: MVC + Control
   1. unchanged
4. L4: UICollectionView
   1. Same as L5 from prev sem
5. <mark style="color:$danger;">**L5: Delegation + Protocols**</mark>
   1. <mark style="color:$danger;">**new lecture but reinforces same learning objectives**</mark>
   2. <mark style="color:$danger;">**new demo**</mark>
6. L6: SwiftUI I
   1. unchanged
7. L7: SwiftUI II
   1. unchanged
8. L8: Networking I
   1. minimal change&#x20;
   2. connect to swiftui, mention uikit
9. L9: Networking II
   1. minimal change
   2. connect to swiftui, mention uikit
10. L10: MVVM
    1. minimal changes from last sem L11
11. L11: Embedded ML
    1. minimal changes from last sem L12
    2. focus more on CreateML as well as CoreML
12. L12: Special fun Topics
    1. decide on what to do (VR, Gaming,...)
13. L13: Recruiting + Internship experience
    1. minimal to no slides necessary
    2. get iOS members to talk about their experiences (panel-like)
14. L14: AppDev + Career talk
    1. no clue what this is lol<br>


# Course Staff

Spring 2025

{% hint style="info" %}
**Click on our names to schedule a coffee chat with us! We’d love to chat!**
{% endhint %}

## Instructors

<div align="center"><figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FnAKxKpplhEvSA31fso7z%2Fdaniel.png?alt=media&amp;token=93f2c57e-0682-46d6-9099-28aa3784d56a" alt="" width="256"><figcaption><p>Daniel Chuang | CS '26<br>dc863@cornell.edu</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F6JzYs5Ts9ba0s81fRQh4%2FIMG_9779-2-modified.png?alt=media&amp;token=64d53d62-1f2e-49ac-afbc-8dda08a9c2df" alt="" width="247"><figcaption><p>Adelynn Wu | CS  '27 <br>hw769@cornell.edu</p></figcaption></figure></div>

## TAs

<div align="center" data-full-width="true"><figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fd48VFTASnQNWbgxtUiuw%2Frichie.png?alt=media&amp;token=52029682-c4f8-47cc-95b2-0ba1d9ebd35b" alt="" width="256"><figcaption><p>Richie Sun | CS '25<br>rs929</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fgn9Eb0K7qcQRQ3PQ8H5i%2Fcaitlyn_circle.png?alt=media&amp;token=6ab463d3-f6c7-427f-8389-2e399c3c49e0" alt="" width="256"><figcaption><p>Caitlyn Jin | CS '26<br>cj384</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FnR9v3wKgmeFpAzK5LF0u%2Fjayson_resized.png?alt=media&amp;token=c5f7b973-92ea-4a15-a59d-16c967950b3b" alt="" width="256"><figcaption><p>Jayson Hahn | CS '26<br>jmh585</p></figcaption></figure></div>

<div align="center"><figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FGapNpLtELUskEDMUTtCD%2Fpeter.png?alt=media&amp;token=40c79b87-bf9a-4ce8-a472-73c62677e58f" alt="" width="256"><figcaption><p>Peter Bidoshi | Info Sci '26<br>pjb294</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F9a4TieHPlfRY4yiMNcB4%2FIMG_7112-modified.png?alt=media&amp;token=c57b4fe0-ccd5-4373-817a-58f03cb81b26" alt="" width="249"><figcaption><p>Angelina Chen | CS '27<br>asc337</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FaJz8mJmo2mlQBiTJXFWY%2F23E29C5B-C380-4440-B3AF-23204A4AE577_1_201_a-modified.png?alt=media&amp;token=37a09099-0f6f-46cf-a1e7-33621fb82124" alt="" width="249"><figcaption><p>Charles Liggins | CS '27<br>cll258</p></figcaption></figure></div>

<div align="center"><figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F7AvT4dtaAwWtg669t1VT%2FDSC_5026-modified.png?alt=media&amp;token=051ba461-631d-4d8b-bd66-0f5fb6aab1a9" alt="" width="300"><figcaption><p>Asen Kim Ou | CS '26<br>ako28</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FSUMX5ev1szlwKVsy4UeL%2Fheadshot_square-modified.png?alt=media&amp;token=ea34f537-f68c-4498-a13c-bb375640cbae" alt=""><figcaption><p>Jiwon Jeong | CS '28<br>jj775</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FKDTWXC2lgoebJJ2zzoRT%2FJay-modified.png?alt=media&amp;token=f2dfc5e4-d215-4b36-a0e5-fb0f5ece6cbf" alt="" width="300"><figcaption><p>Jay Zheng | Stat '27<br>jz2384</p></figcaption></figure></div>


# Office Hours

Spring 2026

<table><thead><tr><th width="139">Day</th><th width="152.125">Time</th><th width="193">Location</th><th>Staff</th></tr></thead><tbody><tr><td>Monday</td><td>6:00-7:00 pm</td><td><strong>CIS 142</strong></td><td>Caitlyn and Amy</td></tr><tr><td>Tuesday</td><td><p>3:30-4:30pm</p><p></p><p>4:00-5:00pm</p></td><td><strong>Hollister 372</strong></td><td>Andrew<br><br>Duru and Isha</td></tr><tr><td>Wednesday</td><td>3:30-4:30pm<br><br>6:30-7:30pm</td><td><strong>Olin 165</strong><br><br><strong>CIS 142</strong></td><td>Arielle<br><br>Anatoli and Gabriel</td></tr><tr><td>Friday</td><td>3:00-4:00pm<br><br>4:00-5:00pm</td><td><strong>Hollister 368</strong><br><br><strong>Statler 445</strong></td><td>Jiwon and Kaylee<br><br>Adelynn and Angie</td></tr><tr><td>Sunday</td><td>3:00-4:00pm</td><td><strong>CIS 142</strong></td><td>Asen and Alyssa</td></tr></tbody></table>

> *Check out* [*this neat resource*](https://scheduling.cornell.edu/academic-scheduling/registrar-building-codes-and-contacts) *for all building codes on campus!*


# Schedule

Spring 2026

{% embed url="<https://intro-to-ios.github.io/course-curriculum/>" %}

### Schedule

{% hint style="info" %}
**This schedule is tentative and subject to changes to Cornell's academic calendar.**
{% endhint %}

<table><thead><tr><th width="126">Week</th><th width="119">Date</th><th width="328">Lectures</th><th width="330">Assignments</th></tr></thead><tbody><tr><td>1</td><td>Wed 03/11</td><td>L1: Course Intro + Git + Swift Basics</td><td>Post-lecture reading (git)</td></tr><tr><td>2</td><td><p>Mon 03/16</p><p></p><p>Wed 03/18</p></td><td><p>L2: UIKit</p><p></p><p>L3: MVC + Control</p></td><td><p>Pre-lecture 1 | A1 Released <br></p><p>Pre-lecture 2<br><br>Friday 03/20: A1 Due| A2 Released</p></td></tr><tr><td>3</td><td>Mon 03/23<br><br>Wed 03/25</td><td><p>L4: UICollectionView</p><p></p><p>L5: Delegation + Protocols</p></td><td>Pre-lecture 4<br><br>Pre-lecture 5 | A2 Due | A2.5 Released</td></tr><tr><td></td><td>03/28 - 03/05</td><td>SPRING BREAK</td><td></td></tr><tr><td>4</td><td><p>Mon 04/06</p><p><br>Wed 04/08</p></td><td><p>L6: SwiftUI I<br></p><p>L7: SwiftUI II</p></td><td><p>Pre-lecture 6</p><p>Tuesday 04/7: A2.5 Due | A3 released<br>  </p><p>Pre-lecture 7                       </p></td></tr><tr><td>5</td><td>Mon 04/13<br><br>Wed 04/15</td><td><p>L8: Networking I<br></p><p>L9: Networking II</p></td><td><p>Pre-lecture 8 | A3 Due | A3.5 released<br></p><p>Pre-lecture 9</p></td></tr><tr><td>6</td><td>Mon 04/20<br><br>Wed 04/22</td><td><p>L10: MVVM<br></p><p>L11: Embedded ML</p></td><td>Pre-lecture 9 | A3.5 due | A4  (MVVM + networking) released<br><br>Pre-lecture 10</td></tr><tr><td>7</td><td>Mon 04/27 <br><br>Wed 04/29</td><td><p>L12: Special fun Topics<br></p><p>L13: Recruiting + Internship experience</p></td><td>A4 Due</td></tr><tr><td>8</td><td>Mon 05/04         </td><td>L14: AppDev + Career talk</td><td><p>(12/05) Hack Challenge Submissions Due</p><p>(12/08) Attend Hack Challenge Final</p></td></tr></tbody></table>


# Grading

Spring 2026

### Breakdown

| Assignments              |      |                                                        |
| ------------------------ | ---- | ------------------------------------------------------ |
|                          | A1   | 10%                                                    |
|                          | A2   | 10% <mark style="color:red;">+ 2%</mark>               |
|                          | A2.5 | 5%                                                     |
|                          | A3   | 10% <mark style="color:red;">+ 3%</mark>               |
|                          | A3.5 | 10%                                                    |
|                          | A4   | 20% <mark style="color:red;">+ 5%</mark>               |
| **Assignments Subtotal** |      | **65%&#x20;**<mark style="color:red;">**+ 10%**</mark> |
|                          |      |                                                        |
| **Hack Challenge**       |      | 30%                                                    |
| **Attendance**           |      | 5%                                                     |
| Participation            |      | <mark style="color:red;">+ 5%</mark>                   |
| **Total**                |      | **100%**                                               |
| Extra Credit             |      | <mark style="color:red;">+ 0-15%</mark>                |
| **Passing Score**        |      | **70%**                                                |

### Late Policy

{% hint style="danger" %}
**Assignments are due at 11:59pm, but we will continue to accept submissions for 2 days. For example, if the assignment is due Tuesday, the last day we will accept the submission is Thursday.**
{% endhint %}

You are given a total of **4 free slip days**. After all free slip days have been used, there will be a **10% deduction** from that assignment’s grade per day submitted for a maximum of 2 days. In other words, **no late submissions will be accepted the third day after the normal submission deadline.** **Midpoint submissions do not count towards your slip days.** If there are any emergencies or other conflicts out of your control that prevent you from turning in your assignments on time, please reach out to the instructions so we can help you.

### Assignments

There will be a total of 4 assignments throughout the duration of the course. The weighted percentage for each submission is displayed in the table above.

**All submissions will be graded for correctness. You are allowed to work with one other person in the course for A2, A3, and A4. However, A1 must be submitted individually.** We will be using CMS for grading and submission. The submission requirements and details for each assignment will be provided later.

Assignments will be graded and returned, at the latest, one week after the normal submission deadline. **If you feel that the grader make a mistake, create a private Ed post with an explanation about the mistake.**

You will need to put in effort in order to pass this class. We will send out emails to students in jeopardy before the drop deadline. If you have any questions or concerns, please reach out to the course instructors. We care about your learning and want everyone to succeed!

### Extra Credit

There will be extra credit opportunities for every assignment where you can go above and beyond the minimum requirements. These will be challenging but are very rewarding and will definitely help you become a better developer. **You can earn up to a 2% boost for A2, 3% boost for A3 Final, and 5% boost for A4 Final, 5% boost for participating in class (asking and answering questions), adding up to a total of 15%.** Details will be provided in the assignment handout.

### Hack Challenge

This final group project is weighted more heavily than the rest of the individual assignments, so if you don’t do so great on the assignments, a solid final project can boost your grade significantly.

**More details coming soon!**


# Week 1 | Xcode, Swift Basics, and Git


# Todos

#### Course Logistics

* [ ] Fill out the course application [here](https://docs.google.com/forms/d/e/1FAIpQLSdPd81yX79k0uTMJSNPPv7D9ejxWkiOYnoFuts2LksLFvtxEA/viewform).
* [ ] Add the [course calendar](https://calendar.google.com/calendar/u/0?cid=Y182ZDU4MGI4YjI2YzBhOGQ0ODczYTE3NGFkZWNmNmY1YjI1MzA4ODljOTJhNWQzMGI2Y2UwYmQ0MGI0NTcwNTZiQGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20) to your GCal.
* [ ] Read the Getting Started, Syllabus, and Grading sections on the left.
* [ ] Join our [Ed Discussion](https://edstem.org/us/join/2sBeUM). This is where you can ask questions and start discussions!
* [ ] Enroll on Student Center (CS1998-601) if you want credit for this course.

#### Coding Logistics

* [ ] Install Xcode [here](https://apps.apple.com/us/app/xcode/id497799835?mt=12). If you do not have a Mac, please reach out to the instructors.
* [ ] Setup Git and Github enterprise. Follow this [tutorial](/resources/textbook/git-+-github/git-installation), and reach out on Ed if you run into any problems.
* [ ] Optional, but super helpful, read through [Git Basics](/resources/textbook/git-+-github/git-basics) \[important] and [Git+](/resources/textbook/git-+-github/git+) \[less important for the course]


# L1: Git & Intro to Swift

Spring 2026

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1JedeVOZ_g_p45NnTXMsidE2wWuxb8yWJ4XIlEwxB-QY/edit?slide=id.g27e7496d2d2_0_58#slide=id.g27e7496d2d2_0_58>" %}

### Fall 2025 Lecture Video

{% embed url="<https://youtu.be/LCyxuicRtOo>" %}

### Fall 2024 Lecture Video

{% embed url="<https://youtu.be/x0bhrOiLbhQ>" %}


# Week 2 | UIKIT, MVC, and Control

Working with UIKit

## Monday

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/XRBglCzbmljsX8QC2pvC" %}
[Pre-lecture Reading I](/course-content/week-2-or-uikit-mvc-and-control/pre-lecture-reading-i)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/KfKiEVFhmQDzqD3JP63S" %}
[Monday | UIKit](/course-content/week-2-or-uikit-mvc-and-control/monday-or-uikit)
{% endcontent-ref %}

## Wednesday

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/s7E5c1wCZTO6MlGDJjD8" %}
[Pre-lecture Reading II](/course-content/week-2-or-uikit-mvc-and-control/pre-lecture-reading-ii)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/kytaGjqb7y6sUzm7KY7Q" %}
[Wednesday | MVC and Control (Navigation + Delegation)](/course-content/week-2-or-uikit-mvc-and-control/wednesday-or-mvc-and-control-navigation-+-delegation)
{% endcontent-ref %}

## Assignment

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/WHqf3XvzIL5wBKi8ybTp" %}
[A1: Swift Basics](/course-content/week-2-or-uikit-mvc-and-control/a1-swift-basics)
{% endcontent-ref %}


# Pre-lecture Reading I

SP 2026 | Zain Bilal

Before we build screens, we need to understand how iOS structures its code.

### 1. Classes and Objects

* Classes: Think of a class as a blueprint for something. Each class contains properties and functions (methods) that determine its behavior and state. For example, a `Student` class might have properties like `name`, `age`, and `major`.  Notice that the properties have types: `name` and `major` are strings, and `age` is an int.&#x20;

{% hint style="info" %}
&#x20;We might represent this as: `name: String`, `age: Int`, `major: String.`
{% endhint %}

* Objects: Think of objects as instances of the class. If a class is a blueprint for a house, an object is a house. To go with the student example above, an object would be: `name = "Asen"`, `age = 38`, `major = "sleep"` . Basically, an object is a specific instance of a class with concrete values for its properties.
* Simple sentence to remember: Classes are blueprints that define the *properties* and *behaviors* something can have. (a cat has a number representing age and a string representing a name), Objects are the *actual* things (a cat with age 6 and name Jiwon)

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FtWysg1HppTgCoDrhqAeX%2FFrame%202%20(1).svg?alt=media&amp;token=67b908aa-e1a8-48a4-ade8-44b9f957eea1" alt=""><figcaption></figcaption></figure>

### 2. Inheritance

We use classes and inheritance to avoid repeating ourselves when objects share common features. Imagine creating 100 human characters, instead of coding their basic traits 100 separate times, we can use a shared blueprint to do the heavy lifting.

Look at the photo below:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F8NuAx0WJq4KNgDL79FSw%2FFrame%201.svg?alt=media&amp;token=17bd23c5-e8ed-41e5-847d-62f06239269e" alt=""><figcaption></figcaption></figure>

Both planes and submarines are vehicles that share some properties (`Speed`, `NumberOfSeats`...). However, a plane has a property that neither vehicle nor submarine share, `Elevation`. Similarly, a submarine might have a property that others do not, such as oxygenLeft. All the statements below are true:

* Vehicle is a *superclass* of both Submarine and Plane.
* Submarine and Plane inherit Vehicle.
* Submarine and Plane are *subclasses* of Vehicle.

### How does this tie into UIKit?

UIKit provides a massive library of pre-built classes we can use. For example, if you want text on your screen, you use the `UILabel` class. If you want a button, you use the `UIButton` class.

More importantly, when we create a new screen (or "page") in our app, we don't code the underlying mechanics from scratch. Instead, we create a subclass of a master (*superclass*) UIKit class called `UIViewController`. This means our custom page automatically inherits all the complex, behind-the-scenes behaviors of a standard iOS screen. All we have to do is write the code to add our specific properties, like text, images, and buttons, on top of it!


# Monday | UIKit

Spring 2026

<details>

<summary>Classes Demo Code</summary>

```swift
class Student {
    // Properties
    var name: String
    var major: String
    var age: Int

    // Initializer
    init(name: String, major: String, age: Int) {
        self.name = name
        self.major = major
        self.age = age
    }
}

// Creating an instance of Student
let jay = Student(name: "Jay", major: "CS", age: 67)
// Access properties like below
jay.name
jay.major
jay.age

// NOTE: the super class of `EngineeringStudent` is `Student`
class EngineeringStudent: Student {
    // Inherits all properties and function from 'Student'
    // Define more properties
    var doesShower: Bool

    init(name:String, major:String, age: Int, doesShower: Bool) {
        self.doesShower = doesShower // Initalize property specific to this class
        super.init(name: name, major: major, age: age) // Call the super class's initializer
    }
}

// Creating an instance of EngineeringStudent
let asen = EngineeringStudent(name: "Asen", major: "CS", age: 22, doesShower: false)
asen.doesShower // This works fine since asen is an EngineeringStudent
jay.doesShower  // This DOESN'T work since jay is a Student. `doesShower` 
                //    is a property of EngineeringStudent but not Student
```

</details>

<details>

<summary>UIKit Follow-Along</summary>

{% embed url="<https://github.com/intro-to-ios/lec2-uikit>" %}
If you prefer to download the ZIP, go to Code > Download ZIP in the Github Repository website.
{% endembed %}

## Using git in Terminal

#### 1. Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/lec2-uikit
</strong></code></pre>

#### 2. Checkout Branches

* **If you fall behind during demo**
  * **restore** using "git restore ."&#x20;
    * or stash using "git stash"
  * then checkout a completed code to start the next demo

```zsh
## Completed UI Label Code
git checkout 1-uilabel
```

```zsh
## Completed UIImageView Code
git checkout 2-uiimageview
```

</details>

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1hfOS2ko47X6RBvBHj7pUiCPKQtwjQBRwtKTQtitcn04/edit?usp=sharing>" %}

### Spring 2026 Lecture Video

{% embed url="<https://www.youtube.com/watch?list=PLjf6nsEcF5KN3xI48VwrmWMPmlmuAxU2x&v=Iu_1z976niU>" %}


# Pre-lecture Reading II

SP 2026 | Jay Zheng

### What is MVC?

MVC stands for **Model-View-Controller**. It's a software design pattern — a set of rules that govern how we organize our code. UIKit apps follow MVC as their core architecture.

Think of it like a TV setup as an analogy:

| Component      | TV Analogy     | Role                                            |
| -------------- | -------------- | ----------------------------------------------- |
| **Model**      | TV channels    | Where the actual data lives                     |
| **View**       | TV screen      | Displays what's happening right now             |
| **Controller** | Remote control | Tells the system what to do based on user input |

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FtgDnHbJFioykCrMvo21W%2Fimage.png?alt=media&amp;token=dd862c16-a9f4-4412-ad03-ab0179f102b9" alt=""><figcaption></figcaption></figure>

**Key Rule**: Views and Models never talk to each other directly. They always communicate through the Controller.

***

### Model

Models are objects that represent your app's **data**. They hold the information your app works with and get updated based on user interaction or data from a backend.

* Example: In Eatery, the models are things like dining halls and food items.
* We typically define models as **structs** in Swift.

#### Quick refresher on Structs vs Classes&#x20;

**Structs are value types.** When you assign a struct to a new variable or mutate it, Swift creates a *copy*. The original is untouched.

swift

```swift
struct User {
    var name: String
}

var user1 = User(name: "Vin")
var user2 = user1
user2.name = "Richie"

// user1.name is still "Vin"
// user2.name is "Richie"
```

**Classes are reference types.** Multiple variables can point to the *same* object in memory. Changing one affects all references.

swift

```swift
class User {
    var name: String

    init(name: String) {
        self.name = name
    }
}

var user1 = User(name: "Vin")
var user2 = user1
user2.name = "Richie"

// user1.name is now "Richie" too!
// Both variables point to the same object.
```

**When to use which?** Use structs for simple data models — they're faster and safer since mutations don't have unintended side effects. Use classes when you need inheritance or shared mutable state (like `UIViewController`).

***

### View

Views are the **visible UI components** — everything the user sees and interacts with.&#x20;

This includes `UILabel`, `UIButton`, `UIImageView`, and so on, all of these are its own view!

In Eatery, the dining hall name displayed on screen is a `UILabel` that pulls its text from a dining hall model.

***

### Controller

Controllers are the **glue** between models and views. In UIKit, the controller is a `UIViewController`.

A typical flow:

1. User taps a `UIButton` (a **view**)
2. The controller receives that tap event
3. The controller updates the **model** (e.g., adds an item)
4. The controller updates the **view** to reflect the change

***

### Navigation

So far you've been working with a single screen. But real apps have many screens, each represented by its own `UIViewController`.

There are **two main ways** to navigate between screens:

#### Pushing / Popping

* View controllers are pushed onto and popped off of a **navigation stack**.
* The stack is managed by a `UINavigationController` (typically set up in `SceneDelegate.swift`).

Imagine a screen of information

* **Pushing** - slides a new screen in from the right.&#x20;
* **Popping** - removes it

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FHWC0AmDjWIjntvkdhzMB%2Fimage.png?alt=media&amp;token=76e15b82-3a72-4f8b-bb30-8d34337a1661" alt=""><figcaption></figcaption></figure>

#### Presenting / Dismissing

* A view controller is **presented** on top of the current one (like a modal/sheet).
* It can be **dismissed** via gestures like swiping down or tapping a close button.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FqOPqPwpCgPMhicnxfV79%2Fimage.png?alt=media&amp;token=d688b43c-51f5-4851-a7c8-e1a5d8d2376f" alt=""><figcaption></figcaption></figure>

***

### Delegation (Preview)

Delegation is a pattern that lets a **child** view controller communicate back to its **parent**. For example, a settings screen might need to tell the home screen that the user changed their name.

The key idea: the child VC doesn't know *which specific* parent it's talking to — it just knows the parent can do certain things, defined by a **protocol**. This keeps things loosely coupled.

**Key terminology:**

* **Delegator** = the child VC that asks someone else to do something
* **Delegate** = the parent VC that actually does the work
* **Protocol** = the contract between them (similar to interfaces in Java)

> We'll dive much deeper into delegation and protocols in a future lecture. For now, just understand the high-level flow: child says "hey delegate, something happened" → parent handles it.

***

### Key Takeaways

* **MVC** separates your code into data (Model), UI (View), and logic (Controller). Views and models communicate only through the controller.
* **Structs** copy on assignment (value type). **Classes** share references (reference type). Prefer structs for data models.
* **Navigation** uses pushing/popping (with `UINavigationController`) or presenting/dismissing to move between screens.
* **Delegation** uses protocols to let child VCs communicate back to parent VCs without tight coupling.


# Wednesday | MVC and Control (Navigation + Delegation)

Spring 2026

[Where we at](https://intro-to-ios.github.io/course-curriculum/)

<details>

<summary><strong>Interactive Demo:</strong> Struct vs Class</summary>

{% embed url="<https://intro-to-ios.github.io/Lec3-struct-vs-class/>" fullWidth="true" %}
Interactive Demo :)&#x20;
{% endembed %}

</details>

<details>

<summary><strong>Follow Along Demo:</strong> UIKit Navigation Management </summary>

{% embed url="<https://github.com/intro-to-ios/lec3-navigation>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

### Using git in Terminal

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec3-navigation.git
```

#### 2. Checkout Branches

* **If you fall behind during demo**
  * **restore** using "git restore ."&#x20;
    * or stash using "git stash"
  * then checkout a completed code to start the next demo

```sh
git checkout 1-navigation
```

```sh
git checkout 2-delegation
```

</details>

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1UxmsScpTNESBTpwr2aLyW1GBiB5zy4TBKnGug0dYAfw/edit?usp=sharing>" %}

#### Spring 2026 Lecture Video <a href="#spring-2026-lecture-video" id="spring-2026-lecture-video"></a>

{% embed url="<https://youtu.be/SCUA8sPU4Uc?si=A4IflQvtEZ9d3mHx>" %}


# A1: Swift Basics

Original Author: Vin Bui

{% hint style="danger" %}
**Assignment Due: Friday March 20, 2026 11:59pm**
{% endhint %}

{% file src="/files/9ZGsAjtulgoCVCe11n3x" %}

## Overview

***

The goal of this assignment is to help you become familiar with basic Swift syntax.

## Learning Objectives

***

**Developer Skills**

* How to implement functions according to a specification
* How to read documentation from outside resources
* How to read, create, and use functions to organize code
* How to work with Git and GitHub for version control

**Course Material**

* How to use string interpolation to combine variables with strings
* How to convert data types using type casting
* How to create and work with arrays and dictionaries
* How to use conditionals to control program flow
* How to use methods provided by Swift
* How to use loops to repeat code
* How to work with optionals
* How to use higher order functions to simplify code

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment must be done individually.** However, we do encourage *limited* collaboration. You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/course-content/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

The grading for TODOs 1-9 are based on the number of test cases that you pass. We will convert the values to a decimal and their sum will be your subtotal (out of 10). The feedback form link is located in the [Submission](#submission) section of this handout.

| TODO 1: <mark style="color:red;">`introduce`</mark>         | \_ / 2                                       |
| ----------------------------------------------------------- | -------------------------------------------- |
| TODO 2: <mark style="color:red;">`getStudentInfo`</mark>    | \_ / 1                                       |
| TODO 3: <mark style="color:red;">`countEvens`</mark>        | \_ / 4                                       |
| TODO 4: <mark style="color:red;">`capitalizeStrings`</mark> | \_ / 4                                       |
| TODO 5: <mark style="color:red;">`repeatString`</mark>      | \_ / 4                                       |
| TODO 6: <mark style="color:red;">`countWords`</mark>        | \_ / 6                                       |
| TODO 7: <mark style="color:red;">`containsNum`</mark>       | \_ / 4                                       |
| TODO 8: <mark style="color:red;">`uppercaseLead`</mark>     | \_ / 6                                       |
| TODO 9: <mark style="color:red;">`filterImposter`</mark>    | \_ / 6                                       |
| Feedback Survey                                             | \_ / 1                                       |
| <mark style="color:blue;">**SUBTOTAL**</mark>               | <mark style="color:blue;">**\_ / 10**</mark> |
| Deduction: Crash Tax                                        | -1 point                                     |
| <mark style="color:blue;">**GRAND TOTAL**</mark>            | <mark style="color:blue;">**\_ / 10**</mark> |

## Getting Started

***

### Opening the Project

Download and unzip the files at the top of this page. Navigate to the files located on your local computer drive. Inside of the folder  should contain an Xcode project called <mark style="color:red;">`A1.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard.

If you expand everything underneath <mark style="color:red;">`A1`</mark> you should see the following:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FHu0kd73FguwMDgH6Ngrd%2FUntitled.png?alt=media&amp;token=34a12809-af85-49af-b752-82dd85639f7e" alt="" width="269"><figcaption></figcaption></figure>

**You will be working on&#x20;**<mark style="color:red;">**`MainApp.swift`**</mark>**&#x20;and&#x20;**<mark style="color:red;">**`A1Tests.swift`**</mark>**.**

## Part I: Assignment Files

***

### `MainApp.swift`

You will be implementing the functions provided in this file. **There are a total of 9 TODOs.** If you click on this red box at the top of your Xcode, there should be a dropdown menu.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FYPDcnIX8pjvUGb8LJCGo%2FUntitled.png?alt=media&amp;token=c637668a-dfc6-4e9d-bad0-8be30e80a2ac" alt="" width="277"><figcaption></figcaption></figure>

If you click on the clipboards, you will directed to the TODOs. The stars (⭐️) represent the difficulty level of each function. At the top of each function header is the ***specification***. **Your goal is to implement the function according to the specification. DO NOT CHANGE THE FUNCTION HEADER.** We have given you hints to help you complete the tasks.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FlwaPbJydvSeXNt2HJLv9%2FUntitled.png?alt=media&amp;token=37c7805a-1d21-47d6-857f-35f6b99c50d9" alt="" width="229"><figcaption></figcaption></figure>

### `A1Tests.swift`

This file contains the test cases for each function. **DO NOT EDIT THIS FILE.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FNfzS59VKB3AiuEo4vCgH%2FUntitled.png?alt=media&amp;token=2041c0b4-fa79-4d1b-9881-dba78e5537ef" alt=""><figcaption></figcaption></figure>

There are two ways to run the test cases:

1. You can run the entire test suite by clicking on the button in the blue box next to <mark style="color:red;">`final class A1Tests: XCTestCase`</mark> in the Editor or <mark style="color:red;">`A1Tests`</mark> in the Navigator on the left.
2. You can run test cases for a specific function by clicking on the button in the blue box next to the function (such as <mark style="color:red;">`func testIntroduce()`</mark>) in the Editor or in the Navigator on the left.

When you run the test suite for the first time, it may take about 30 seconds to 1 minute to load. After the first launch, it should not take that long. If the Simulator opens up, keep it open as it is required to run the test suite (for some reason). **You will get a popup saying “Build Succeeded”, but this does not mean that you have passed the test cases. A passed test case will have green checkmarks and no error messages.**

The yellow box above indicates an error message. The value pointed by the pink arrow is the “Received” output which is what your implementation returned. The value pointed by the green arrow is the “Expected” output which is what your function *should* return. The console will also output the error message.

{% hint style="danger" %}
**Make sure you are using an iPhone simulator at the top of Xcode.**
{% endhint %}

## Part II: Implementing the Functions

***

There are a total of 9 functions that you need to implement with varying levels of difficulty (indicated by a ⭐️). Follow these steps when working on the assignment:

1. Begin **TODO 1** and implement the function.
2. Run the test function for **TODO 1**. If failed, fix your function and try again. If passed, move on to the next step.
3. Repeat for **TODOs 2-9**

## Submission

***

1. Double-check that all of your files are properly filled out.
2. Zip all of your files, you can right-click the folder they are in and click "compress"
3. Submit the assignment to CMSX
4. Fill out this [feedback survey](https://forms.gle/WAdrUG3zHzEBM7cv6) (worth 1 point).


# A2: Profile

Original Author: Vin Bui

{% hint style="danger" %}
**Assignment Due: Wed, March 25th 2026 11:59pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands). Otherwise, we will create a repository for you.**
{% endhint %}

{% file src="/files/rFSbGbSKutB3htStOdgy" %}

## Setup

***

If you prefer to use your personal GitHub account instead (not recommended), please make a private Ed post and we’ll provide instructions.

Note: After your assignment has been graded, you’re welcome to copy or upload your repo to your personal GitHub for portfolio purposes.&#x20;

Read these steps carefully, and reach out on ed if you encounter any problems:

#### 1. Go to the course organization

Navigate to:\
👉 <https://github.coecis.cornell.edu/cs1998-601-sp26>

#### 2. Open the template repo

Click on:

```
a2-template
```

#### 3. Create your own repo

* Click the green **“Use this template”** button
* Select:
  * **Owner:** `cs1998-601-sp26`
  * **Repository name:** `NETID-a2` (replace NETID with your NetID)
* Click **“Create repository”**
* Choose **"private"**

#### 4. Clone your repo

On your newly created repo page:

* Click the green **“Code”** button
* Copy the SSH URL

Then run in your terminal (from the directory you want your files to end up in):

```
git clone <PASTE_URL_HERE>
cd NETID-a2
```

#### 5. Start working

Open the project and begin coding.

#### 6. Save your work (commit + push)

Whenever you make changes:

```
git add .
git commit -m "your message"
git push
```

* you can also use [**github desktop**](https://desktop.github.com/download/)**,** but we encourage you to play with command line interface.

## Overview

***

In this assignment, you will be creating your first ever iOS application using UIKit programmatically. You will be creating a Profile and Edit Profile page, commonly seen in many apps today.

## Learning Objectives

***

**Developer Skills**

* **How to format and structure your code to follow MVC design pattern**
* **How to follow common styling conventions used in industry**
* **How to implement designs created on Figma**
* How to work with Git and GitHub for version control
* How to read documentation from outside resources

**Course Material**

* How to create classes such as a <mark style="color:red;">`UIViewController`</mark>
* How to create and customize a <mark style="color:red;">`UIView`</mark> and position them with <mark style="color:red;">`NSLayout`</mark>
  * <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIButton`</mark>, <mark style="color:red;">`UIImageView`</mark>, <mark style="color:red;">`UIImage`</mark>, <mark style="color:red;">`UITextField`</mark>
* How to navigate between view controllers using a <mark style="color:red;">`UINavigationController`</mark> and popping/pushing
* How to use delegation to communicate between view controllers
* How to implement design system using <mark style="color:red;">`UIFont`</mark> and <mark style="color:red;">`UIColor`</mark>

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/course-content/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Creating the Profile Page**</mark>              | <mark style="color:blue;">**\_ / 1**</mark>        |
| ----------------------------------------------------------------------------------- | -------------------------------------------------- |
| <p>UI: Profile Image<br>UI: Name, Bio<br>UI: Hometown and Major</p>                 | \_/ 1                                              |
| <mark style="color:blue;">**PART II: Push the Edit Profile Page**</mark>            | <mark style="color:blue;">**\_ / 2**</mark>        |
| UI: Edit Profile Button                                                             | \_ / 1                                             |
| F: Pushes <mark style="color:red;">`EditProfileVC`</mark>                           | \_ / 1                                             |
| <mark style="color:blue;">**PART III: Create the Edit Profile Page**</mark>         | <mark style="color:blue;">**\_ / 1**</mark>        |
| <p>UI: Profile Image<br>UI: Name, Bio<br>UI: Hometown and Major TextFields</p>      | \_ / 1                                             |
| <mark style="color:blue;">**PART IV: Pop the Edit Profile Page**</mark>             | <mark style="color:blue;">**\_ / 2**</mark>        |
| UI: Save Button                                                                     | \_ / 1                                             |
| F: Pops <mark style="color:red;">`EditProfileVC`</mark>                             | \_ / 1                                             |
| <mark style="color:blue;">**PART V: Delegation**</mark>                             | <mark style="color:blue;">**\_ / 2**</mark>        |
| F: Clicking on <mark style="color:red;">`Save`</mark> updates the main Profile page | \_ / 2                                             |
| <mark style="color:blue;">**OTHER**</mark>                                          | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                     | \_ / 1                                             |
| Styling: <mark style="color:red;">`viewDidLoad`</mark> calls helper functions       | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                      | <mark style="color:green;">**\_ / 10**</mark>      |
| ~~EC: Custom back button~~                                                          | ~~+ 1~~                                            |
| EC: Edit profile picture                                                            | + 1                                                |
| Deduction: Crash Tax                                                                | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                   | <mark style="color:green;">**\_ / 10 (+2)**</mark> |

## Getting Started

***

### Setting up Figma

You can find the link to the Figma [here](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). If you do not have an account, you can create one under your Cornell email. I will provide details on how to navigate through Figma later.

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the [`Git Installation Section`](https://ios-course.cornellappdev.com/~/revisions/wrtYMFJVea8chxL2Ntds/resources/textbook/git-+-github/git-installation), or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a2`</mark> should contain an Xcode project called <mark style="color:red;">`A2.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard.

If you expand everything underneath <mark style="color:red;">`A2`</mark> you should see the following:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fmj0x1GlWzLSyfQvY51SH%2FUntitled.png?alt=media&amp;token=c8a86de6-493b-4e02-8ef5-2a2f6ef71976" alt="" width="237"><figcaption></figcaption></figure>

**You will be working on&#x20;**<mark style="color:red;">**`ProfileVC.swift`**</mark>**,&#x20;**<mark style="color:red;">**`EditProfileVC.swift`**</mark>**, and&#x20;**<mark style="color:red;">**`Assets.xcassets`**</mark>**.**

## Assignment Files

***

### `ProfileVC.swift`

You will be creating the *main profile page* in this file, primarily in Parts I and II. You are responsible for creating the UI design based on the [Figma](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). This view controller is the root view controller inside of a <mark style="color:red;">`UINavigationController`</mark> located in <mark style="color:red;">`SceneDelegate.swift`</mark>. You will be asked to push <mark style="color:red;">`EditProfileVC`</mark> onto this navigation stack.

### `EditProfileVC.swift`

You will be creating the *edit profile page* in this file, primarily in Parts III and IV. You will be implementing the UI design based on the [Figma](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). This view controller will be pushed by <mark style="color:red;">`ProfileVC`</mark> onto the navigation stack. You will be asked to implement popping functionality as well as delegation to save changes from the text field.

### `UIColor+Extension.swift`

**DO NOT EDIT THIS FILE!** This file contains colors that are featured in the Figma design. To use the colors, simply type <mark style="color:red;">`UIColor.a2.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FVxatHYWE39O33tL8yrWX%2FUntitled.png?alt=media&amp;token=b2b2473c-76e3-42c7-baba-194127743474" alt=""><figcaption><p>From the Figma Design</p></figcaption></figure>

## Using Figma and Importing Assets

***

For the scope of this course, we will be teaching you the skills necessary to read a design implemented on Figma. This is widely used both on AppDev and in industry, so it’s important to have this skill in your toolkit. Please read over the [Figma guide](/resources/tool-guides/figma) now.

## Styling

***

Throughout the provided files, you may have noticed the <mark style="color:red;">`// MARK`</mark> comments. These are used to keep the code organized.

* <mark style="color:red;">`Properties (View)`</mark> are used for <mark style="color:red;">`UIView`</mark> objects such as <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIImageView`</mark>, etc. **You should mark these properties as** <mark style="color:red;">`private`</mark> **and make them&#x20;*****constants*****&#x20;(use** <mark style="color:red;">`let`</mark>**).**
* <mark style="color:red;">`Properties (Data)`</mark> are used for data types such as <mark style="color:red;">`String`</mark>, <mark style="color:red;">`Int`</mark>, delegates, etc. **Again, mark these properties as** <mark style="color:red;">`private`</mark> **but it is up to you to decide if they are constants or variables.**
* The <mark style="color:red;">`Set Up Views`</mark> section should be used for initializing your view properties.

You are not limited to these sections and are free to add more (and you should). Because many of your data properties are marked as <mark style="color:red;">`private`</mark>, you ***may*** need to create an <mark style="color:red;">`init`</mark> function.

Follow these steps when implementing the UI:

1. Create the view
2. Initialize the view
3. Constrain the view
4. Run, confirm, and repeat

{% hint style="danger" %}
**Your&#x20;**<mark style="color:red;">**`viewDidLoad`**</mark>**&#x20;method should contain&#x20;*****mostly*****&#x20;function calls to helper functions. We will be grading you on this.**
{% endhint %}

## Part I: Creating the Profile Page

***

**Your task is to create the UI for the&#x20;*****main profile page*****&#x20;in&#x20;**<mark style="color:red;">**`ProfileVC`**</mark>**.** This profile can be for you, your partner, or if you want you can use me (Vin). Do not worry about any functionality here. We will do that in Part II. Your profile will have the following:

* Profile Image: <mark style="color:red;">`UIImageView`</mark>
  * You will need to add the image to <mark style="color:red;">`Assets.xcassets`</mark>. Refer to the Figma guide.
  * To get a perfect circle, set the <mark style="color:red;">`layer.cornerRadius`</mark> of the <mark style="color:red;">`UIImageView`</mark> to the radius (set it to the width of the image divided by 2) and set <mark style="color:red;">`layer.masksToBounds`</mark> to <mark style="color:red;">`true`</mark>.
* Name: <mark style="color:red;">`UILabel`</mark>
  * You can get the colors from Figma under the “Inspect” section. To use the color, type: <mark style="color:red;">`UIColor.a2.<color_name>`</mark>
  * You can get the font **weight** and **size** from Figma under the “Inspect” section. Set the “Code” to `iOS`. To set the font, type: <mark style="color:red;">`.systemFont(ofSize: <size>, <weight>)`</mark>. **Do not use the code. You should only look at the font name and size.**
    * **Make sure you use the weight from the font name instead of the number. For example, even though Figma says a weight of&#x20;**<mark style="color:red;">**`600`**</mark>**, the weight should be&#x20;**<mark style="color:red;">**`.semibold`**</mark>**.**
  * If any of these fields are too long, you can set the <mark style="color:red;">`numberOfLines`</mark> property to <mark style="color:red;">`0`</mark> for unlimited lines.
* Bio: <mark style="color:red;">`UILabel`</mark> (or <mark style="color:red;">`UITextView`</mark>)
  * To make the text italic, use: <mark style="color:red;">`.italicSystemFont(ofSize: <size>)`</mark>
* Hometown: <mark style="color:red;">`UIImageView`</mark> for the icon, <mark style="color:red;">`UILabel`</mark> for the text
* Major: <mark style="color:red;">`UIImageView`</mark> for the icon, <mark style="color:red;">`UILabel`</mark> for the text

Don’t forget to set the title of the view controller to <mark style="color:red;">`“My Profile”`</mark> and background color.

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Push the Edit Profile Page

***

**You task is to create the “Edit Profile” button as well as pushing&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**&#x20;onto the navigation stack.**

Edit Profile Button: <mark style="color:red;">`UIButton`</mark>

* To change the text, use <mark style="color:red;">`setTitle(<text>, for: .normal)`</mark>
* To change the text color, use <mark style="color:red;">`setTitleColor(<color>, for: .normal)`</mark>
* To change the background color, use <mark style="color:red;">`backgroundColor = <color>`</mark>
* To change the corner radius, use <mark style="color:red;">`layer.cornerRadius = <radius>`</mark>. You can get this under “Inspect > Properties” in Figma on the right hand side.
* As a hint, you will need to add the following constraints: leading, trailing, bottom, and height (not width)
* To add functionality to this button when tapped, use <mark style="color:red;">`addTarget(self, #selector(<function_to_call>), for: .touchUpInside)`</mark>

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Create the Edit Profile Page

***

**Your task is to create the UI for the&#x20;*****edit profile page*****&#x20;in&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**.** Do not worry about any functionality here. We will do that in Part IV. Consult Part I for hints on how to implement these views. This page will have the following:

* Profile Image: <mark style="color:red;">`UIImageView`</mark>
* Name: <mark style="color:red;">`UILabel`</mark>
* Bio: <mark style="color:red;">`UILabel`</mark> (or <mark style="color:red;">`UITextView`</mark>)
* Hometown: <mark style="color:red;">`UILabel`</mark> for the text, <mark style="color:red;">`UITextField`</mark> for the text field
  * To set the border width, use <mark style="color:red;">`layer.borderWidth = <width>`</mark>
  * To set the border color, use <mark style="color:red;">`layer.borderColor = <color>`</mark>
    * The color must be a CGColor. Use the following line: <mark style="color:red;">`UIColor.a2.silver.cgColor`</mark>
  * To set the corner radius, use <mark style="color:red;">`layer.cornerRadius = <radius>`</mark>
  * For the text field, you will need to set following constraints: top, leading, trailing, and height (not width)
  * Creating the padding before the text inside of the textfield is not as straight forward, so it’s okay to not have it. However, if you are interested, check [this](https://stackoverflow.com/questions/25367502/create-space-at-the-beginning-of-a-uitextfield) out.
* Major: <mark style="color:red;">`UILabel`</mark> for the text, <mark style="color:red;">`UITextField`</mark> for the text field

You will need to create a data property to store some information. Mark these properties as <mark style="color:red;">`private`</mark> and create an <mark style="color:red;">`init`</mark> function. Make sure to include the following line after initializing your properties: <mark style="color:red;">`super.init(nibName: nil, bundle: nil)`</mark>. The values for these properties will be passed in from <mark style="color:red;">`ProfileVC`</mark>.

{% hint style="info" %}
**If you haven’t realized it yet, for most of the setup functions you can copy and paste from the previous and make slight modifications!**
{% endhint %}

Don’t forget to set the title of the view controller to <mark style="color:red;">`“Edit Profile”`</mark> and background color.

**Once you are done, stage, commit, and push to GitHub.**

## Part IV: Pop the Edit Profile Page

***

**You task is to create the “Save” button as well as popping&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**&#x20;from the navigation stack.**

Save Button: <mark style="color:red;">`UIButton`</mark>

* See Part II for implementation hints

{% hint style="info" %}
**If you implemented Part II correctly, this should be as simple as copy and pasting!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Delegation

***

**You task is to use delegation to update information from&#x20;**<mark style="color:red;">**`ProfileVC`**</mark>**&#x20;based on the text fields in&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**.** Remember these steps:

1. Create a protocol with a function
2. Conform <mark style="color:red;">`ProfileVC`</mark> to the protocol (delegate)
   * Implement the function
3. Create a property in <mark style="color:red;">`EditProfileVC`</mark> to reference <mark style="color:red;">`EditProfileVC`</mark> (delegator)
   * Make sure it has <mark style="color:red;">`weak`</mark> before it. If this property is <mark style="color:red;">`private`</mark>, make sure to initialize it in the <mark style="color:red;">`init`</mark> function.
4. Call the function in <mark style="color:red;">`EditProfileVC`</mark>

If you have forgotten how to implement delegation, view the lecture notes or textbook.

To access the text from a <mark style="color:red;">`UITextField`</mark>, use the <mark style="color:red;">`text`</mark> property of the text field. Note that this gives you an optional.

**Double check that your main profile updates when you click save. Then click on “Edit Profile” again and make sure that the text fields in the edit profile page are also updated.**

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="danger" %}
**If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### ~~1: Custom Back Button (+1 pt)~~ Deprecated extra credit, ios 26 is now just a left cheveron as default back button instead of "< back" - Jay Zheng

When using a <mark style="color:red;">`UINavigationController`</mark>, there is a default back button. However, it does not look nice with our design so **your task is to customize the back button**. The Figma contains the design for this feature. As a hint, the icon used is known as an **SF Symbol** called <mark style="color:red;">`chevron.left`</mark>. You do not need to export this icon; it is built-in.

### 2: Edit Profile Picture (+1 pt)

This one is ***a lot*** more challenging than the previous feature. **Your task here is to allow the user to edit their profile picture.** You can access their camera roll, photo library, or both.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a2.git
Extra Credit:
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://forms.gle/SUtV52cGhVpoLQsz7) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# Week 3 | CollectionViews and more UIKIT


# No reading for Monday lecture

We will be learning about UICollectionViews. Review previous lectures about delegation and mvc!

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fl78kPQyHNOIHIGf3gRPx%2Fimage.png?alt=media&amp;token=f1294aa8-04f7-48d7-980f-fff8bfd212c5" alt=""><figcaption></figcaption></figure>


# Monday | UICollectionView

Spring 2026

<details>

<summary>UICollectionView Follow-Along</summary>

## Using git in Terminal

#### 1. Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/lec5-uicollectionview.git
</strong></code></pre>

#### 2. Delete the Cell File

Remove the file in this directory: `/Views/BirdCollectionViewCell.swift/`

#### 3. Follow Along!

</details>

<details>

<summary>How to access the solution code</summary>

You have two options:

1. Through the GitHub website
   1. Go to <https://github.com/intro-to-ios/lec5-uicollectionview.git>
   2. Press the button that says main (this will show all the branches in this repo)
   3. Choose the branch `1-collectionview`&#x20;
2. Through the terminal
   1. restore your changes or stach them
      1. `git restore .` or `git stash push`
   2. Checkout to the solution branch
      1. `git checkout 1-collectionview`&#x20;
   3. Now your should have the solution code

</details>

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1c_t02iODHLiw_LzMLoDc0NKROHfGm7VEM3N1U6qxvm8/edit?usp=sharing>" %}

### Spring 2026 Lecture Video

{% hint style="info" %}
Due to a technical issue, the recording from today’s lecture was corrupted. The video below is from last semester and assumes familiarity with `UITableView`, which we do not cover this semester. If students find the video difficult to follow, we will record and post a new version of the lecture.
{% endhint %}

### Fall 2025 Lecture Video

{% embed url="<https://www.youtube.com/watch?v=5sRg_SCh2GQ>" %}


# Wednesday Pre-lecture Skim

SP 2026 | Jay Zheng

This is the last UIKit lecture!

We will take UICollectionView one step further by making the individual cells clickable, revisiting UIView, Push/Pop, Protocol and Delegation :)

> Review previous lectures and demos!


# Wednesday | TODO

Spring 2026

<details>

<summary>UICollectionView Follow-Along</summary>

## Using git in Terminal

#### 1. Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/lec5-uicollectionview.git
</strong></code></pre>

#### 2. Delete the Cell File

Remove the file in this directory: `/Views/BirdCollectionViewCell.swift/`

#### 3. Follow Along!

</details>

<details>

<summary>How to access the solution code</summary>

You have two options:

1. Through the GitHub website
   1. Go to <https://github.com/intro-to-ios/lec5-uicollectionview.git>
   2. Press the button that says main (this will show all the branches in this repo)
   3. Choose the branch `1-collectionview`&#x20;
2. Through the terminal
   1. restore your changes or stach them
      1. `git restore .` or `git stash push`
   2. Checkout to the solution branch
      1. `git checkout 1-collectionview`&#x20;
   3. Now your should have the solution code

</details>

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1c_t02iODHLiw_LzMLoDc0NKROHfGm7VEM3N1U6qxvm8/edit?usp=sharing>" %}

### Spring 2026 Lecture Video

{% hint style="info" %}
Due to a technical issue, the recording from today’s lecture was corrupted. The video below is from last semester and assumes familiarity with `UITableView`, which we do not cover this semester. If students find the video difficult to follow, we will record and post a new version of the lecture.
{% endhint %}

### Fall 2025 Lecture Video

{% embed url="<https://www.youtube.com/watch?v=5sRg_SCh2GQ>" %}


# A2.5: Profile Addon

Original Author: Zain Bilal

{% hint style="danger" %}
**Assignment Due: Tue, April 7th 2026 11:59pm**
{% endhint %}

{% hint style="info" %}
Note that there is no starter code for this assignment. You will build on the code you developed for A2. When grading this assignment, we will not penalize issues that originate from mistakes in the A2 tasks.
{% endhint %}

{% hint style="info" %}
This assignment does not require specific spacing or assets. You should experiment with spacing and layout so that the result is scrollable and easy to read.
{% endhint %}

## Setup

***

Continue working in the repository you created for **A2**. All new changes should be committed and pushed to that same repository.

## Overview

***

In this assignment, you will extend the profile application you built in **A2** by adding a **UICollectionView** to your profile page. This collection view will display a grid of hobbies associated with the user’s profile.

{% hint style="info" %}
&#x20;If you get stuck, use lecture 4 demo as guiding code.
{% endhint %}

## Learning Objectives

***

**Course Material**

* How to create and configure a **UICollectionView**
* How to create a **custom UICollectionViewCell**
* How to implement **UICollectionViewDataSource**
* How to use **UICollectionViewDelegateFlowLayout** to control layout
* How to display properties inside reusable cells

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/course-content/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality

| UI: Collection View UI                            | \_/ 3                                        |
| ------------------------------------------------- | -------------------------------------------- |
| F: Collection View Functionality                  | \_ / 2                                       |
| <mark style="color:green;">**SUBTOTAL**</mark>    | <mark style="color:green;">**\_ / 5**</mark> |
| Deduction: Crash Tax                              | -1 point                                     |
| <mark style="color:green;">**GRAND TOTAL**</mark> | <mark style="color:green;">**\_ / 5**</mark> |

## Getting Started

***

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the [`Git Installation Section`](https://ios-course.cornellappdev.com/~/revisions/wrtYMFJVea8chxL2Ntds/resources/textbook/git-+-github/git-installation), or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a2`</mark> should contain an Xcode project called <mark style="color:red;">`A2.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard.

If you expand everything underneath <mark style="color:red;">`A2`</mark> you should see the following:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fmj0x1GlWzLSyfQvY51SH%2FUntitled.png?alt=media&amp;token=c8a86de6-493b-4e02-8ef5-2a2f6ef71976" alt="" width="237"><figcaption></figcaption></figure>

You will primarily work in: `ProfileVC.swift`

You will also create: `HobbyCell.swift`

## Assignment Files

***

### `ProfileVC.swift`

This file contains the main **profile page**.

You will modify this file to:

* Create the **UICollectionView**
* Implement **UICollectionViewDataSource**
* Implement **UICollectionViewDelegateFlowLayout**

### `HobbyCell.swift`

You will create a **custom UICollectionViewCell** that displays a label.

This cell will be reused by the collection view to display multiple hobbies.

### Example of what this could look like:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FjTvYashQK8y6Ai9tPC4r%2FMain%20Profile.png?alt=media&amp;token=f821e385-97e8-44a3-a7fa-f2a5ae4810ce" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Note:** This assignment allows for creative freedom. You will not be graded on the visual design itself, as long as the hobbies are clearly distinguishable.
{% endhint %}

## Part I: Create the Custom Cell (UI)

***

Your first task is to create a custom cell that will display a label.

Create a new Swift file called:

```ssh-config
HobbyCell.swift
```

This class should inherit from:

```swift
UICollectionViewCell
```

Your cell should contain:

#### Text View

```
UILabel
```

This will display the text.

#### Implementation Hints

Create a property for the label.

Example:

```swift
private let hobbyText = UILabel()
```

Inside your setup functions:

1. Initialize the view
2. Add it to the cell’s `contentView`
3. Constrain it to fill the entire cell

Constraints typically include:

* top
* bottom
* (and anything else you see fit)

Create a function that allows the label’s text to be updated (similar to the `configure` function from the Lecture 4 demo).

## Part II: Create the UICollectionView (UI)

***

Next, you will create the **collection view** in `ProfileVC`. This will live **under** the "major" property in the main view. You will NOT be adding functionality to edit these hobbies. The hobbies will be hardcoded under the major information in the profile.

#### Step 1: Create a `UICollectionViewFlowLayout`.

Example:

```
let layout = UICollectionViewFlowLayout()
```

Change it's properties to make it vertical or horizontal, and to tweak spacing.

#### Step 2: Create the Collection View

Add a property in `ProfileVC`:

```swift
UICollectionView
```

#### Step 3: Register the Cell

Register your custom cell with the collection view.

#### Step 4: Set the datasource and delegate

Set the collection view’s `dataSource` and `delegate` to the view controller.

Example:

```
collectionView.dataSource = self
collectionView.delegate = self
```

#### Step 5: Add Constraints

Add the collection view to the view controller and constrain it below the existing profile content.

Typical constraints include:

* top
* leading
* (and anything else you see fit)

## Part III: Implement the Data Source

***

Next, you will implement the **UICollectionViewDataSource** protocol.

In `ProfileVC`, add an extension that conforms to:

```
UICollectionViewDataSource
```

You must implement the following functions.

#### Number of Items

Return the number of hobbies you want to display.

You should store your hobbies in a **data array.** Add <mark style="color:red;">**9 or more**</mark> hobbies (represented by strings) to the array. You can have emojis, or if you want more of a challenge you can represent the hobbies as images.

Example:

```swift
private let hobbies: [String] = [
    "basketball",
    "gym",
    .
    .
    .
]
```

#### Cell for Item

Configure the cell with a label.

Steps:

1. Dequeue the reusable cell
2. Cast it to `HobbyCell`
3. Assign the correct string

## Part IV: Layout the Grid

***

Finally, implement the **UICollectionViewDelegateFlowLayout** protocol to control the grid layout.

Add an extension that conforms to:

```
UICollectionViewDelegateFlowLayout
```

Implement:

```
sizeForItemAt
```

Your goal is to create a **grid of 3 items per row**.

Hints:

* Use the width of the collection view
* Divide it by 3
* Subtract spacing

You can also adjust spacing using:

```swift
minimumLineSpacing
minimumInteritemSpacing
```

Run your app and confirm that your collection view displays a **grid of strings**.

## Final Checklist

Before submitting:

* The project **builds successfully**
* The **collection view displays 9 or more hobbies**
* The **grid layout works correctly**
* Code follows **good organization practices**

Then:

1. Stage
2. Commit
3. Push to GitHub

## Submission

Double check that all files are pushed to GitHub.

Clone your repository into a **separate folder** and run the project.

Download the provided **submission.txt** file and fill it out.

Example format:

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a2.git
```

Submit the **submission.txt** file to **CMS**.

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# Week 4 | SwiftUI


# Monday Pre-lecture Skim

SP 2026 | Jay Zheng

Welcome to SwiftUI! This reading covers a few concepts that can feel unfamiliar the first time you see them. Skim through before lecture so the demos and examples click faster.

### Declarative vs. Imperative

* In UIKit (Imperative), you write step-by-step instructions for *how* to build UI.&#x20;
* In SwiftUI (Declarative), you describe *what* the UI should look like and the framework handles the rest.&#x20;

If you catch yourself asking "when does this code run?" — that's the imperative mindset. In SwiftUI, you just keep your description up to date.

### Structs! Not Classes

SwiftUI views are structs — lightweight value types with no inheritance baggage. Think of them as disposable blueprints, not long-lived objects you mutate over time.

If you're used to thinking of views as long-lived objects that get mutated over time, this is a mental shift!

### Modifiers Create New Views

This is the big one. Each modifier wraps the previous view in a **new view**:

```swift
Text("Hello")
    .padding(20)       // wraps Text in a padded view
    .background(.blue) // wraps THAT in a blue background
```

You're not setting properties like for UILabel — you're nesting wrappers. That's why **order matters**: swapping `.padding` and `.background` changes the result (you will see during demo).

### `some View`

You'll see this in every SwiftUI file:

```swift
var body: some View {
    Text("Hello, world!")
}
```

You'll see `var body: some View` everywhere. It just means "this returns something that conforms to `View`" without you needing to spell out the gnarly concrete type. Don't overthink it.

Why not just write the type?&#x20;

* Because after you chain a few modifiers, the actual type becomes something horrific like `ModifiedContent<ModifiedContent<Text, _PaddingLayout>, _BackgroundModifier<Color>>`. The `some` keyword lets Swift figure out the type for you while still guaranteeing it's a `View`. You don't need to fully understand opaque types right now — just know that `some View` is SwiftUI's way of saying "trust me, it's a view."

### Stacks = Layout

SwiftUI replaces Auto Layout constraints with three simple containers:

* &#x20;**HStack** — arranges views horizontally (left to right)
* &#x20;**VStack** — arranges views vertically (top to bottom)
* &#x20;**ZStack** — layers views on top of each other (back to front)

**HStack (horizontal)**, **VStack (vertical)**, **ZStack (layered).** Nest them to build any layout.&#x20;

**Spacer** is a flexible empty view that pushes other views apart. It expands to fill available space:

```swift
HStack {
    Text("Left")
    Spacer()
    Text("Right")
}
```

This pushes "Left" and "Right" to opposite edges — no constraints needed.


# Monday | SwiftUI I

Spring 2026

<details>

<summary>SwiftUI I Follow-Along</summary>

## Using git in Terminal

#### 1. Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec6-swiftui-1.git
```

#### 2. Follow Along!

</details>

<details>

<summary>How to access the solution code</summary>

You have two options:

1. Through the GitHub website
   1. Go to <https://github.com/intro-to-ios/lec10-swiftui-1>
   2. Press the button that says main (this will show all the branches in this repo)
   3. Choose the branch `1-layouts`&#x20;
   4. Repeat step c for demo 2, 3
2. Through the terminal
   1. restore your changes or stach them
      1. `git restore .` or `git stash push`
   2. Checkout to the solution branch
      1. `git checkout 1-layouts`&#x20;
   3. Now your should have the solution code for demo 1
   4. Same thing for demo 2, 3

</details>

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1f4eSWYShtii700w9XK7VFE3WJp8ozBI3TiaSZb4wn60/edit?usp=sharing>" %}

### Spring 2026 Lecture Video

Coming soon..

***

<details>

<summary>Apple documentation on Topic</summary>

{% embed url="<https://developer.apple.com/documentation/swift/choosing-between-structures-and-classes>" %}
Struct vs Classes
{% endembed %}

{% embed url="<https://developer.apple.com/documentation/swiftui/building-layouts-with-stack-views>" %}
Layouts
{% endembed %}

{% embed url="<https://developer.apple.com/documentation/swiftui/viewmodifier>" %}
View Modifiers
{% endembed %}

</details>


# No Wednesday Pre-lecture Skim

Just come with any questions you have about SwiftUI, iOS developement, or life in general!


# Wednesday | SwiftUI II

Spring 2026

<details>

<summary>SwiftUI Follow-Along</summary>

## Using git in Terminal

#### 1. Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/swiftui-2-demo.git
</strong></code></pre>

#### 2. Follow Along!

</details>

<details>

<summary>How to access the solution code</summary>

You have two options:

1. Through the GitHub website
   1. Go to <https://github.com/intro-to-ios/swiftui-2-demo.git>
   2. Press the button that says main (this will show all the branches in this repo)
   3. Choose the branch you want!
2. Through the terminal
   1. restore your changes or stach them
      1. `git restore .` or `git stash push`
   2. Checkout to the solution branch
      1. `git checkout <branch-name>`&#x20;
   3. Now your should have the solution code

</details>

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1UPRhM4MRwgounHG-jnJ9F1RFhAvAVhfixKgByCE_gIU/edit?slide=id.g3523f2e6685_0_185#slide=id.g3523f2e6685_0_185>" %}

### Spring 2026 Lecture Video

{% embed url="<https://youtu.be/UxFd4NKjr_I>" %}


# A3: ChatDev

Original Author: Vin Bui | New Changes: Zain Bilal

{% hint style="danger" %}
**Due: Monday, April 13, 2026 11:59 pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands).  Otherwise follow the setup instructions.**
{% endhint %}

{% file src="/files/8HJ3oz89kqDVcfELGj22" %}

### Setup <a href="#setup" id="setup"></a>

***

If you prefer to use your personal GitHub account instead (not recommended), please make a private Ed post and we’ll provide instructions.

Note: After your assignment has been graded, you’re welcome to copy or upload your repo to your personal GitHub for portfolio purposes.

Read these steps carefully, and reach out on ed if you encounter any problems:

**1. Go to the course organization**

Navigate to: 👉 <https://github.coecis.cornell.edu/cs1998-601-sp26>

**2. Open the template repo**

Click on:

```
a3-template
```

**3. Create your own repo**

* Click the green **“Use this template”** button
* Select:
  * **Owner:** `cs1998-601-sp26`
  * **Repository name:** `NETID-a3` (replace NETID with your NetID)
* Click **“Create repository”**
* Choose **"private"**

**4. Clone your repo**

On your newly created repo page:

* Click the green **“Code”** button
* Copy the SSH URL

Then run in your terminal (from the directory you want your files to end up in):

```
git clone <PASTE_URL_HERE>
cd NETID-a3
```

**5. Start working**

Open the project and begin coding.

**6. Save your work (commit + push)**

Whenever you make changes:

```
git add .
git commit -m "your message"
git push
```

* you can also use [**github desktop**](https://desktop.github.com/download/)**,** but we encourage you to play with the command line interface.

## Overview

***

In this assignment, you will be creating a “social media” app. You only have to worry about the UI for now!

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/course-content/office-hours). **Please do not publicly post your code on Ed Discussion.**&#x20;

## Grading Rubric

***

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

<table data-header-hidden><thead><tr><th width="374"></th><th></th></tr></thead><tbody><tr><td><mark style="color:blue;"><strong>PART I: Creating the Post model</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>F: Post has all required properties (name, text, likes, timestamp)</td><td>_ / 1</td></tr><tr><td>F: Mock data created (at least 4 posts in <code>posts</code> array)</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART II: Building PostView</strong></mark></td><td><mark style="color:blue;"><strong>_ / 3</strong></mark></td></tr><tr><td>UI: Header (name, date, image)</td><td>_ / 1</td></tr><tr><td>UI: Post Message</td><td>_ / 1</td></tr><tr><td>UI: Like Button + Number of Likes</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART III: Wiring up the feed</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>F: ForEach renders posts dynamically</td><td>_ / 1</td></tr><tr><td>UI: Each cell is unique and represents a different Post</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART IV: Creating a New Post</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>F: post button adds a new post and adds it to the feed</td><td>_ / 1</td></tr><tr><td>F: NewPostView can modify the posts array in ContentView</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>OTHER</strong></mark></td><td><mark style="color:blue;"><strong>_ / 1</strong></mark></td></tr><tr><td>Feedback Survey</td><td>_ / 1</td></tr><tr><td><mark style="color:green;"><strong>SUBTOTAL</strong></mark></td><td><mark style="color:green;"><strong>_ / 10</strong></mark></td></tr><tr><td>Deduction: Crash Tax</td><td>-1 point</td></tr><tr><td>Deduction: Submitting Empty Posts</td><td>-1 point</td></tr><tr><td><mark style="color:green;"><strong>GRAND TOTAL</strong></mark></td><td><mark style="color:green;"><strong>_ / 10</strong></mark></td></tr></tbody></table>

## Getting Started

***

### Using Figma

Similar to A2, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

You shouldn't worry about the extra credit frames!

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a3`</mark> should contain an Xcode project called <mark style="color:red;">`A3.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard.

## Extension Files

***

### `Date+Extension.swift`

**DO NOT EDIT THIS FILE!** This file contains a function <mark style="color:red;">`convertToAgo`</mark> that returns a string representation of the <mark style="color:red;">`Date`</mark> object indicating how long ago this post was created. You will call this function on the property holding the post’s date when you create your custom collection view cell.

### `UIColor+Extension.swift`

**DO NOT EDIT THIS FILE!** Similar to A2, this file contains colors that are featured in the [Figma](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1) design. To use the colors, simply type <mark style="color:red;">`UIColor.a3.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fq5I0dUR2sGvei9vwAJJl%2FUntitled.png?alt=media&amp;token=0d1e2ed0-6665-44de-8807-4e4392a9cb82" alt="" width="226"><figcaption><p>From the Figma Design</p></figcaption></figure>

## Part I: Creating `Post` Model

***

Your first task is to define the `Post` model in `Post.swift`.

You'll notice the struct already has `let id = UUID()` and conforms to `Identifiable`. This is required so that SwiftUI can uniquely identify each `Post` when rendering a list, each post automatically gets its own unique ID.

You will need to add properties for the post's name, body, likes, and timestamp. You must figure out the appropriate type for each property. However, the timestamp property should use the `Date` type. Calling `Date()` returns the current date and time at the moment it's created. For example:

```swift
let now = Date() // captures the current date and time
```

To display a `Date` as a human-readable relative string (e.g. "10 min. ago"), use the provided `convertToAgo()` extension:

```swift
someDate.convertToAgo() // → "10 min. ago"
```

Because you have not implemented networking yet, you will need to create dummy data to test the UI. When creating your mock posts, use `Date()` for the timestamp. For the other fields, you can customize however you like. Create at least 4 mock posts and store them in the `posts` array in `ContentView`.

Once you are done, stage, commit, and push to GitHub.

## Part II: Building `PostView`

***

Your task is to build `PostView` in `PostView.swift`. This view represents a single post in the feed.

`PostView` should accept a `Post` as a property (input) and display the following:

* Name (e.g. "Anonymous")
* Profile Picture (you can use any image you like! Either import it through the asset library, or use a system image)
  * Look at [SF Symbols](https://developer.apple.com/design/human-interface-guidelines/sf-symbols) where you can find system images (or ask AI)
  * This image will be identical for all posts (that's why our post model doesn't include it)
* Timestamp: use the provided `convertToAgo()` function on your `Date` property to format it as a relative time string (e.g. "10 min. ago")
* Post message body: limit to 3 lines of text
* Like button: use a non-filled heart icon (`Image(systemName: "heart")`) for now
* Number of likes

Use the provided color extensions for styling. Colors are accessed via `Color(UIColor.a3.ruby)`, `Color(UIColor.a3.white)`, `Color(UIColor.a3.silver)`, etc. Keep in mind the background color, text color, font weight, corner radius, and padding. Look at `NewPostView` as a reference for styling conventions.

Once you are done, stage, commit, and push to GitHub.

## Part III: Wiring Up the Feed

***

Your task is to connect everything together in `ContentView`.

There is already some code written that you will need to look over. `NewPostView` represents the "Create Post" card and is already implemented for you. Read and understand the code written in this view.

1. Consider making posts something that SwiftUI can observe so updates propagate automatically.
2. Pass the corresponding `Post` to each `PostView`.
   1. Hint: go through wednesday's demo if you get stuck
3. Make sure posts are showing up correctly
   1. add/delete posts from the array, does it behave as expected?

If you can see the `NewPostView` at the top followed by your list of mock posts, you should be good to go.

Once you are done, stage, commit, and push to GitHub.

## Part IV: Creating a Post

***

Your task is to hook up the "Post" button in `NewPostView` so that it creates a new post and adds it to the feed. We need this post to NOT be empty. You will lose 1 point if you can submit empty posts.

Think about the following as you work on this:

* How can `NewPostView` let the parent view know when a new post is added? (think about property wrappers)
* When creating `NewPostView` in the parent, how can it stay in sync with the parent’s list of posts?
* What should happen when the user taps “Post” so the feed updates correctly and the input is ready for a new post? (how do we add an element to an array?)
* How can the button know when it should be active or disabled? (should I be able to submit empty posts?)
  * Use this modifier `.disabled(Boolean_Value)` on the button (disables the button if `Boolean_Value == true` )

Once you are done, stage, commit, and push to GitHub.

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a3.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://docs.google.com/forms/d/e/1FAIpQLSf-82p3c7K85EZqG6-cSB-jASQvrT7-I8Dcr_i_99EASST6EQ/viewform?usp=sharing\&ouid=118188825185295730350) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# Week 5 | Networking


# Monday | Networking I

Spring 26

## Lecture slides

{% embed url="<https://docs.google.com/presentation/d/1UGRG7MrRbZifamZYLyJad0QgXZx7f_4MOSWuK__sSro/edit?usp=sharing>" %}

## Video:

{% hint style="info" %}
The postman demo was not captured in the recording, I also posted the recording from last semester below, note that the code block in last semester's video is in UIKit. You can also follow the postman guide.
{% endhint %}

{% embed url="<https://youtu.be/YTMdYpp5Ir4>" %}

### FALL 25 video

{% embed url="<https://www.youtube.com/watch?index=6&list=PLjf6nsEcF5KP6QEdCiTxOZtSIEhoqslCn&v=t7UHFqxVbqY>" %}


# Wednesday | Networking II

Spring 2026

<details>

<summary>Networking Follow-Along</summary>

## Using git in Terminal

#### 1. Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/networking-II-demo
</strong></code></pre>

#### 2. Follow Along!

</details>

<details>

<summary>How to access the solution code</summary>

You have two options:

1. Through the GitHub website
   1. Go to <https://github.com/intro-to-ios/networking-II-demo>
   2. Press the button that says main (this will show all the branches in this repo)
   3. Choose the branch you want!
2. Through the terminal
   1. restore your changes or stach them
      1. `git restore .` or `git stash push`
   2. Checkout to the solution branch
      1. `git checkout <branch-name>`&#x20;
   3. Now your should have the solution code

</details>

{% hint style="info" %}
The last two slides were not covered in the lecture. You can read through them for an alternative way of doing .onAppear(). You could use any of the two in A3.5.
{% endhint %}

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1Jh69VZ8tIQyLM2PN18SAO0Trrq-KLrXkmpKmqjeF-iQ/edit?usp=sharing>" %}

### Spring 2026 Lecture Video

{% embed url="<https://youtu.be/o_PyKdmxml0>" %}

### Fall 2025 Lecture Video

{% embed url="<https://youtu.be/gm4zGPa-aeU?si=UfFETDH678-Mylag>" %}


# A3.5: ChatDev — Networking

Original Author: Vin Bui | New Changes: Jay Zheng

{% hint style="danger" %}
**Due: Monday, Apr 20, 2026 11:59 pm**
{% endhint %}

### Overview

In this assignment, you will be extending your A3 ChatDev app to integrate networking. You will be using **URLSession** (Swift's built-in networking API) to send HTTP requests to a backend endpoint to fetch and create posts, replacing the any dummy data you used in A3. You will also implement liking a post.

***

### Learning Objectives

**Developer Skills**

* **How to use Postman to test HTTP requests**
* **How to read data received from the backend to structure frontend code**
* How to work with Git and GitHub for version control
* How to read documentation from outside resources

**Course Material**

* How to send **GET** requests to a backend API using URLSession
* How to send **POST** requests to a backend API using URLSession
* How to use `async/await` to handle asynchronous networking calls
* How to create a `NetworkManager` singleton class to contain network calls
* How to decode a JSON using a `JSONDecoder` in Swift
* How to handle errors with networking calls

***

### Academic Integrity

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

***

### Getting Help

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit office hours. **Please do not publicly post your code on Ed Discussion.**

The feedback form link is located in the Submission section of this handout.

***

### Grading Rubric

* **UI** : implements the user interface
* **F** : implements the functionality
* **EC** : extra credit

|                                                                        | Points                                                |
| ---------------------------------------------------------------------- | ----------------------------------------------------- |
| <mark style="color:$primary;">**PART I: Setting Up Networking**</mark> | <mark style="color:$primary;">**\_ / 2**</mark>       |
| F: `NetworkManager` singleton created with URLSession                  | \_ / 1                                                |
| F: `Post` model updated to be `Codable` / `Decodable`                  | \_ / 1                                                |
| <mark style="color:$primary;">**PART II: Fetching Posts**</mark>       | <mark style="color:$primary;">**\_ / 3**</mark>       |
| F: GET request fetches posts from the backend                          | \_ / 2                                                |
| F: Pull-to-refresh reloads posts                                       | \_ / 1                                                |
| <mark style="color:$primary;">**PART III: Creating a Post**</mark>     | <mark style="color:$primary;">**\_ / 3**</mark>       |
| F: POST request creates a post on the backend                          | \_ / 2                                                |
| F: Feed updates after creating a post                                  | \_ / 1                                                |
| <mark style="color:$primary;">**PART IV: Liking a Post**</mark>        | <mark style="color:$primary;">**\_ / 2**</mark>       |
| F: POST request to like a post                                         | \_ / 1                                                |
| F: ❤️ turns red if liked, number of likes goes up                      | \_ / 1                                                |
| <mark style="color:$success;">**SUBTOTAL**</mark>                      | <mark style="color:$success;">**\_ / 10**</mark>      |
| EC: POST Request to Unlike a Post                                      | + 1                                                   |
| EC: Sort by Top/New posts                                              | + 1                                                   |
| EC: Animation when liking a Post                                       | + 1                                                   |
| Deduction: Crash Tax                                                   | -1 point                                              |
| <mark style="color:$success;">**GRAND TOTAL**</mark>                   | <mark style="color:$success;">**\_ / 10 (+3)**</mark> |

***

### Getting Started

#### Using Postman

You are encouraged to use [Postman](https://www.postman.com/downloads/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

#### Using Figma

The Figma designs from A3 still apply. You can find the link to the Figma [\[here\]](https://www.figma.com/design/kzgaF8pBYQLgjyWDyIzKSh/A3--ChatDev?node-id=1-1199\&t=TeP2K9BVE8BCj1QG-0). If you do not have an account, you can create one under your Cornell email.

#### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under Understanding Git and GitHub section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** `git add .`
2. **Commit:** `git commit -m "YOUR MESSAGE HERE"`
3. **Push:** `git push`

#### Opening the Project

Continue working in the same repository from A3. Your project should already contain your completed SwiftUI views from A3.

***

### Endpoints

* **Endpoint:** `https://ios-course-backend.cornellappdev.com/`

|                 | Type | Route                         | Request Body       |
| --------------- | ---- | ----------------------------- | ------------------ |
| Fetch all posts | GET  | `/api/posts/`                 | None               |
| Create a post   | POST | `/api/posts/create/`          | `message` (String) |
| Like a post     | POST | `/api/posts/{postId}/like/`   | `netId` (String)   |
| Unlike a post   | POST | `/api/posts/{postId}/unlike/` | `netId` (String)   |

***

## Part I: Setting Up Networking

#### Updating the Post Model

In A3, your `Post` model used local dummy data. Now you need to update it to work with data from the backend.

Here is an example post object in JSON fetched from the backend:

```json
{
    "id": "7m03J198pyXFBvCOLNbw",
    "likes": ["vdb23", "rs929"],
    "message": "Howdy!",
    "time": "2023-06-12T22:03:23Z"
}
```

Update your `Post` struct so that:

* It conforms to `Codable` (or at least `Decodable`)
* Its properties match the JSON keys from the backend (`id`, `likes`, `message`, `time`)
* The `time` property should remain a `Date` type — you will handle decoding this in the `NetworkManager`
* The `likes` property should be an array of strings (`[String]`)

> ⚠️ Because the backend provides its own `id`, you may need to adjust how your model handles identity (e.g., remove `let id = UUID()` and use the backend-provided `id` instead). Make sure your model still conforms to `Identifiable`.

#### Creating the NetworkManager

Create a new file called `NetworkManager.swift`. This will be a **singleton** class that contains all of your networking functions.

```swift
class NetworkManager {
    static let shared = NetworkManager()
    private init() {}

    let baseURL = "https://ios-course-backend.cornellappdev.com"

    // You will add your networking functions here
}
```

Once you are done, stage, commit, and push to GitHub.

***

## Part II: Fetching Posts

**Your task is to send a GET request using URLSession to fetch all posts from the backend.** Currently, your posts are all hard-coded dummy data. We want to be able to receive posts created by other people, so we must integrate networking.

#### Testing with Postman

Before writing any code, test the endpoint in Postman:

1. Add a new **GET** request
2. Enter the URL: `https://ios-course-backend.cornellappdev.com/api/posts/`
3. This should return a list of all posts from the backend with a **200** status code

#### Writing the Network Call

In `NetworkManager`, create a function to fetch all posts. Since we are using Swift's `async/await`, your function should be marked as `async throws` and return `[Post]`. You can decode the `time` field to a `Date` object by setting the decoder's `dateDecodingStrategy` to `.iso8601`. For example:

```swift
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
```

Make sure to handle errors properly in your code.

#### Integrating with SwiftUI

Once you have your fetch function, call it from your `ContentView` to populate the posts array. Use the `.task` modifier to trigger the fetch when the view loads. Since your networking function is `async`, you can call it directly inside `.task`

```swift
.task {
    do {
        posts = try await NetworkManager.shared.fetchPosts()
    } catch {
        print(error)
    }
}
```

Make sure your `@State` posts array updates on the main thread (SwiftUI handles this automatically when using `.task`).

#### Pull to Refresh

Add pull-to-refresh to your feed using the `.refreshable` modifier in SwiftUI:

```swift
List {
    // your content
}
.refreshable {
    // call your fetch function here
}
```

> 💡 If you are using a `ScrollView` + `LazyVStack` instead of a `List`, you can still use `.refreshable` on the `ScrollView`.

Once you are done, stage, commit, and push to GitHub.

***

### Part III: Creating a Post

**Your task is to send a POST request using URLSession to add a post to the backend.**

#### Testing with Postman

A good rule of thumb is to always use Postman before writing the code.

1. Add a new request to your collection with a **POST** method
2. Enter the URL: `https://ios-course-backend.cornellappdev.com/api/posts/create/`
3. Click on the **Body** tab, select **raw**, and change the blue dropdown from "Text" to **JSON**
4. This request expects the following body:

```json
{
    "message": "<Enter some message here>"
}
```

If successful, the server returns a **201** status code with JSON data representing the post that was just created. **You do not need to do anything with this information for this assignment**, but it is common practice for the backend to return this data. If you fetch all posts again, either through Postman or your app, you should see the new post that you created.

#### Writing the Network Call

Create a function in `NetworkManager` that uses URLSession to make the call. Remember that this is a **POST** request with a request body parameter called `message`. You will need to:

1. Create a `URLRequest` and set its `httpMethod` to `"POST"`
2. Set the `Content-Type` header to `"application/json"`
3. Encode the request body as JSON data and assign it to `httpBody`
4. Use `URLSession.shared.data(for:)` to send the request

Here is the general pattern:

```swift
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try JSONEncoder().encode(body)
let (data, _) = try await URLSession.shared.data(for: request)
```

Proper error handling is highly recommended.

#### Integrating with SwiftUI

Hook up the "Post" button in `NewPostView` so that:

1. When the user taps "Post", it sends the POST request to the backend
2. If the call is successful, clear the text field and refresh the feed
3. Empty posts should still not be submittable (keep your `.disabled` logic from A3)

{% hint style="info" %}
Since your networking functions use `async/await`, you can wrap the call in a `Task { }` block inside your button action.
{% endhint %}

Once you are done, stage, commit, and push to GitHub.

***

### Part IV: Liking a Post

**Your task is to send a POST request using URLSession to like a post.**

#### Before Networking

First, configure the like button to be **filled** with the color **ruby** if the post's `likes` array contains your NetID. Otherwise, it should show the non-filled heart.

#### Testing with Postman

1. Add a new request to your collection with a **POST** method
2. Enter the URL: `https://ios-course-backend.cornellappdev.com/api/posts/{postId}/like/`
   * Note that `{postId}` is the ID of the post. Use string interpolation here.
3. Click on the **Body** tab, select **raw**, and change the blue dropdown from "Text" to **JSON**
4. This request expects the following body:

```json
{
    "netId": "<Enter your NetID>"
}
```

You will use your NetID (all lowercase). If the call is successful, you should receive the updated post.

#### Writing the Network Call & Integrating

Create a function in `NetworkManager` for liking a post. There are many ways you can go about this. One recommendation is to pass a boolean to the callback to indicate whether or not the call was successful. If the call is successful, make the like button filled and increment the count by 1. Additionally, you should only be able to tap on the button if it is not already filled red, so wrap your network request in an `if` statement.

You may notice that there is a delay before the button turns red when tapping on it. In apps like Instagram, usually the UI changes even if the API call fails. However, for the sake of simplicity and grading, we want the button to only turn red if the network call succeeds.

Once you are done, stage, commit, and push to GitHub.

***

## Extra Credit

{% hint style="info" %}
Extra credit will only be given if the features are **fully** implemented. These are unordered and you can choose as many as you like.
{% endhint %}

#### 1: Unlike a Post (+1 pt)

**Your task is to send a POST request using URLSession to unlike a post.** This may seem similar to Part IV, but it requires some additional frontend logic. When grading for this, we will unlike a post and refresh to make sure the backend is actually updated. If you try to unlike a post in which the given NetID does not already like it, you will get an error. You can test this out on Postman. The URL is `https://ios-course-backend.cornellappdev.com/api/posts/{postId}/unlike/`.

#### 2: Sort by Top/New Posts (+1) <a href="#id-2-sort-by-top-new-posts-1" id="id-2-sort-by-top-new-posts-1"></a>

If you take a look at the [Figma](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1) file, you should see a design containing the text “Top” and “New”. **Your task here is to sort the posts by the # of likes (top) and the most recent (new)**. For example, if the selected tab is “Top”, the post with the most likes will be at the top. If the selected tab is “New”, the most recent post will be at the top. Make sure that the color of the tab changes depending on what is selected.

#### 3: Like Animation (+1) <a href="#id-3-like-animation-1" id="id-3-like-animation-1"></a>

**Your task here is to add some animation when liking a post**. You could add a scaling animation similar to most social media apps or do some other cool animation. As long as there is some animation when liking a post, you will get full credit.

{% hint style="info" %}
SwiftUI makes animations easy — check out `.scaleEffect()`, `.animation()`, and `withAnimation {}`.
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**&#x20;

***

### Submission

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download the TXT file and fill it out. Make sure to use the **Clone SSH path**.
5. Confirm that your `submission.txt` is formatted like the following and submit it on CMSX.

```
Name: Your Name
NetID: your_netid
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-sp26/NETID-a3.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://docs.google.com/forms/d/e/1FAIpQLSeVPkDFFlFK5Zf65Ns9dOHx_VdnhNmpCTlrjUvn5HxoGIB4kA/viewform?usp=publish-editor) (worth 1 point).

{% hint style="info" %}
If you are partnered, make sure to create a group on CMS and put both names in the `submission.txt` file. Both students must fill out the feedback survey to receive credit.
{% endhint %}


# Week 6 | MVVM, CreateML, and CoreML


# Monday | MVVM

Spring 26

<details>

<summary>MVVM Follow-Along</summary>

## Using git in Terminal

#### 1. Clone the Repository

{% hint style="info" %}
We will be adding onto the last demo from lecture 9
{% endhint %}

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/networking-II-demo
</strong></code></pre>

#### 2. Checkout to correct branch

<pre class="language-sh"><code class="lang-sh"><strong>git checkout post-requests
</strong></code></pre>

#### 3. Follow Along!

</details>

<details>

<summary>How to access the solution code</summary>

You have two options:

1. Through the GitHub website
   1. Go to <https://github.com/intro-to-ios/networking-II-demo>
   2. Press the button that says main (this will show all the branches in this repo)
   3. Choose the branch you want!
2. Through the terminal
   1. restore your changes or stach them
      1. `git restore .` or `git stash push`
   2. Checkout to the solution branch
      1. `git checkout <branch-name>`&#x20;
   3. Now your should have the solution code

</details>

## Lecture slides

{% embed url="<https://docs.google.com/presentation/d/1wF-PnTQYZynMxdYX02_P6jWq6vd1WUIMflSt2cwfz3s/edit?usp=sharing>" %}

{% hint style="info" %}
Read more about [Enums & Switches](/resources/swift-foundations/enums-and-switches)
{% endhint %}

### Spring 2026 Lecture Video

### Fall 2025 Lecture Video


# Wednesday | CoreML and CreateML

Spring 2026

<details>

<summary>SwiftUI Follow-Along</summary>

## Using git in Terminal

#### 1. Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/networking-II-demo
</strong></code></pre>

#### 2. Follow Along!

</details>

<details>

<summary>How to access the solution code</summary>

You have two options:

1. Through the GitHub website
   1. Go to <https://github.com/intro-to-ios/networking-II-demo>
   2. Press the button that says main (this will show all the branches in this repo)
   3. Choose the branch you want!
2. Through the terminal
   1. restore your changes or stach them
      1. `git restore .` or `git stash push`
   2. Checkout to the solution branch
      1. `git checkout <branch-name>`&#x20;
   3. Now your should have the solution code

</details>

{% hint style="info" %}
The last two slides were not covered in the lecture. You can read through them for an alternative way of doing .onAppear(). You could use any of the two in A3.5.
{% endhint %}

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1Jh69VZ8tIQyLM2PN18SAO0Trrq-KLrXkmpKmqjeF-iQ/edit?usp=sharing>" %}

### Spring 2026 Lecture Video

{% embed url="<https://youtu.be/o_PyKdmxml0>" %}

### Fall 2025 Lecture Video

{% embed url="<https://youtu.be/gm4zGPa-aeU?si=UfFETDH678-Mylag>" %}


# A4: ChefOS - SwiftUI

Original project authored by Vin Bui, adapted to SwiftUI by Daniel Chuang

{% hint style="danger" %}
**Due: Monday May 4th, 2026 11:59 pm**
{% endhint %}

{% hint style="info" %}
**For this assignment, please make a blank SwiftUI project. We're starting from scratch! Make sure to submit via your Cornell repo though, more info below**
{% endhint %}

## Overview

***

In this assignment, you will be creating a recipe book app. You will be able to fetch recipes from a server, and filter by category

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/course-content/office-hours). **Please do not publicly post your code on Ed Discussion.**

## Grading Rubric

***

{% hint style="info" %}
**Due to the shrinking of the course, the features implemented up to the midpoint submission will be worth more than after.**
{% endhint %}

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Recipe CollectionView**</mark>                                                | <mark style="color:blue;">**\_ / 5**</mark>        |
| ----------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| UI: Name, Image, Rating                                                                                           | \_ / 2                                             |
| UI: 2 columns, Dynamic number of cells (adding a new item to the array creates a new item/cell)                   | \_ / 2                                             |
| UI: Each cell is unique and represents a different Recipe                                                         | \_ / 1                                             |
| <mark style="color:blue;">**PART II: Detailed Recipe View**</mark>                                                | <mark style="color:blue;">**\_ / 5**</mark>        |
| UI: Image                                                                                                         | \_ / 1                                             |
| UI: Name and Description                                                                                          | \_ / 1                                             |
| F: Tapping on a Recipe cell pushes a detailed view                                                                | \_ / 3                                             |
| <mark style="color:blue;">**PART III: Filtering**</mark>                                                          | <mark style="color:blue;">**\_ / 5**</mark>        |
| UI: Collection view for filters WITH horizontal scrolling                                                         | \_ / 1                                             |
| UI: Selected filter is highlighted (separate from functionality)                                                  | \_ / 2                                             |
| F: Tapping on a filter filters the recipe data (one filter at time; stacking filters is extra credit)             | \_ / 2                                             |
| <mark style="color:blue;">**PART IV: Fetching Recipes**</mark>                                                    | <mark style="color:blue;">**\_ / 2**</mark>        |
| F: GET Request to Fetch Recipes                                                                                   | \_ / 2                                             |
| <mark style="color:blue;">**PART V: Bookmark Recipes**</mark>                                                     | <mark style="color:blue;">**\_ / 1**</mark>        |
| F: Bookmarking from the detailed view updates the collection view using delegation                                | \_ / 1                                             |
| <mark style="color:blue;">**OTHER**</mark>                                                                        | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                                                   | \_ / 1                                             |
| <mark style="color:red;">`.onAppear`</mark> or <mark style="color:red;">`.task`</mark> calls networking functions | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                                                    | <mark style="color:green;">**\_ / 20**</mark>      |
| EC: Custom back button                                                                                            | + 1                                                |
| EC: Stacking filters                                                                                              | + 1                                                |
| EC: Nesting collection views                                                                                      | + 1                                                |
| EC: Separate bookmark page                                                                                        | + 2                                                |
| Deduction: Crash Tax                                                                                              | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                                                 | <mark style="color:green;">**\_ / 20 (+5)**</mark> |

## Getting Started

***

### Using Postman

You are encouraged to use [Postman](https://www.postman.com/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

### Using Figma

Similar to A2 and A3, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

### Creating a new SwiftUI Project

Go to Xcode -> File -> New -> Project -> App -> \[MAKE SURE THAT Interface = SwiftUI] and just proceed from there via clicking Next and Create.

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Pushing to the Repository

1. Make an empty github repository on the course github <https://github.coecis.cornell.edu/cs1998-601-sp26>
2. New -> No template -> name: NETID-a4 -> Private
3. Navigate into the folder that contains the SwiftUI Project
   1. The folder should contain the .xcodeproj file and another folder with the name you chose
   2. ```sh
      git init
      ```
4. Look at the "push an existing repository from the command line" on github
   1. copy the commands into your terminal
5. This should connect your local repo to the github one, refresh github to see if the files show up there.

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

## Assignment Files

***

**Color File**

You may find the following code helpful to put into a <mark style="color:red;">`Color.swift`</mark> file, as it will allow for you to input the hex values of colors you have from Figma into Swift directly.

```swift
// Copy into a file called Color.swift
import SwiftUI

extension Color {
    init(hex: UInt, alpha: Double = 1) {
        self.init(
            .sRGB,
            red: Double((hex >> 16) & 0xff) / 255,
            green: Double((hex >> 08) & 0xff) / 255,
            blue: Double((hex >> 00) & 0xff) / 255,
            opacity: alpha
        )
    }
}
```

You will now be able to make colors via the following syntax. Note that the "0x" at the beginning is telling Swift that the proceeding values should be interpreted in hexadecimal base.

```swift
Color(hex: 0xFAFAFA)
```

{% hint style="info" %}
**Source: All of the recipes used in this assignment are from** [**allrecipes.com**](https://www.allrecipes.com/)**.**
{% endhint %}

## Part I: Recipe CollectionView

***

**Notice that on Figma, the screens are broken down into the different stages you need to implement.**

**Your first task is to create a "Collection View" to display the recipes.** We encourage using the textbook and the internet for syntax and modifier help! We will not guide you as much as we did with the other assignments, but here is a general blueprint for what to do:

1. Set up your Recipe struct and dummy data using data from this [Pastebin](https://pastebin.com/KPrsHR38) link. Make sure the struct's properties align with the Pastebin format!
2. Make a RecipeCell view in a new file called <mark style="color:red;">`RecipeCell.swift`</mark>
   1. Set up a preview if you'd like!
   2. Add a property to the view called <mark style="color:red;">`recipe`</mark> which should allow for you to input any recipe you want from your dummy data (so your string should be using recipe.\[property])
   3. Use an AsyncImage for putting in the recipe's image. Refer to Swift [documentation](https://developer.apple.com/documentation/swiftui/asyncimage) for a reference on how to do this.
3. Now, in ContentView, you'll want to set up a LazyVGrid in order to get the grid with 2 columns. Refer to the Swift [documentation](https://developer.apple.com/documentation/swiftui/lazyvgrid#:~:text=struct-,VerticalSmileys,-%3A%20View%20%7B) for this!&#x20;
   1. Unlike a normal VStack, we need to initialize columns and input that as a parameter, so make sure to do that
   2. After that, just write a ForEach inside of the LazyVGrid. You might need to make sure that your Recipe struct conforms to certain things before you can proceed with this, but XCode should tell you exactly what you need to do in this regard!
   3. Wrap your LazyVGrid with a ScrollView
4. Wrap your LazyVGrid + ScrollView component in a VStack, and add some text right above it in the VStack that says "ChefOS" just how the Figma has it (so the scroll only scrolls through the items, not the ChefOS title)
5. Make your your styling matches the Figma!

Side notes:

* You are not required to implement the bookmark icon until Part V, but you are free to do so now.
* You will not be implementing the filters until Part III.
* You do not have to worry about dynamic cell size. Set the text labels’ line limit to <mark style="color:red;">`2`</mark> lines and the height of the cell to around <mark style="color:red;">`216`</mark>. The width, however, will depend on the size of the screen. Remember, we want to have two columns. *Hint: We can multiply/divide the screen’s width by a certain factor.*
* **Do not save recipe images in the Assets catalog. You must use AsyncImage for displaying these images**

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Detailed Recipe View

***

**Your task is to create a view controller representing a detailed recipe view.** You will push this view controller when tapping on the collection view cell. This detailed view will be unique to the recipe.

**Detailed Recipe Page**

This is very straight-forward and there aren’t any tricks. Make a new view called <mark style="color:red;">`RecipePage.swift`</mark>  and implement what you see on Figma. Make sure that recipe is a property of the view (like before) so that you can input the recipe you want as a parameter.&#x20;

Remember to use AsyncImage to download the images (feel free to copy and paste).

**Navigating to the Detailed Recipe Page**

This is super simple: first, wrap your ENTIRE ContentView in a NavigationView. Then, wrap each of your RecipeCells in the ForEach from before with NavigationLink, with a destination parameter of RecipePage(recipe: recipe). Feel free to refer back to SwiftUI II's lecture for a code snippet on this.

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Filtering

***

**Your task is to create a horizontally scrolling collection view that represents the filter pills as well as adding filtering functionality.**

Here is a quick demo of what we’re expecting:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FjSiKmRla1i22MGjXdrUv%2Fa4_part3.gif?alt=media&amp;token=3acc89cf-2c0d-48b7-9b69-18f748ae33f1" alt="" width="221"><figcaption></figcaption></figure>

### Adding a Filter Collection View

In UIKit, this would be very difficult. Thankfully for you, you're coding in SwiftUI!

1. Make a selectedDifficulty property in ContentView and make a difficulties property in ContentView. Feel free to copy this in, as long as you understand why we will need the @State. Your default selectedDifficulty should be "All"

```swift
@State private var selectedDifficulty = "All"
private let difficulties: [String] = ["All", "Beginner", "Intermediate", "Advanced"]
```

2. Make a ScrollView containing a HStack between the ChefOS title and your recipe cells. The following shows how to allow for horizontal scrolling.

```swift
ScrollView(.horizontal, showsIndicators: false)
```

3. Make a ForEach in this HStack that looks through difficulties. You will need to set it up with the id parameter as well, since difficulties doesn't conform to identifiable.

```swift
ForEach(difficulties, id: \.self) {
    ...
}
```

4. Make these little capsule filter buttons inside the for each. One way to do this is by making each of them a Button. The code / function that the Button actually calls should be as easy as setting selectedDifficulty = Difficulty. Then, make the label a Text component that uses the .background() modifier with a capsule inside

<pre class="language-swift"><code class="lang-swift"><strong>Text(difficulty)
</strong><strong>// fonts and other modifiers
</strong><strong>.background(  Capsule()
</strong>                // more modifiers here for the Capsule specifically
                )
</code></pre>

### Filtering Logic

* You ***do not*** need to handle filter stacking. This is somewhat advanced so we will leave that for extra credit.
* There are many ways to determine if a cell is selected, so I will leave this up to you to decide. Make sure that the currently selected tab is highlighted with a white text color. If you are lost and have no idea where to start, feel free to ask on Ed Discussion or come to office hours.
* To filter the array of recipes, you can use the <mark style="color:red;">`filter`</mark> higher order function. Feel free to look up documentation for this, or just check out A1.

**Once you are done, stage, commit, and push to GitHub.**

## Part IV: Fetching Recipes

***

**Your task is to create a GET request to fetch all recipes from this API:**

```
https://api.jsonbin.io/v3/b/64d033f18e4aa6225ecbcf9f?meta=false
```

You can use Postman to test the HTTP request. You will need to create a <mark style="color:red;">`NetworkManager`</mark> class with a <mark style="color:red;">`shared`</mark> singleton instance. You will be using async/await. See the L9, textbook, or use the internet as a reference.

Error handling is not required but is nice to have. You will know if you integrated it correctly if there are more recipes than the dummy data. As a reminder, the JSON uses snake\_case but Swift uses camelCase.

Networking is one of the most important but difficult concepts to learn and implement. We want you to get as much practice as you can to prepare you for the Hack Challenge. If you are confused, please create a post on Ed Discussion or visit office hours.

**One caveat for SwiftUI is that you will need to call your fetch function (e.g. NetworkManager.fetchRecipes()) inside of a .onAppear modifier instead of viewDidLoad() like in UIKit**

You'll need to update your model for recipe to make ID into a UUID instead of a string, like this:&#x20;

```swift
var id: UUID?
```

Next, add coding keys into your recipe struct:

```swift
enum CodingKeys: String, CodingKey {
    case id, description, difficulty, imageUrl = "image_url", name, rating
}
```

Make two init functions for the recipe struct, one that is a default initializer for your dummy data, and another is a networking initializer for fetching. This is how you should do the networking initializer. I will post an Ed post explaining this so look at it to understand what this does.

```swift
init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // Convert string ID to UUID
        if let idString = try container.decodeIfPresent(String.self, forKey: .id) {
            self.id = UUID(uuidString: idString)
        } else {
            self.id = nil
        }
        
        // Decode the rest of the properties normally
        self.description = try container.decode(String.self, forKey: .description)
        self.difficulty = try container.decode(String.self, forKey: .difficulty)
        self.imageUrl = try container.decode(String.self, forKey: .imageUrl)
        self.name = try container.decode(String.self, forKey: .name)
        self.rating = try container.decode(Float.self, forKey: .rating)
    }
```

**Finally, check that your networking is actually working. Make sure you see King Pao Chicken in your recipes in the app - that is a recipe that is in the endpoint but not the dummy data.**

{% hint style="danger" %}
**Make sure that filtering still works properly!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Bookmark Recipes

***

**Your task is to implement bookmarking functionality for these recipes.** You will need a way to keep track of bookmarked recipes to save them locally via UserDefaults. We will also have an Ed post out for UserDefaults!

* First, figure out what data structure you will use to keep track of bookmarked recipes. Then, think of a key that you will use to access through UserDefaults. My recommendation is that you use a BookmarkManager that is a singleton instance.
* In your BookmarkManager, you'll want to include:
  * @Published bookmarkRecipesIds, which is a Set\<UUID> (set of UUIDs from your recipe ids).
  * saveBookmarks() function that uses UserDefaults.set
  * loadBookmarks() function that loads from UserDefaults
  * toggleBookmarks() function that adds or removes the ID from bookmarkRecipeIds, and calls saveBookmarks afterwards
  * an init function that calls loadBookmarks()
* Then, in ContentView, RecipePage, and RecipeCell, set up an @StateObject called bookmarkManager that is equal to BookmarkManager.shared. If you don't make it a State object and instead use BookmarkManager.shared directly, your bookmark icons will not be updated!
* You'll need to use the <mark style="color:red;">`.onAppear{}`</mark> modifier on your views to make sure that the view gets the data from BookmarkManager.
* Update the UI so that recipes that are bookmarked should have a bookmark icon in their cell. See the Figma for UI details. See the point below on how to get the bookmark icon.
  * You will need to create a <mark style="color:red;">`ToolbarItem`</mark> to represent the bookmark button in RecipePage. This button will be in the detailed recipe view on the top right corner. If the recipe is already saved, the bookmark button will be filled and tapping on it will remove it from the saved recipes. You can add this to your RecipePage by using the <mark style="color:red;">`.toolbar{}`</mark>modifier at the end of the RecipePage and putting ToolbarItem wrapping a Button wrapping <mark style="color:red;">`Image(systemName: "bookmark")`</mark>  or <mark style="color:red;">`Image(systemName: "bookmark.fill")`</mark>
  * Adding the bookmark to the RecipeCell should be as easy as just putting the bookmark image in an if statement.&#x20;
* All saved recipes should be stored locally. You can check by restarting the app. If the saved recipes do not reset, then you are good to go.

Here is a quick demo of what we are looking for:

{% file src="/files/OJ2hEDPeJJYPDanjBwOq" %}

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Custom Back Button (+1 pt)

**Your task is to create a custom back button.** The [Figma](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1) has a possible design for this, but you are free to use any button you like. This should be a freebie if you finished the task in Part V.

### 2: Stacking Filters (+1)

Right now, you can only select one filter at a time. **Your task is to allow for filter stacking**. All selected filters should be highlighted and the collection view should contain all selected filters.

### 3: Nesting CollectionViews (+1)

Right now, you have two separate collection views: one for the filters and the other for the recipes. Because these collection views have different scrolling directions, if we wanted to make them both scrollable vertically, then we will have to nest collection views. **Your task here is to nest collection views so that the filters scroll with the recipes.** In other words, if I scroll up, the filters should scroll up as well while maintaining its horizontal scrolling attribute.

### 4: Separate Bookmark Page (+2)

**Your task here is to create a page listing out all bookmarked recipes.** The design is up to your creativity, but there needs to be some way to push the detailed recipe view where you can then bookmark/unbookmark. You may also need to use delegation to update this bookmark list, similar to what you did in Part V.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
+1 : ____
+2 : ____
```

6. Fill out this [feedback survey](https://forms.gle/q5yAHdh5CxNTDuJu7) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# Machine Learning on iOS

Spring 2026 | Jay Zheng

## What is Machine Learning?

Normally when you write a program, you spell out every rule explicitly — *"if the pixel is red, do this; if it's blue, do that."* That works fine for simple logic, but it breaks down fast for complex tasks like recognizing a cat in a photo. There are too many rules to write by hand.

Machine learning flips this around. Instead of writing the rules yourself, you feed the computer a pile of **data** (say, thousands of labeled photos) and let an **algorithm** figure out the rules on its own. That process produces a **model**.

> Core idea: **Data + Algorithm -> Model**

Think of the model as a **black box** — you don't need to know what's going on inside it. All you need to know is:

* It takes some **input** (an image, a sentence, a number).
* It produces some **output** (a label, a score, a prediction).

\
For example, in this demo app below, the input is a photo and the output is a label like *"golden retriever — 94% confident."*

The algorithm you choose depends on what you're trying to do. Classifying images calls for a different algorithm than predicting house prices or generating text. That's most of what machine learning research is about — figuring out which algorithms work best for which problems (you can learn more in CS 3780). For this demo, we're using a pre-trained neural network called **MobileNetV2** that's already been tuned for image classification.

## Machine Learning on iOS

When you hear "AI" or "ML," you probably think of something that lives in the cloud — you send a request to ChatGPT or Claude, OpenAI's or Anthropic's servers process it and you get a response back.

iOS does it differently. Apple wanted ML to run **on the device itself**, for a few reasons:

* **Privacy** — your data never leave the phone.
* **Speed** — Light weight model and instant result.
* **Offline** — Not wifi/cellular network dependent.
* **No server costs** — you don't pay for token.

To make this practical, Apple built a stack of frameworks:

| Framework            | What it does                                                                                    |
| -------------------- | ----------------------------------------------------------------------------------------------- |
| **Core ML**          | Runs ML models on the iPhone's chips, and Neuro Engine introduced in 2017 with A11 Bionic Chip. |
| **Vision**           | High-level wrapper for image tasks (classification, face/text detection).                       |
| **Natural Language** | Same idea, but for text.                                                                        |
| **Create ML**        | An app that lets you *train* your own models without writing ML code.                           |

The model file format Apple uses is `.mlmodel`. You drag one into your Xcode project and Xcode automatically generates a Swift class for it — that's why you can write `MobileNetV2()` in code below without ever defining that class yourself.

To get started, visit each explandable below

* **Demo** has a working image classification app, you can try it and see how it works
* **Limitation on MobileNetV2** talks about what the model we use in the demo can not do
* **Training your own model with createML** gives you the steps to training your own ML model that you can use in your own project.

<details>

<summary><strong>Demo</strong></summary>

{% file src="/files/mJP3Pgi50xlI5FD9Ez9j" %}

How does demo app ?work

1. You tap a button, the photo picker opens
2. You pick an image, then the image is shown on the screen
3. The App runs the image through MobileNetV2, the pre-trained model that we are using
4. It outputs the confidence score

{% hint style="info" %}
None of this requires the internet
{% endhint %}

### Try the app <a href="#try" id="try"></a>

Once you have the demo running, experiment:

1. Pick photos of objects you'd expect it to know (dog, banana, laptop), if you are running on a simulator, you can find an image online and drag into the phone simulator.&#x20;
2. Pick photos of things it *won't* know (your face, a screenshot, a meme). Watch it guess wrong — and notice the confidence score is often still high. **This is an important note: confidence is not correctness.**
3. Try a blurry or dark photo. See how the predictions degrade.

## File walk through

`imageClassifierDemoApp.swift`  - App entry point. It launches `ContentView`.&#x20;

`MobileNetV2.mlmodel` - The a pre-trained model from [Apple's model gallery](https://developer.apple.com/machine-learning/models/) that recognizes **1,000 categories** of objects (dogs, cars, fruit, instruments, etc.) — the standard ImageNet classes.

* When you click on it in Xcode, you can see its inputs (a 224×224 image) and outputs (a label + confidence). You **don't write any code for this file** — Xcode auto-generates a class called `MobileNetV2` so Swift can use it.

### `Classifier.swift` — the ML logic

This is the file that actually runs the model. It's is only aobut 20 lines of code, here is the skeleton structure:

```swift
@Observable
class Classifier {
    var result: String?
    var confidence: Float?

    public func detect(ciImage: CIImage) {
        // 1. Load the model
        // 2. Build a Vision request
        // 3. Run the request on the image
        // 4. Read the top result
    }
}
```

1. **Load the model**

```swift
let model = try? VNCoreMLModel(for: MobileNetV2(...).model)
```

Wraps the auto-generated `MobileNetV2` class in a `VNCoreMLModel` so the Vision framework can use it.

2. **Build a request**

```swift
let request = VNCoreMLRequest(model: model)
let handler = VNImageRequestHandler(ciImage: ciImage)
```

* A `VNCoreMLRequest` says *"I want to run this model."*&#x20;
* A `VNImageRequestHandler` says *"…on this specific image."*&#x20;
* It is separated so that you may run request on the same image in the case you want to do that

3. **Run it**

```swift
try? handler.perform([request])
```

* This line of code runs the inference. It is synchronous but fast (usually < 100 ms on a newer iPhone).

4. **Read the result**

```swift
let results = request.results as? [VNClassificationObservation]
if let firstResult = results.first {
    confidence = firstResult.confidence
    result = firstResult.identifier
}
```

The model returns a sorted list of guesses, we grab the best guess  — its label "`identifier"` and how sure it is, "`confidence"`, a 0–1 float.

### `ContentView.swift` — the UI

**State**

```swift
@State private var selectedImage: PhotosPickerItem? = nil
@State private var selectedImageData: Data? = nil
var classifier = Classifier()
```

Tracks what the user picked and holds an instance of our `Classifier`.

**The image / placeholder**

In the file, we have a  `ZStack` that shows either the picked image or a "Select image…" prompt if nothing is picked yet.

**The result overlay**

When `classifier.result` isn't `nil`, a panel appears at the top showing the labels and confidence. Because `Classifier` is `@Observable`, this panel appears automatically as soon as the model finishes.

**The picker button (in the toolbar)**

```swift
PhotosPicker(...)
    .onChange(of: selectedImage) { oldItem, newItem in
        Task {
            if let data = try? await newItem?.loadTransferable(type: Data.self) {
                selectedImageData = data
                classifier.detect(ciImage: CIImage(data: data)!)
            }
        }
    }
```

This is the link between the UI and ML logic code.&#x20;

When the user picks a photo: we tell our phone to load the image data → store it for display → hand it to the classifier. The `Task { … await … }` is async because loading photo data from the library may take a moment.<br>

</details>

<details>

<summary><strong>Limitation on MobileNetV2</strong></summary>

It's worth mentioning what this model can't do:

* This model has only 1000 fixed classes, it does not have class for things like "phone screen", "whiteboard", or anything outside [ImageNet](https://www.image-net.org/)
* Can not give you a good guess for something outside of the image net, it will pick the closest of 1,000 classes
* It only gives you the best guess of the image, but only one label, so if your image is "a person and a dog", then it will give you only either a dog or a person. To have multiple label, you may check out [this project](https://developer.apple.com/documentation/vision/recognizing-objects-in-live-capture).
* Only Image classification, this model does not classify video, or live camera.

If any of those limits matter for your app, you may train your own model with Create ML, or pick a different model from [Apple's model gallery](https://developer.apple.com/machine-learning/models/).

</details>

<details>

<summary><strong>Training your own model with Create ML</strong></summary>

MobileNetV2 only knows the 1,000 ImageNet classes. If you want to recognize, for example

* **difference between a golden retriever and your specific dog**,&#x20;
* or **good vs. burnt cookies**, you need your own model.

That's where **Create ML** comes in. It is bundled with Xcode.&#x20;

* You can use use **Spotlight Search** (Cmd + Space) and type "Create ML"

**Steps:**

1. Open Create ML → choose **Image Classification**.
2. Drop in folders of training images, one folder per category.
3. Click **Train**. (it may take couple minutes, but it should not take hours on a Mac.)
4. Export the resulting `.mlmodel` file
5. Drag it into Xcode and use it in code exactly like we use `MobileNetV2` in the above demo.

</details>


# Assignments


# A1: Swift Basics

Original Author: Vin Bui

{% hint style="danger" %}
**Assignment Due: Friday Oct 24, 2025 11:59pm**
{% endhint %}

{% file src="/files/9ZGsAjtulgoCVCe11n3x" %}

## Overview

***

The goal of this assignment is to help you become familiar with basic Swift syntax and version control with Git and GitHub.

## Learning Objectives

***

**Developer Skills**

* How to implement functions according to a specification
* How to read documentation from outside resources
* How to read, create, and use functions to organize code
* How to work with Git and GitHub for version control

**Course Material**

* How to use string interpolation to combine variables with strings
* How to convert data types using type casting
* How to create and work with arrays and dictionaries
* How to use conditionals to control program flow
* How to use methods provided by Swift
* How to use loops to repeat code
* How to work with optionals
* How to use higher order functions to simplify code

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment must be done individually.** However, we do encourage *limited* collaboration. You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/fa25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

The grading for TODOs 1-9 are based on the number of test cases that you pass. We will convert the values to a decimal and their sum will be your subtotal (out of 10). The feedback form link is located in the [Submission](#submission) section of this handout.

| TODO 1: <mark style="color:red;">`introduce`</mark>         | \_ / 2                                       |
| ----------------------------------------------------------- | -------------------------------------------- |
| TODO 2: <mark style="color:red;">`getStudentInfo`</mark>    | \_ / 1                                       |
| TODO 3: <mark style="color:red;">`countEvens`</mark>        | \_ / 4                                       |
| TODO 4: <mark style="color:red;">`capitalizeStrings`</mark> | \_ / 4                                       |
| TODO 5: <mark style="color:red;">`repeatString`</mark>      | \_ / 4                                       |
| TODO 6: <mark style="color:red;">`countWords`</mark>        | \_ / 6                                       |
| TODO 7: <mark style="color:red;">`containsNum`</mark>       | \_ / 4                                       |
| TODO 8: <mark style="color:red;">`uppercaseLead`</mark>     | \_ / 6                                       |
| TODO 9: <mark style="color:red;">`filterImposter`</mark>    | \_ / 6                                       |
| Feedback Survey                                             | \_ / 1                                       |
| <mark style="color:blue;">**SUBTOTAL**</mark>               | <mark style="color:blue;">**\_ / 10**</mark> |
| Deduction: Crash Tax                                        | -1 point                                     |
| <mark style="color:blue;">**GRAND TOTAL**</mark>            | <mark style="color:blue;">**\_ / 10**</mark> |

## Getting Started

***

### Opening the Project

Download and unzip the files at the top of this page. Navigate to the files located on your local computer drive. Inside of the folder  should contain an Xcode project called <mark style="color:red;">`A1.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard.

If you expand everything underneath <mark style="color:red;">`A1`</mark> you should see the following:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FHu0kd73FguwMDgH6Ngrd%2FUntitled.png?alt=media&amp;token=34a12809-af85-49af-b752-82dd85639f7e" alt="" width="269"><figcaption></figcaption></figure>

**You will be working on&#x20;**<mark style="color:red;">**`MainApp.swift`**</mark>**&#x20;and&#x20;**<mark style="color:red;">**`A1Tests.swift`**</mark>**.**

## Part I: Assignment Files

***

### `MainApp.swift`

You will be implementing the functions provided in this file. **There are a total of 9 TODOs.** If you click on this red box at the top of your Xcode, there should be a dropdown menu.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FYPDcnIX8pjvUGb8LJCGo%2FUntitled.png?alt=media&amp;token=c637668a-dfc6-4e9d-bad0-8be30e80a2ac" alt="" width="277"><figcaption></figcaption></figure>

If you click on the clipboards, you will directed to the TODOs. The stars (⭐️) represent the difficulty level of each function. At the top of each function header is the ***specification***. **Your goal is to implement the function according to the specification. DO NOT CHANGE THE FUNCTION HEADER.** We have given you hints to help you complete the tasks.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FlwaPbJydvSeXNt2HJLv9%2FUntitled.png?alt=media&amp;token=37c7805a-1d21-47d6-857f-35f6b99c50d9" alt="" width="229"><figcaption></figcaption></figure>

### `A1Tests.swift`

This file contains the test cases for each function. **DO NOT EDIT THIS FILE.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FNfzS59VKB3AiuEo4vCgH%2FUntitled.png?alt=media&amp;token=2041c0b4-fa79-4d1b-9881-dba78e5537ef" alt=""><figcaption></figcaption></figure>

There are two ways to run the test cases:

1. You can run the entire test suite by clicking on the button in the blue box next to <mark style="color:red;">`final class A1Tests: XCTestCase`</mark> in the Editor or <mark style="color:red;">`A1Tests`</mark> in the Navigator on the left.
2. You can run test cases for a specific function by clicking on the button in the blue box next to the function (such as <mark style="color:red;">`func testIntroduce()`</mark>) in the Editor or in the Navigator on the left.

When you run the test suite for the first time, it may take about 30 seconds to 1 minute to load. After the first launch, it should not take that long. If the Simulator opens up, keep it open as it is required to run the test suite (for some reason). **You will get a popup saying “Build Succeeded”, but this does not mean that you have passed the test cases. A passed test case will have green checkmarks and no error messages.**

The yellow box above indicates an error message. The value pointed by the pink arrow is the “Received” output which is what your implementation returned. The value pointed by the green arrow is the “Expected” output which is what your function *should* return. The console will also output the error message.

{% hint style="danger" %}
**Make sure you are using an iPhone simulator at the top of Xcode.**
{% endhint %}

## Part II: Implementing the Functions

***

There are a total of 9 functions that you need to implement with varying levels of difficulty (indicated by a ⭐️). Follow these steps when working on the assignment:

1. Begin **TODO 1** and implement the function.
2. Run the test function for **TODO 1**. If failed, fix your function and try again. If passed, move on to the next step.
3. Repeat for **TODOs 2-9**

## Submission

***

1. Double-check that all of your files are properly filled out.
2. Zip all of your files, you can right-click the folder they are in and click "compress"
3. Submit the assignment to CMSX
4. Fill out this [feedback survey](https://forms.gle/MxVK3Bjnv6k8EJDA9) (worth 1 point).


# A2: Profile

Original Author: Vin Bui

{% hint style="danger" %}
**Assignment Due: Wed, March 25th 2026 11:59pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands). Otherwise, we will create a repository for you.**
{% endhint %}

{% file src="/files/rFSbGbSKutB3htStOdgy" %}

## Setup

***

If you prefer to use your personal GitHub account instead (not recommended), please make a private Ed post and we’ll provide instructions.

Note: After your assignment has been graded, you’re welcome to copy or upload your repo to your personal GitHub for portfolio purposes.&#x20;

Read these steps carefully, and reach out on ed if you encounter any problems:

#### 1. Go to the course organization

Navigate to:\
👉 <https://github.coecis.cornell.edu/cs1998-601-sp26>

#### 2. Open the template repo

Click on:

```
a2-template
```

#### 3. Create your own repo

* Click the green **“Use this template”** button
* Select:
  * **Owner:** `cs1998-601-sp26`
  * **Repository name:** `NETID-a2` (replace NETID with your NetID)
* Click **“Create repository”**
* Choose **"private"**

#### 4. Clone your repo

On your newly created repo page:

* Click the green **“Code”** button
* Copy the SSH URL

Then run in your terminal (from the directory you want your files to end up in):

```
git clone <PASTE_URL_HERE>
cd NETID-a2
```

#### 5. Start working

Open the project and begin coding.

#### 6. Save your work (commit + push)

Whenever you make changes:

```
git add .
git commit -m "your message"
git push
```

* you can also use [**github desktop**](https://desktop.github.com/download/)**,** but we encourage you to play with command line interface.

## Overview

***

In this assignment, you will be creating your first ever iOS application using UIKit programmatically. You will be creating a Profile and Edit Profile page, commonly seen in many apps today.

## Learning Objectives

***

**Developer Skills**

* **How to format and structure your code to follow MVC design pattern**
* **How to follow common styling conventions used in industry**
* **How to implement designs created on Figma**
* How to work with Git and GitHub for version control
* How to read documentation from outside resources

**Course Material**

* How to create classes such as a <mark style="color:red;">`UIViewController`</mark>
* How to create and customize a <mark style="color:red;">`UIView`</mark> and position them with <mark style="color:red;">`NSLayout`</mark>
  * <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIButton`</mark>, <mark style="color:red;">`UIImageView`</mark>, <mark style="color:red;">`UIImage`</mark>, <mark style="color:red;">`UITextField`</mark>
* How to navigate between view controllers using a <mark style="color:red;">`UINavigationController`</mark> and popping/pushing
* How to use delegation to communicate between view controllers
* How to implement design system using <mark style="color:red;">`UIFont`</mark> and <mark style="color:red;">`UIColor`</mark>

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/course-content/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Creating the Profile Page**</mark>              | <mark style="color:blue;">**\_ / 1**</mark>        |
| ----------------------------------------------------------------------------------- | -------------------------------------------------- |
| <p>UI: Profile Image<br>UI: Name, Bio<br>UI: Hometown and Major</p>                 | \_/ 1                                              |
| <mark style="color:blue;">**PART II: Push the Edit Profile Page**</mark>            | <mark style="color:blue;">**\_ / 2**</mark>        |
| UI: Edit Profile Button                                                             | \_ / 1                                             |
| F: Pushes <mark style="color:red;">`EditProfileVC`</mark>                           | \_ / 1                                             |
| <mark style="color:blue;">**PART III: Create the Edit Profile Page**</mark>         | <mark style="color:blue;">**\_ / 1**</mark>        |
| <p>UI: Profile Image<br>UI: Name, Bio<br>UI: Hometown and Major TextFields</p>      | \_ / 1                                             |
| <mark style="color:blue;">**PART IV: Pop the Edit Profile Page**</mark>             | <mark style="color:blue;">**\_ / 2**</mark>        |
| UI: Save Button                                                                     | \_ / 1                                             |
| F: Pops <mark style="color:red;">`EditProfileVC`</mark>                             | \_ / 1                                             |
| <mark style="color:blue;">**PART V: Delegation**</mark>                             | <mark style="color:blue;">**\_ / 2**</mark>        |
| F: Clicking on <mark style="color:red;">`Save`</mark> updates the main Profile page | \_ / 2                                             |
| <mark style="color:blue;">**OTHER**</mark>                                          | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                     | \_ / 1                                             |
| Styling: <mark style="color:red;">`viewDidLoad`</mark> calls helper functions       | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                      | <mark style="color:green;">**\_ / 10**</mark>      |
| EC: Custom back button                                                              | + 1                                                |
| EC: Edit profile picture                                                            | + 1                                                |
| Deduction: Crash Tax                                                                | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                   | <mark style="color:green;">**\_ / 10 (+2)**</mark> |

## Getting Started

***

### Setting up Figma

You can find the link to the Figma [here](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). If you do not have an account, you can create one under your Cornell email. I will provide details on how to navigate through Figma later.

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the [`Git Installation Section`](https://ios-course.cornellappdev.com/~/revisions/wrtYMFJVea8chxL2Ntds/resources/textbook/git-+-github/git-installation), or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a2`</mark> should contain an Xcode project called <mark style="color:red;">`A2.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard.

If you expand everything underneath <mark style="color:red;">`A2`</mark> you should see the following:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fmj0x1GlWzLSyfQvY51SH%2FUntitled.png?alt=media&amp;token=c8a86de6-493b-4e02-8ef5-2a2f6ef71976" alt="" width="237"><figcaption></figcaption></figure>

**You will be working on&#x20;**<mark style="color:red;">**`ProfileVC.swift`**</mark>**,&#x20;**<mark style="color:red;">**`EditProfileVC.swift`**</mark>**, and&#x20;**<mark style="color:red;">**`Assets.xcassets`**</mark>**.**

## Assignment Files

***

### `ProfileVC.swift`

You will be creating the *main profile page* in this file, primarily in Parts I and II. You are responsible for creating the UI design based on the [Figma](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). This view controller is the root view controller inside of a <mark style="color:red;">`UINavigationController`</mark> located in <mark style="color:red;">`SceneDelegate.swift`</mark>. You will be asked to push <mark style="color:red;">`EditProfileVC`</mark> onto this navigation stack.

### `EditProfileVC.swift`

You will be creating the *edit profile page* in this file, primarily in Parts III and IV. You will be implementing the UI design based on the [Figma](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). This view controller will be pushed by <mark style="color:red;">`ProfileVC`</mark> onto the navigation stack. You will be asked to implement popping functionality as well as delegation to save changes from the text field.

### `UIColor+Extension.swift`

**DO NOT EDIT THIS FILE!** This file contains colors that are featured in the Figma design. To use the colors, simply type <mark style="color:red;">`UIColor.a2.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FVxatHYWE39O33tL8yrWX%2FUntitled.png?alt=media&amp;token=b2b2473c-76e3-42c7-baba-194127743474" alt=""><figcaption><p>From the Figma Design</p></figcaption></figure>

## Using Figma and Importing Assets

***

For the scope of this course, we will be teaching you the skills necessary to read a design implemented on Figma. This is widely used both on AppDev and in industry, so it’s important to have this skill in your toolkit. Please read over the [Figma guide](/resources/tool-guides/figma) now.

## Styling

***

Throughout the provided files, you may have noticed the <mark style="color:red;">`// MARK`</mark> comments. These are used to keep the code organized.

* <mark style="color:red;">`Properties (View)`</mark> are used for <mark style="color:red;">`UIView`</mark> objects such as <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIImageView`</mark>, etc. **You should mark these properties as** <mark style="color:red;">`private`</mark> **and make them&#x20;*****constants*****&#x20;(use** <mark style="color:red;">`let`</mark>**).**
* <mark style="color:red;">`Properties (Data)`</mark> are used for data types such as <mark style="color:red;">`String`</mark>, <mark style="color:red;">`Int`</mark>, delegates, etc. **Again, mark these properties as** <mark style="color:red;">`private`</mark> **but it is up to you to decide if they are constants or variables.**
* The <mark style="color:red;">`Set Up Views`</mark> section should be used for initializing your view properties.

You are not limited to these sections and are free to add more (and you should). Because many of your data properties are marked as <mark style="color:red;">`private`</mark>, you ***may*** need to create an <mark style="color:red;">`init`</mark> function.

Follow these steps when implementing the UI:

1. Create the view
2. Initialize the view
3. Constrain the view
4. Run, confirm, and repeat

{% hint style="danger" %}
**Your&#x20;**<mark style="color:red;">**`viewDidLoad`**</mark>**&#x20;method should contain&#x20;*****mostly*****&#x20;function calls to helper functions. We will be grading you on this.**
{% endhint %}

## Part I: Creating the Profile Page

***

**Your task is to create the UI for the&#x20;*****main profile page*****&#x20;in&#x20;**<mark style="color:red;">**`ProfileVC`**</mark>**.** This profile can be for you, your partner, or if you want you can use me (Vin). Do not worry about any functionality here. We will do that in Part II. Your profile will have the following:

* Profile Image: <mark style="color:red;">`UIImageView`</mark>
  * You will need to add the image to <mark style="color:red;">`Assets.xcassets`</mark>. Refer to the Figma guide.
  * To get a perfect circle, set the <mark style="color:red;">`layer.cornerRadius`</mark> of the <mark style="color:red;">`UIImageView`</mark> to the radius (set it to the width of the image divided by 2) and set <mark style="color:red;">`layer.masksToBounds`</mark> to <mark style="color:red;">`true`</mark>.
* Name: <mark style="color:red;">`UILabel`</mark>
  * You can get the colors from Figma under the “Inspect” section. To use the color, type: <mark style="color:red;">`UIColor.a2.<color_name>`</mark>
  * You can get the font **weight** and **size** from Figma under the “Inspect” section. Set the “Code” to `iOS`. To set the font, type: <mark style="color:red;">`.systemFont(ofSize: <size>, <weight>)`</mark>. **Do not use the code. You should only look at the font name and size.**
    * **Make sure you use the weight from the font name instead of the number. For example, even though Figma says a weight of&#x20;**<mark style="color:red;">**`600`**</mark>**, the weight should be&#x20;**<mark style="color:red;">**`.semibold`**</mark>**.**
  * If any of these fields are too long, you can set the <mark style="color:red;">`numberOfLines`</mark> property to <mark style="color:red;">`0`</mark> for unlimited lines.
* Bio: <mark style="color:red;">`UILabel`</mark> (or <mark style="color:red;">`UITextView`</mark>)
  * To make the text italic, use: <mark style="color:red;">`.italicSystemFont(ofSize: <size>)`</mark>
* Hometown: <mark style="color:red;">`UIImageView`</mark> for the icon, <mark style="color:red;">`UILabel`</mark> for the text
* Major: <mark style="color:red;">`UIImageView`</mark> for the icon, <mark style="color:red;">`UILabel`</mark> for the text

Don’t forget to set the title of the view controller to <mark style="color:red;">`“My Profile”`</mark> and background color.

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Push the Edit Profile Page

***

**You task is to create the “Edit Profile” button as well as pushing&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**&#x20;onto the navigation stack.**

Edit Profile Button: <mark style="color:red;">`UIButton`</mark>

* To change the text, use <mark style="color:red;">`setTitle(<text>, for: .normal)`</mark>
* To change the text color, use <mark style="color:red;">`setTitleColor(<color>, for: .normal)`</mark>
* To change the background color, use <mark style="color:red;">`backgroundColor = <color>`</mark>
* To change the corner radius, use <mark style="color:red;">`layer.cornerRadius = <radius>`</mark>. You can get this under “Inspect > Properties” in Figma on the right hand side.
* As a hint, you will need to add the following constraints: leading, trailing, bottom, and height (not width)
* To add functionality to this button when tapped, use <mark style="color:red;">`addTarget(self, #selector(<function_to_call>), for: .touchUpInside)`</mark>

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Create the Edit Profile Page

***

**Your task is to create the UI for the&#x20;*****edit profile page*****&#x20;in&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**.** Do not worry about any functionality here. We will do that in Part IV. Consult Part I for hints on how to implement these views. This page will have the following:

* Profile Image: <mark style="color:red;">`UIImageView`</mark>
* Name: <mark style="color:red;">`UILabel`</mark>
* Bio: <mark style="color:red;">`UILabel`</mark> (or <mark style="color:red;">`UITextView`</mark>)
* Hometown: <mark style="color:red;">`UILabel`</mark> for the text, <mark style="color:red;">`UITextField`</mark> for the text field
  * To set the border width, use <mark style="color:red;">`layer.borderWidth = <width>`</mark>
  * To set the border color, use <mark style="color:red;">`layer.borderColor = <color>`</mark>
    * The color must be a CGColor. Use the following line: <mark style="color:red;">`UIColor.a2.silver.cgColor`</mark>
  * To set the corner radius, use <mark style="color:red;">`layer.cornerRadius = <radius>`</mark>
  * For the text field, you will need to set following constraints: top, leading, trailing, and height (not width)
  * Creating the padding before the text inside of the textfield is not as straight forward, so it’s okay to not have it. However, if you are interested, check [this](https://stackoverflow.com/questions/25367502/create-space-at-the-beginning-of-a-uitextfield) out.
* Major: <mark style="color:red;">`UILabel`</mark> for the text, <mark style="color:red;">`UITextField`</mark> for the text field

You will need to create a data property to store some information. Mark these properties as <mark style="color:red;">`private`</mark> and create an <mark style="color:red;">`init`</mark> function. Make sure to include the following line after initializing your properties: <mark style="color:red;">`super.init(nibName: nil, bundle: nil)`</mark>. The values for these properties will be passed in from <mark style="color:red;">`ProfileVC`</mark>.

{% hint style="info" %}
**If you haven’t realized it yet, for most of the setup functions you can copy and paste from the previous and make slight modifications!**
{% endhint %}

Don’t forget to set the title of the view controller to <mark style="color:red;">`“Edit Profile”`</mark> and background color.

**Once you are done, stage, commit, and push to GitHub.**

## Part IV: Pop the Edit Profile Page

***

**You task is to create the “Save” button as well as popping&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**&#x20;from the navigation stack.**

Save Button: <mark style="color:red;">`UIButton`</mark>

* See Part II for implementation hints

{% hint style="info" %}
**If you implemented Part II correctly, this should be as simple as copy and pasting!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Delegation

***

**You task is to use delegation to update information from&#x20;**<mark style="color:red;">**`ProfileVC`**</mark>**&#x20;based on the text fields in&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**.** Remember these steps:

1. Create a protocol with a function
2. Conform <mark style="color:red;">`ProfileVC`</mark> to the protocol (delegate)
   * Implement the function
3. Create a property in <mark style="color:red;">`EditProfileVC`</mark> to reference <mark style="color:red;">`EditProfileVC`</mark> (delegator)
   * Make sure it has <mark style="color:red;">`weak`</mark> before it. If this property is <mark style="color:red;">`private`</mark>, make sure to initialize it in the <mark style="color:red;">`init`</mark> function.
4. Call the function in <mark style="color:red;">`EditProfileVC`</mark>

If you have forgotten how to implement delegation, view the lecture notes or textbook.

To access the text from a <mark style="color:red;">`UITextField`</mark>, use the <mark style="color:red;">`text`</mark> property of the text field. Note that this gives you an optional.

**Double check that your main profile updates when you click save. Then click on “Edit Profile” again and make sure that the text fields in the edit profile page are also updated.**

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="danger" %}
**If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Custom Back Button (+1 pt)

When using a <mark style="color:red;">`UINavigationController`</mark>, there is a default back button. However, it does not look nice with our design so **your task is to customize the back button**. The Figma contains the design for this feature. As a hint, the icon used is known as an **SF Symbol** called <mark style="color:red;">`chevron.left`</mark>. You do not need to export this icon; it is built-in.

### 2: Edit Profile Picture (+1 pt)

This one is ***a lot*** more challenging than the previous feature. **Your task here is to allow the user to edit their profile picture.** You can access their camera roll, photo library, or both.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a2.git
Extra Credit:
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://forms.gle/SUtV52cGhVpoLQsz7) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# A3: ChatDev

Original Author: Vin Bui

{% hint style="danger" %}
**Midpoint Due: Wednesday, November 5, 2025 11:59 pm**\
**Final Due: Monday, November 10, 2025 11:59 pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands). Otherwise, we will create a repository for you.**
{% endhint %}

{% file src="/files/0AGMMjho0PH0Np3SRCEd" %}

## Overview

***

In this assignment, you will be creating a “social media” app. You will be using Alamofire to send HTTP requests to a backend endpoint to fetch information.

## Learning Objectives

***

**Developer Skills**

* **How to use Postman to test HTTP requests**
* **How to read code written by other developers**
* **How to read data received from the backend to structure frontend code**
* How to work with Git and GitHub for version control
* How to read documentation from outside resources
* How to format and structure your code to follow MVC design pattern
* How to follow common styling conventions used in industry
* How to implement designs created on Figma

**Course Material**

* How to represent lists of data using a <mark style="color:red;">`UICollectionView`</mark> and a <mark style="color:red;">`UICollectionViewCell`</mark>
* How to send GET requests to a backend API using Alamofire
* How to send POST requests to a backend API using Alamofire
* How to write callbacks (completion handlers) to handle asynchronous calls
* How to create a <mark style="color:red;">`NetworkManager`</mark> singleton class to contain network calls
* How to decode a JSON using a <mark style="color:red;">`JSONDecoder`</mark> in Swift
* How to handle errors with networking calls

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/fa25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

<table data-header-hidden><thead><tr><th width="374"></th><th></th></tr></thead><tbody><tr><td><mark style="color:blue;"><strong>PART I: Creating the UICollectionViewCell</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>UI: Header (name, date, image)</td><td>_ / 1</td></tr><tr><td>UI: Post Message, Like Button, # Likes</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART II: Creating the UICollectionView</strong></mark></td><td><mark style="color:blue;"><strong>_ / 3</strong></mark></td></tr><tr><td>UI: Multiple sections</td><td>_ / 1</td></tr><tr><td>UI: Dynamic number of items/cells (adding a new Post to the array adds a new item/cell)</td><td>_ / 1</td></tr><tr><td>UI: Each cell is unique and represents a different Post</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART III: Fetching Posts</strong></mark></td><td><mark style="color:blue;"><strong>_ / 3</strong></mark></td></tr><tr><td>F: GET Request to Fetch Posts</td><td>_ / 2</td></tr><tr><td>F: Refresh Control</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART IV: Creating a Post</strong></mark></td><td><mark style="color:blue;"><strong>_ / 3</strong></mark></td></tr><tr><td>F: POST Request to Create a Post</td><td>_ / 3</td></tr><tr><td><mark style="color:blue;"><strong>PART V: Liking a Post</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>F: POST Request to Like a Post</td><td>_ / 1</td></tr><tr><td>F: ❤️ turns red if liked, # likes goes up</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>OTHER</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>Feedback Survey</td><td>_ / 1</td></tr><tr><td>Styling: <mark style="color:red;"><code>viewDidLoad</code></mark> calls helper functions</td><td>_ / 1</td></tr><tr><td><mark style="color:green;"><strong>SUBTOTAL</strong></mark></td><td><mark style="color:green;"><strong>_ / 15</strong></mark></td></tr><tr><td>EC: POST Request to Unlike a Post</td><td>+ 1</td></tr><tr><td>EC: Sort by Top/New posts</td><td>+ 1</td></tr><tr><td>EC: Animation when liking a Post</td><td>+ 1</td></tr><tr><td>Deduction: Crash Tax</td><td>-1 point</td></tr><tr><td><mark style="color:green;"><strong>GRAND TOTAL</strong></mark></td><td><mark style="color:green;"><strong>_ / 15 (+3)</strong></mark></td></tr></tbody></table>

## Getting Started

***

### Using Postman

You are encouraged to use [Postman](https://www.postman.com/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

### Using Figma

Similar to A2, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Cloning the Repository

Navigate to a folder on your device where you will keep all of your assignments. You can navigate to the folder using <mark style="color:red;">`cd`</mark> in Terminal.

Clone the repository on GitHub:

* Replace **NETID** with your NetID
* Replace **SEM** with the semester (such as <mark style="color:red;">`fa23`</mark> or <mark style="color:red;">`sp24`</mark>)

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
# Ex: git clone git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a3.git
```

If you have a partner, replace **NETID1** and **NETID2**. Try changing the order if the former does not work.

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID1-NETID2-a3.git
```

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a3`</mark> should contain an Xcode project called <mark style="color:red;">`A3.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard. You should see something like this:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fu2a0T7G9eF0zkAKBpLZp%2FScreenshot%202023-10-31%20at%206.53.19%E2%80%AFPM.png?alt=media&amp;token=57ef94be-459f-45b3-8a6c-5bc18febf589" alt="" width="262"><figcaption></figcaption></figure>

## Assignment Files

***

There is already code written in this file. As developers, we often build on top of what others have written which is why it is important that you practice this skill. You will often see code that you have never seen before, and it is your job to understand it.

### `FeedVC.swift`

This file contains the main view controller that you will be working with throughout the entire assignment. The “Create Post” cell has already been implemented but you will notice that you cannot see it. You will need to finish setting up the collection view. The lecture does not go over how to create different sections; however, the process is very similar to what we went over in lecture and we will guide you in this handout. There are <mark style="color:red;">`TODO`</mark> comments to help guide you.

### `CreatePostCollectionViewCell.swift`

This file represents the cell to create a post. You are free and encouraged to look over this file to help you implement your own custom collection view cell. You can also reference the lecture or textbook chapter [here](broken://pages/QbHalx1aTnlWeCmF8y8e). In addition, you will be asked to write code to send a network request to create a post. There is a <mark style="color:red;">`TODO`</mark> comment indicating where you should implement this logic.

### `NetworkManager.swift`

This file will contain the Alamofire code to send HTTP requests to the backend. Refer to the lectures or textbook chapters [here](broken://pages/E9fBwDbUqFlypMQFRx4o).

### `Date+Extension.swift`

**DO NOT EDIT THIS FILE!** This file contains a function <mark style="color:red;">`convertToAgo`</mark> that returns a string representation of the <mark style="color:red;">`Date`</mark> object indicating how long ago this post was created. You will call this function on the property holding the post’s date when you create your custom collection view cell.

### `UIColor+Extension.swift`

**DO NOT EDIT THIS FILE!** Similar to A2, this file contains colors that are featured in the [Figma](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1) design. To use the colors, simply type <mark style="color:red;">`UIColor.a3.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fq5I0dUR2sGvei9vwAJJl%2FUntitled.png?alt=media&amp;token=0d1e2ed0-6665-44de-8807-4e4392a9cb82" alt="" width="226"><figcaption><p>From the Figma Design</p></figcaption></figure>

## Styling

***

Throughout the provided files, you may have noticed the <mark style="color:red;">`// MARK`</mark> comments. These are used to keep the code organized.

* <mark style="color:red;">`Properties (View)`</mark> are used for <mark style="color:red;">`UIView`</mark> objects such as <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIImageView`</mark>, etc. **You should mark these properties as** <mark style="color:red;">`private`</mark> **and make them&#x20;*****constants*****&#x20;(use** <mark style="color:red;">`let`</mark>**).**
* <mark style="color:red;">`Properties (Data)`</mark> are used for data types such as <mark style="color:red;">`String`</mark>, <mark style="color:red;">`Int`</mark>, delegates, etc. **Again, mark these properties as** <mark style="color:red;">`private`</mark> **but it is up to you to decide if they are constants or variables.**
* The <mark style="color:red;">`Set Up Views`</mark> section should be used for initializing your view properties.

You are not limited to these sections and are free to add more (and you should). Because many of your data properties are marked as <mark style="color:red;">`private`</mark>, you ***may*** need to create an <mark style="color:red;">`init`</mark> function.

Follow these steps when implementing the UI:

1. Create the view
2. Initialize the view
3. Constrain the view
4. Run, confirm, and repeat

{% hint style="danger" %}
**Your&#x20;**<mark style="color:red;">**`viewDidLoad`**</mark>**&#x20;method should contain&#x20;*****mostly*****&#x20;function calls to helper functions. We will be grading you on this.**
{% endhint %}

## Endpoints

***

* **Endpoint:** [**https://ios-course-backend.cornellappdev.com/api/posts**](https://ios-course-backend.cornellappdev.com/api/posts)

<mark style="color:red;">(EDIT 4/14 23:23: For liking and unliking a post, you'll have to pass in the post ID as a parameter of the URL)</mark>

|                 | Type | Route                       | Request Body                                       |
| --------------- | ---- | --------------------------- | -------------------------------------------------- |
| Fetch all posts | GET  | /api/posts/                 | None                                               |
| Create a post   | POST | /api/posts/create/          | <mark style="color:red;">`message`</mark> (String) |
| Like a post     | POST | /api/posts/{postId}/like/   | <mark style="color:red;">`netId`</mark> (String)   |
| Unlike a post   | POST | /api/posts/{postId}/unlike/ | <mark style="color:red;">`netId`</mark> (String)   |

## Part I: Creating the <mark style="color:red;">`UICollectionViewCell`</mark>

***

**Your task is to create a custom&#x20;**<mark style="color:red;">**`UICollectionViewCell`**</mark> **for the post**. **Create this file inside of the&#x20;**<mark style="color:red;">**`Views`**</mark>**&#x20;folder.** You will need to create a struct or class (struct recommended) to represent a post. **Create this file inside of the&#x20;**<mark style="color:red;">**`Models`**</mark>**&#x20;folder**. As a reference, this is an example post object in JSON fetched from the backend.

```json
{
    "id": "7m03J198pyXFBvCOLNbw",
    "likes": ["vdb23", "rs929"],
    "messsage": "Howdy!",
    "time": "2023-06-12T22:03:23Z"
}
```

You will need to figure out the name and type of your properties for this object. **However, the&#x20;**<mark style="color:red;">**`time`**</mark>**&#x20;property will be a&#x20;**<mark style="color:red;">**`Date`**</mark>**&#x20;object (even though it’s a string in the JSON).** I will show you how to decode this in Part III.

Because you have not implemented networking yet, you will need to create dummy data to test the UI. When creating these dummy data, you can use the code <mark style="color:red;">`Date()`</mark> for the <mark style="color:red;">`time`</mark> property. For the other fields, you can customize it however you like.

Your custom cell class will have the following:

* Name (”Anonymous”)
* Date
* Image (AppDev Logo)
* Post message body
* Like button (use non-filled heart for now)
* Number of likes

Keep in mind the background color, text color, font style, corner radius, etc. You should already have practice in A2 implementing views so I will not guide you as much as A2. Feel free to Google or look at the <mark style="color:red;">`CreatePostCollectionViewCell`</mark> class as a reference. However, your custom cell class differs in that it will need a <mark style="color:red;">`configure`</mark> method. **You can use the&#x20;**<mark style="color:red;">**`convertToAgo`**</mark>**&#x20;function for the date object and assign it to the label’s text to format the “time ago” string.**

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Creating the <mark style="color:red;">`UICollectionView`</mark>

***

**Your task is to create a&#x20;**<mark style="color:red;">**`UICollectionView`**</mark>**&#x20;representing the feed.** There is already some code written that you will need to look over. There is also a custom cell class called <mark style="color:red;">`CreatePostCollectionViewCell`</mark> that represents the “Create Post” cell already implemented for you. You will need to register and use this cell along with the other custom cell you created in Part I.

**This collection view contains 2 sections, each section containing different cell classes.**

* Similar to items, sections are zero-indexed meaning that the first section has index 0. Use this information to implement the functions required to conform to <mark style="color:red;">`UICollectionViewDataSource`</mark>, <mark style="color:red;">`UICollectionViewDelegate`</mark>, and <mark style="color:red;">`UICollectionViewFlowLayoutDelegate`</mark>.
* When creating your FlowLayout, keep in mind the spacing between each item is 16px and between each section is 24px. To add the spacing between sections, implement the <mark style="color:red;">`insetForSectionAt`</mark> function in the <mark style="color:red;">`UICollectionViewDataSource`</mark> extension.

The first section contains only 1 cell and there is no data model associated with it. Again, the custom cell class for this section is <mark style="color:red;">`CreatePostCollectionViewCell`</mark>. I highly recommend that you read and understand the code written in this class. Once you are able to see this cell in your collection view, begin implementing the second section.

The second section contains a variable number of cells indicating that you will need a data model representing the posts. Because you have not implemented networking yet, you will need to create dummy data to test this. If you can see both sections and their cells, you should be good to go.

{% hint style="danger" %}
**Note: For the scope of this course, we will not be handling self-sizing cells. The height for each cell is fixed and there are a maximum of three lines for the post message.**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **This is the stopping point for the midpoint submission. We will grade you for completion based on your GitHub commit history.**

**Please submit a `submission.txt` file on CMSX similar to how you did it for your A2 submission. You can download the outline below and see an example submission right under it.**
{% endhint %}

{% file src="/files/T0mO1eR7fdASVffFG8uk" %}

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
Notes: I was having trouble with setting up the UICollectionViewDelegateFlowLayout...
```

## Part III: Fetching Posts

***

**Your task is to send a GET request using Alamofire to fetch all posts from the backend.** Currently, your posts are all hard-coded dummy data. Of course, we want to be able to receive posts created by other people, so we must integrate networking. In Part I, you were given an example JSON representing a post, and you created your model object based on this JSON. The reason for this is that it makes decoding the JSON received from the backend to your model very simple.

If you have not installed Postman yet, you can install it [here](https://www.postman.com/). Read [this short chapter](https://ios-course.cornellappdev.com/guides/postman) on how to use Postman for this assignment. Then, add a new GET request with the URL: <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/`</mark> . This should return a list of all posts from the backend with a 200 status code.

Your job is to integrate these posts into the frontend. You can decode the <mark style="color:red;">`time`</mark> field to a <mark style="color:red;">`Date`</mark> object if you set the decoder’s <mark style="color:red;">`dateDecodingStrategy`</mark> to <mark style="color:red;">`.iso8601`</mark>. For example:

```swift
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
```

Your callback (completion handler) will take in an array of <mark style="color:red;">`Post`</mark> objects (<mark style="color:red;">`[Post]`</mark>). It will also be very helpful to have proper error handling in your code. Refer to the lecture or textbook chapter [here](broken://pages/Fxlid2ij8oOA7jaHpx5R).

**Once you are able to fetch all posts from the backend, your next task is to add pull to refresh to your collection view.** Follow these steps:

```swift
// 1. Create a UIRefreshControl view property
private let refreshControl = UIRefreshControl()

// 2. Add a function to be called as a target
refreshControl.addTarget(self, action: #selector(fetchAllPosts), for: .valueChanged)

// 3. Assign the collection view’s refresh control
collectionView.refreshControl = refreshControl

// 4. Stop refreshing after the network call is complete
refreshControl.endRefreshing()
```

**Once you are done, stage, commit, and push to GitHub.**

## Part IV: Creating a Post

***

**Your task is to send a POST request using Alamofire to add a post to the backend.**

A good rule of thumb is to always use Postman before writing the code.

1. Add a new request to your collection with a POST method
2. Enter the URL <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/create/`</mark>.
3. Click on the <mark style="color:red;">`Body`</mark> tab, select <mark style="color:red;">`raw`</mark>, and change the blue dropdown from “Text” to <mark style="color:red;">`JSON`</mark>
4. This request expects the following body:

```swift
{
    "message": "<Enter some message here>"
}
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FYndwBChiShY3xHARA3d0%2FScreenshot%202025-04-15%20at%2010.32.00%E2%80%AFAM.png?alt=media&amp;token=99dc5755-3eda-499c-a607-84c96fdad218" alt=""><figcaption></figcaption></figure>

If successful, the server returns a 201 status code with the above JSON data representing the post that was just created. **You do not need to do anything with this information for this assignment, but it is a common practice for the backend to return this data.** If you fetch all posts again, either through Postman or your app, you should see the new post that you created.

Similar to Part III, you will integrate this network call within your app. Follow these steps:

1. Create a function in <mark style="color:red;">`NetworkManager`</mark> that uses Alamofire to make the call. Remember that this is a POST request with a request body parameter called <mark style="color:red;">`message`</mark>. Proper error handling is highly recommended!
2. Call this function inside of <mark style="color:red;">`CreatePostCollectionViewCell.createPost`</mark>. There should be a <mark style="color:red;">`TODO`</mark> comment. As a hint, there is a text field in this class that you will need to use.
3. (Optional) If the call is successful, clear the the textfield. You can pass <mark style="color:red;">`true`</mark> to the callback if successful or <mark style="color:red;">`false`</mark> otherwise.
4. Run the app and try to create a post. For the scope of this assignment, you do not need to have the collection view updated as soon as you create the post. However, refreshing the collection view should contain the new post.

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Liking a Post

***

**Your task is to send a POST request using Alamofire to&#x20;*****like*****&#x20;a post.**

Before you integrate networking, configure the like button to be filled with the color ruby if the post’s liked users contains your NetID.

Just like before, use Postman to test the backend call.

1. Add a new request to your collection with a POST method
2. Enter the URL: <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/{postId}/like/`</mark> <mark style="color:red;"></mark><mark style="color:red;">(EDIT 4/14 23:23: You'll have to pass in the post ID as a parameter of the URL)</mark>
3. Click on the <mark style="color:red;">`Body`</mark> tab, select <mark style="color:red;">`raw`</mark>, and change the blue dropdown from “Text” to <mark style="color:red;">`JSON`</mark>
4. This request expects the following body:

```swift
{
    "netId": "<Enter your NetID>"
}
```

**You will use your NetID (all lowercase).** If the call is successful, you should receive the updated post.

There are many ways you can go about this. My recommendation for you is to pass a boolean to the callback to indicate whether or not the call was successful, similar to Part IV. If the call is successful, make the like button filled and increment the count by 1. Additionally, you should only be able to tap on the button if the button is not already filled red, so you will need to wrap your network request in an if statement.

You may notice that there is a delay before the button turns red when tapping on it. In apps like Instagram, usually the UI changes even if the API call fails. However, for the sake of simplicity and grading, we want the button to only turn red if the network call succeeds.

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Unlike a Post (+1 pt)

**Your task is to send a POST request using Alamofire to&#x20;*****unlike*****&#x20;a post.** This may seem similar to Part V, but it requires some additional frontend logic. When grading for this, we will unlike a post and refresh to make sure the backend is actually updated. If you try to unlike a post in which the given NetID does not already like it, you will get an error. You can test this out on Postman. The URL is <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/{postId}/unlike/`</mark>. <mark style="color:red;">(EDIT 4/14 23:23: You'll have to pass in the post ID as a parameter of the URL)</mark>

### 2: Sort by Top/New Posts (+1)

If you take a look at the [Figma](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1) file, you should see a design containing the text “Top” and “New”. **Your task here is to sort the posts by the # of likes (top) and the most recent (new)**. For example, if the selected tab is “Top”, the post with the most likes will be at the top. If the selected tab is “New”, the most recent post will be at the top. Make sure that the color of the tab changes depending on what is selected.

### 3: Like Animation (+1)

**Your task here is to add some animation when liking a post**. You could add a scaling animation similar to most social media apps or do some other cool animation. As long as there is some animation when liking a post, you will get full credit.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a3.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://forms.gle/3vZUFcVXcDfZFXVS7) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# A4: ChefOS

Original Author: Vin Bui

{% hint style="danger" %}
**Midpoint Due: Monday November 17, 2025 11:59 pm**\
**Final Due: Tuesday November 25, 2025 11:59 pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands). Otherwise, we will create a repository for you.**
{% endhint %}

{% file src="/files/Zb0Y6PB0DxgTG0RuWZ84" %}

## Overview

***

In this assignment, you will be creating a recipe book app. You will be able to fetch recipes from a server, filter by category, and save them for later!

## Learning Objectives

***

**Developer Skills**

* **How to organize your project directory**
* How to use Postman to test HTTP requests
* How to read code written by other developers
* How to read data received from the backend to structure frontend code
* How to work with Git and GitHub for version control
* How to read documentation from outside resources
* How to format and structure your code to follow MVC design pattern
* How to follow common styling conventions used in industry
* How to implement designs created on Figma

**Course Material**

* **How to set up multiple collection views and communicate between them**
* **How to filter data using higher order functions**
* **How to save data locally using&#x20;**<mark style="color:red;">**`UserDefaults`**</mark>
* How to represent lists of data using a <mark style="color:red;">`UICollectionView`</mark> and a <mark style="color:red;">`UICollectionViewCell`</mark>
* How to send GET requests to a backend API using Alamofire
* How to write callbacks (completion handlers) to handle asynchronous calls
* How to create a <mark style="color:red;">`NetworkManager`</mark> singleton class to contain network calls
* How to decode a JSON using a <mark style="color:red;">`JSONDecoder`</mark> in Swift
* How to handle errors with networking calls

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/sp25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

{% hint style="info" %}
**Due to the shrinking of the course, the features implemented up to the midpoint submission will be worth more than after.**
{% endhint %}

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Recipe CollectionView**</mark>                                | <mark style="color:blue;">**\_ / 4**</mark>        |
| ------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| UI: Name, Image, Time, Rating                                                                     | \_ / 2                                             |
| UI: 2 columns, Dynamic number of cells (adding a new item to the array creates a new item/cell)   | \_ / 1                                             |
| UI: Each cell is unique and represents a different Recipe                                         | \_ / 1                                             |
| <mark style="color:blue;">**PART II: Detailed Recipe View**</mark>                                | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Image                                                                                         | \_ / 1                                             |
| UI: Name and Description                                                                          | \_ / 1                                             |
| F: Tapping on a Recipe cell pushes a detailed view                                                | \_ / 1                                             |
| <mark style="color:blue;">**PART III: Filtering**</mark>                                          | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Collection view for filters WITH horizontal scrolling                                         | \_ / 1                                             |
| UI: Selected filter is highlighted (separate from functionality)                                  | \_ / 1                                             |
| F: Tapping on a filter filters the recipe data (one at at time; stacking filters is extra credit) | \_ / 1                                             |
| <mark style="color:blue;">**PART IV: Fetching Recipes**</mark>                                    | <mark style="color:blue;">**\_ / 1**</mark>        |
| F: GET Request to Fetch Recipes                                                                   | \_ / 1                                             |
| <mark style="color:blue;">**PART V: Bookmark Recipes**</mark>                                     | <mark style="color:blue;">**\_ / 2**</mark>        |
| F: Bookmarking from the detailed view updates the collection view using delegation                | \_ / 1                                             |
| F: Saved recipes are stored locally via UserDefaults (restart app to check)                       | \_ / 1                                             |
| <mark style="color:blue;">**OTHER**</mark>                                                        | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                                   | \_ / 1                                             |
| Styling: <mark style="color:red;">`viewDidLoad`</mark> calls helper functions                     | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                                    | <mark style="color:green;">**\_ / 15**</mark>      |
| EC: Custom back button                                                                            | + 1                                                |
| EC: Stacking filters                                                                              | + 1                                                |
| EC: Nesting collection views                                                                      | + 1                                                |
| EC: Separate bookmark page                                                                        | + 2                                                |
| Deduction: Crash Tax                                                                              | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                                 | <mark style="color:green;">**\_ / 15 (+5)**</mark> |

## Getting Started

***

### Using Postman

You are encouraged to use [Postman](https://www.postman.com/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

### Using Figma

Similar to A2 and A3, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Cloning the Repository

Navigate to a folder on your device where you will keep all of your assignments. You can navigate to the folder using <mark style="color:red;">`cd`</mark> in Terminal.

Clone the repository on GitHub:

* Replace **NETID** with your NetID
* Replace **SEM** with the semester (such as <mark style="color:red;">`fa23`</mark> or <mark style="color:red;">`sp24`</mark>)

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
# Ex: git clone git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a4.git
```

If you have a partner, replace **NETID1** and **NETID2**. Try changing the order if the former does not work.

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID1-NETID2-a4.git
```

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a4`</mark> should contain an Xcode project called <mark style="color:red;">`A4.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard. You may notice that there is less starter code than in A2 and A3. As developers, directory organization is very important! Look at A2/A3 to see how we organized our directory. **Remember to use those&#x20;**<mark style="color:red;">**`// MARK`**</mark>**&#x20;comments!**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F7SqkVJrERoPKI3c3F7ta%2FScreenshot%202023-10-31%20at%208.56.04%E2%80%AFPM.png?alt=media&amp;token=64f9d82f-8f8b-476f-be56-11345bef5ae8" alt="" width="261"><figcaption></figcaption></figure>

## Assignment Files

***

As mentioned earlier, there is less starter code. You will be required to create your own files and organize them properly. However, there are only two files provided for you.

### `UIColor+Extension.swift`

In contrast to A3, you are free to edit this file if you want to change the colors. This file contains colors that are featured in the [Figma](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1) design. To use the colors, simply type <mark style="color:red;">`UIColor.a4.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FqhBkjYdK1XhVX3TWZgdN%2FUntitled.png?alt=media&amp;token=2191df5f-4153-4efc-86c4-f5ca218d87fe" alt="" width="219"><figcaption><p>From the Figma Design</p></figcaption></figure>

### `UIFont+Extension.swift`

This extension allows you to use the SF Pro Rounded font which is used in the Figma design. To use this font, simply add <mark style="color:red;">`.rounded`</mark> to the end of the <mark style="color:red;">`UIFont`</mark>. For example, you can do <mark style="color:red;">`.systemFont(ofSize: 12, weight: .semibold).rounded`</mark>.

## External Libraries

***

The starter code should have Alamofire, SnapKit, and SDWebImage installed. To use these libraries, use the <mark style="color:red;">`import`</mark> statement at the top of the file. You are not required to use SnapKit, but it would save you a lot of time learning how to use it over NSLayout.

{% hint style="info" %}
**Source: All of the recipes used in this assignment are from** [**allrecipes.com**](https://www.allrecipes.com/)**.**
{% endhint %}

## Part I: Recipe CollectionView

***

**Your task is to create a UICollectionView to display the recipes.** We will not guide you as much as we did with the other assignments, but keep the following in mind:

* You are not required to implement the bookmark icon until Part V, but you are free to do so now.
* You will not be implementing the filters until Part III.
* You will need to create dummy data. For the sake of time and convenience, I have them written out for you in this [Pastebin](https://pastebin.com/KPrsHR38). Make sure your model aligns with the given dummy data since the JSON you will be fetching from follows this format.
* We want the collection view to be scrollable even when not full. Simply set <mark style="color:red;">`alwaysBounceVertical = true`</mark>.
* You do not have to worry about dynamic cell size. Set the text labels’ line limit to <mark style="color:red;">`2`</mark> lines and the height of the cell to around <mark style="color:red;">`216`</mark>. The width, however, will depend on the size of the screen. Remember, we want to have two columns. *Hint: We can multiply/divide the screen’s width by a certain factor.*
* **Do not save recipe images in the Assets catalog. We will be using SDWebImage to download images from URLs.**

{% hint style="danger" %}
**While creating this assignment, I ran into a bug with the collection view. Make sure to set the collection view’s&#x20;**<mark style="color:red;">**`alwaysBounceVertical`**</mark>**&#x20;property to&#x20;**<mark style="color:red;">**`true`**</mark>**.**
{% endhint %}

### Using SDWebImage

There are many ways to download images in Swift, but the easiest way in my opinion is using SDWebImage. Using this library is very simple.

1. Import the library using <mark style="color:red;">`import SDWebImage`</mark> at the top of the file.
2. Given a <mark style="color:red;">`UIImageView`</mark>, simply use the <mark style="color:red;">`.sd_setImage(with: <URL>)`</mark> function. Here is an example:

```swift
// Given a UIImageView called `imageView` and a Recipe object with
// the property `imageUrl`
imageView.sd_setImage(with: URL(string: recipe.imageUrl))
```

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Detailed Recipe View

***

**Your task is to create a view controller representing a detailed recipe view.** You will push this view controller when tapping on the collection view cell. This detailed view will be unique to the recipe.

This is very straight-forward and there aren’t any tricks. Just make sure that your <mark style="color:red;">`Recipe`</mark> model aligns with the given dummy data in this [Pastebin](https://pastebin.com/KPrsHR38) (the data type of your fields matter). Remember to use SDWebImage to download the images and to implement the correct function to handle tapping on a cell. You also need to figure out which labels will have multiple lines. Click on every single cell to check for edge cases.

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Filtering

***

**Your task is to create a horizontally scrolling collection view that represents the filter pills as well as adding filtering functionality.**

Here is a quick demo of what we’re expecting:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FjSiKmRla1i22MGjXdrUv%2Fa4_part3.gif?alt=media&amp;token=3acc89cf-2c0d-48b7-9b69-18f748ae33f1" alt="" width="221"><figcaption></figcaption></figure>

### Handling Multiple Collection Views

The tricky part to this task is that there are now two collection views inside of this view controller. Since it’s not possible to create multiple <mark style="color:red;">`cellForItemAt`</mark> functions, for example, then you need to handle the logic within the function itself. You can do this with an <mark style="color:red;">`if`</mark> statement and checking to see if the parameter <mark style="color:red;">`collectionView`</mark> is equal to the collection view property.

```swift
if collectionView == collectionViewOne {
    // Do something here for collectionViewOne
} else if collectionView == collectionViewTwo {
    // Do something here for collectionViewTwo
}
```

### Filter Collection View

* You want the collection view to span over the entire screen’s width so the leading and trailing anchors need to equal to the parent view. To add an inset to the collection view’s content, you can configure the <mark style="color:red;">`contentInset`</mark> property.
* There are 4 filters: All, Beginner, Intermediate, and Advanced. You can create an array of strings as the data model and use the string to configure the collection view cell which you can use a <mark style="color:red;">`UIButton`</mark> to represent.
* If you want, you can disable the scroll indicator for a cleaner scrolling view.
* You ***do not*** have to handle dynamic cell width. A height of <mark style="color:red;">`32`</mark> and width of <mark style="color:red;">`116`</mark> should work.
* The filter collection view ***does not*** have to scroll vertically with the recipe collection view. This requires nesting collection views inside each other which is a very tedious process. You can have the recipe collection view cut off like this if scrolled:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FtOief8CcHvJDOlp1j9fw%2FUntitled.png?alt=media&amp;token=8c750550-7257-45cf-ada8-3b49a3c8382b" alt="" width="306"><figcaption></figcaption></figure>

### Filtering Logic

* You ***do not*** need to handle filter stacking. This is somewhat advanced so we will leave that for extra credit.
* There are many ways to determine if a cell is selected, so I will leave this up to you to decide. Make sure that the currently selected tab is highlighted with a white text color. If you are lost and have no idea where to start, feel free to ask on Ed Discussion or come to office hours.
* There are also many ways to change the value of the selected filter. You can configure <mark style="color:red;">`didSelectItemAt`</mark> or use delegation to communicate from the cell’s button to the view controller.
* To filter the array of recipes, you can use the <mark style="color:red;">`filter`</mark> higher order function. As a hint, you should have two properties containing the array of recipes: one for all recipes and another for filtered recipes.

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **This is the stopping point for the midpoint submission. We will grade you for completion based on your GitHub commit history.**

**Please submit a `submission.txt` file on CMSX similar to how you did it for your A3 midpoint submission. You can download the outline below and see an example submission right under it.**
{% endhint %}

{% file src="/files/u2TNyw6cWJJ3Xi2IH5uB" %}

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
Notes: I was having trouble with setting up the UICollectionViewDelegateFlowLayout...
```

## Part IV: Fetching Recipes

***

**Your task is to create a GET request to fetch all recipes from this API:**

```
https://api.jsonbin.io/v3/b/64d033f18e4aa6225ecbcf9f?meta=false
```

You can use Postman to test the HTTP request. You will need to create a <mark style="color:red;">`NetworkManager`</mark> class with a <mark style="color:red;">`shared`</mark> singleton instance. You will be using Alamofire so make sure to import this library. See the lecture, textbook, or A3 for reference.

Error handling is not required but is nice to have. You will know if you integrated it correctly if there are more recipes than the dummy data. As a reminder, the JSON uses snake\_case but Swift uses camelCase.

Networking is one of the most important but difficult concepts to learn and implement. We want you to get as much practice as you can to prepare you for the Hack Challenge. If you are confused, please create a post on Ed Discussion or visit office hours.

{% hint style="danger" %}
**Make sure that filtering still works properly!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Bookmark Recipes

***

**Your task is to implement bookmarking functionality for these recipes.** You will need a way to keep track of bookmarked recipes to save them locally via UserDefaults.

* First, figure out what data structure you will use to keep track of bookmarked recipes. Then, think of a key that you will use to access through UserDefaults.
* Recipes that are bookmarked should have a bookmark icon in their cell. See the Figma for UI details.
* You will need to create a <mark style="color:red;">`UIBarButtonItem`</mark> to represent the bookmark button. This button will be in the detailed recipe view on the top right corner. If the recipe is already saved, the bookmark button will be filled and tapping on it will remove it from the saved recipes.
* The bookmark icon should change immediately on press. You will also need to use delegation to reload the recipe collection view so that the cells will be properly updated. Remember to use a weak reference!
* All saved recipes should be stored locally. You can check by restarting the app. If the saved recipes do not reset, then you are good to go.

Here is a quick demo of what we are looking for:

{% file src="/files/OJ2hEDPeJJYPDanjBwOq" %}

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Custom Back Button (+1 pt)

**Your task is to create a custom back button.** The [Figma](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1) has a possible design for this, but you are free to use any button you like. This should be a freebie if you finished the task in Part V.

### 2: Stacking Filters (+1)

Right now, you can only select one filter at a time. **Your task is to allow for filter stacking**. All selected filters should be highlighted and the collection view should contain all selected filters.

### 3: Nesting CollectionViews (+1)

Right now, you have two separate collection views: one for the filters and the other for the recipes. Because these collection views have different scrolling directions, if we wanted to make them both scrollable vertically, then we will have to nest collection views. **Your task here is to nest collection views so that the filters scroll with the recipes.** In other words, if I scroll up, the filters should scroll up as well while maintaining its horizontal scrolling attribute.

### 4: Separate Bookmark Page (+2)

**Your task here is to create a page listing out all bookmarked recipes.** The design is up to your creativity, but there needs to be some way to push the detailed recipe view where you can then bookmark/unbookmark. You may also need to use delegation to update this bookmark list, similar to what you did in Part V.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
+1 : ____
+2 : ____
```

6. Fill out this [feedback survey](https://forms.gle/rHSz5t8By1rHocAU8) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# A4: ChefOS - SwiftUI

Original project authored by Vin Bui, adapted to SwiftUI by Daniel Chuang

{% hint style="danger" %}
**Midpoint Due: Monday November 17, 2025 11:59 pm**\
**Final Due: Tuesday November 25, 2025 11:59 pm**
{% endhint %}

{% hint style="info" %}
**For this assignment, please make a blank SwiftUI project. We're starting from scratch! Make sure to submit via your Cornell repo though, we will set up an empty one for you.**
{% endhint %}

## Overview

***

In this assignment, you will be creating a recipe book app. You will be able to fetch recipes from a server, filter by category, and save them for later!

## Learning Objectives

***

**Developer Skills**

* **How to organize your project directory**
* How to use Postman to test HTTP requests
* How to read data received from the backend to structure frontend code
* How to work with Git and GitHub for version control
* How to read documentation from outside resources
* How to format and structure your code to follow MVC design pattern
* How to follow common styling conventions used in industry
* How to implement designs created on Figma

**Course Material**

* **How to set up multiple collection views and communicate between them in SwiftUI**
* **How to filter data using higher order functions**
* **How to save data locally using&#x20;**<mark style="color:red;">**`UserDefaults`**</mark>
* How to represent lists of data using a <mark style="color:red;">`UICollectionView`</mark> and a <mark style="color:red;">`UICollectionViewCell`</mark>
* How to send GET requests to a backend API using Alamofire
* How to write callbacks (completion handlers) to handle asynchronous calls
* How to create a <mark style="color:red;">`NetworkManager`</mark> singleton class to contain network calls
* How to decode a JSON using a <mark style="color:red;">`JSONDecoder`</mark> in Swift
* How to handle errors with networking calls

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/sp25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.**

## Grading Rubric

***

{% hint style="info" %}
**Due to the shrinking of the course, the features implemented up to the midpoint submission will be worth more than after.**
{% endhint %}

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Recipe CollectionView**</mark>                                | <mark style="color:blue;">**\_ / 4**</mark>        |
| ------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| UI: Name, Image, Time, Rating                                                                     | \_ / 2                                             |
| UI: 2 columns, Dynamic number of cells (adding a new item to the array creates a new item/cell)   | \_ / 1                                             |
| UI: Each cell is unique and represents a different Recipe                                         | \_ / 1                                             |
| <mark style="color:blue;">**PART II: Detailed Recipe View**</mark>                                | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Image                                                                                         | \_ / 1                                             |
| UI: Name and Description                                                                          | \_ / 1                                             |
| F: Tapping on a Recipe cell pushes a detailed view                                                | \_ / 1                                             |
| <mark style="color:blue;">**PART III: Filtering**</mark>                                          | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Collection view for filters WITH horizontal scrolling                                         | \_ / 1                                             |
| UI: Selected filter is highlighted (separate from functionality)                                  | \_ / 1                                             |
| F: Tapping on a filter filters the recipe data (one at at time; stacking filters is extra credit) | \_ / 1                                             |
| <mark style="color:blue;">**PART IV: Fetching Recipes**</mark>                                    | <mark style="color:blue;">**\_ / 1**</mark>        |
| F: GET Request to Fetch Recipes                                                                   | \_ / 1                                             |
| <mark style="color:blue;">**PART V: Bookmark Recipes**</mark>                                     | <mark style="color:blue;">**\_ / 2**</mark>        |
| F: Bookmarking from the detailed view updates the collection view using delegation                | \_ / 1                                             |
| F: Saved recipes are stored locally via UserDefaults (restart app to check)                       | \_ / 1                                             |
| <mark style="color:blue;">**OTHER**</mark>                                                        | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                                   | \_ / 1                                             |
| <mark style="color:red;">`onAppear`</mark> calls networking functions                             | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                                    | <mark style="color:green;">**\_ / 15**</mark>      |
| EC: Custom back button                                                                            | + 1                                                |
| EC: Stacking filters                                                                              | + 1                                                |
| EC: Nesting collection views                                                                      | + 1                                                |
| EC: Separate bookmark page                                                                        | + 2                                                |
| Deduction: Crash Tax                                                                              | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                                 | <mark style="color:green;">**\_ / 15 (+5)**</mark> |

## Getting Started

***

### Using Postman

You are encouraged to use [Postman](https://www.postman.com/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

### Using Figma

Similar to A2 and A3, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

### Creating a new SwiftUI Project

Go to Xcode -> File -> New -> Project -> App -> \[MAKE SURE THAT Interface = SwiftUI] and just proceed from there via clicking Next and Create.

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Pushing to the Repository

Navigate to a folder on your device where you will keep all of your assignments. You can navigate to the folder using <mark style="color:red;">`cd`</mark> in Terminal.

Clone the repository on GitHub:

* Replace **NETID** with your NetID
* Replace **SEM** with the semester (such as <mark style="color:red;">`fa23`</mark> or <mark style="color:red;">`sp24`</mark>)

```powershell
git init
git remote add origin git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
# Ex: git remote add origin git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a4.git
git add .
git commit -m "Initial commit"
git push origin main
```

If you have a partner, replace **NETID1** and **NETID2**. Try changing the order if the former does not work.

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID1-NETID2-a4.git
```

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

## Assignment Files

***

**Color File**

You may find the following code helpful to put into a <mark style="color:red;">`Color.swift`</mark> file, as it will allow for you to input the hex values of colors you have from Figma into Swift directly.

```swift
// Copy into a file called Color.swift
import SwiftUI

extension Color {
    init(hex: UInt, alpha: Double = 1) {
        self.init(
            .sRGB,
            red: Double((hex >> 16) & 0xff) / 255,
            green: Double((hex >> 08) & 0xff) / 255,
            blue: Double((hex >> 00) & 0xff) / 255,
            opacity: alpha
        )
    }
}
```

You will now be able to make colors via the following syntax. Note that the "0x" at the beginning is telling Swift that the proceeding values should be interpreted in hexadecimal base.

```swift
Color(hex: 0xFAFAFA)
```

## External Libraries

***

You will need to import Alamofire. Please import this via Cocoapods or SwiftPackageManager (SPM). You should be able to figure out how to install via Cocoapods via previous projects, but for SPM, here are the instructions!

1. XCode -> File -> Add Package Dependencies
2. Look up Alamofire -> Add Package
3. Click on the Project Settings Page (the very first icon in your file navigation bar, on the top left)
4. Click on General on the top bar of the newly opened project settings page
5. Scroll down to Frameworks, Libraries, and Embedded Content and add Alamofire.
6. You're ready to import Alamofire into your code and write some solid networking code!

{% hint style="info" %}
**Source: All of the recipes used in this assignment are from** [**allrecipes.com**](https://www.allrecipes.com/)**.**
{% endhint %}

## Part I: Recipe CollectionView

***

**Notice that on Figma, the screens are broken down into the different stages you need to implement.**

**Your first task is to create a "Collection View" to display the recipes.** We encourage using the textbook and the internet for syntax and modifier help! We will not guide you as much as we did with the other assignments, but here is a general blueprint for what to do:

1. Set up your Recipe struct and dummy data using data from this [Pastebin](https://pastebin.com/KPrsHR38) link. Make sure the struct's properties align with the Pastebin format!
2. Make a RecipeCell view in a new file called <mark style="color:red;">`RecipeCell.swift`</mark>
   1. Set up a preview if you'd like!
   2. Add a property to the view called <mark style="color:red;">`recipe`</mark> which should allow for you to input any recipe you want from your dummy data (so your string should be using recipe.\[property])
   3. Use an AsyncImage for putting in the recipe's image. Refer to Swift [documentation](https://developer.apple.com/documentation/swiftui/asyncimage) or the Ed [post](https://edstem.org/us/courses/75579/discussion/6551956) made by Daniel for a reference on how to do this.
3. Now, in ContentView, you'll want to set up a LazyVGrid in order to get the grid with 2 columns. Refer to the Swift [documentation](https://developer.apple.com/documentation/swiftui/lazyvgrid#:~:text=struct-,VerticalSmileys,-%3A%20View%20%7B) for this!&#x20;
   1. Unlike a normal VStack, we need to initialize columns and input that as a parameter, so make sure to do that
   2. After that, just write a ForEach inside of the LazyVGrid. You might need to make sure that your Recipe struct conforms to certain things before you can proceed with this, but XCode should tell you exactly what you need to do in this regard!
   3. Wrap your LazyVGrid with a ScrollView
4. Wrap your LazyVGrid + ScrollView component in a VStack, and add some text right above it in the VStack that says "ChefOS" just how the Figma has it (so the scroll only scrolls through the items, not the ChefOS title)
5. Make your your styling matches the Figma!

Side notes:

* You are not required to implement the bookmark icon until Part V, but you are free to do so now.
* You will not be implementing the filters until Part III.
* You do not have to worry about dynamic cell size. Set the text labels’ line limit to <mark style="color:red;">`2`</mark> lines and the height of the cell to around <mark style="color:red;">`216`</mark>. The width, however, will depend on the size of the screen. Remember, we want to have two columns. *Hint: We can multiply/divide the screen’s width by a certain factor.*
* **Do not save recipe images in the Assets catalog. You must use AsyncImage for displaying these images**

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Detailed Recipe View

***

**Your task is to create a view controller representing a detailed recipe view.** You will push this view controller when tapping on the collection view cell. This detailed view will be unique to the recipe.

**Detailed Recipe Page**

This is very straight-forward and there aren’t any tricks. Make a new view called <mark style="color:red;">`RecipePage.swift`</mark>  and implement what you see on Figma. Make sure that recipe is a property of the view (like before) so that you can input the recipe you want as a parameter.&#x20;

Remember to use AsyncImage to download the images (feel free to copy and paste).

**Navigating to the Detailed Recipe Page**

This is super simple: first, wrap your ENTIRE ContentView in a NavigationView. Then, wrap each of your RecipeCells in the ForEach from before with NavigationLink, with a destination parameter of RecipePage(recipe: recipe). Feel free to refer back to SwiftUI II's lecture for a code snippet on this.

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Filtering

***

**Your task is to create a horizontally scrolling collection view that represents the filter pills as well as adding filtering functionality.**

Here is a quick demo of what we’re expecting:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FjSiKmRla1i22MGjXdrUv%2Fa4_part3.gif?alt=media&amp;token=3acc89cf-2c0d-48b7-9b69-18f748ae33f1" alt="" width="221"><figcaption></figcaption></figure>

### Adding a Filter Collection View

In UIKit, this would be very difficult. Thankfully for you, you're coding in SwiftUI!

1. Make a selectedDifficulty property in ContentView and make a difficulties property in ContentView. Feel free to copy this in, as long as you understand why we will need the @State. Your default selectedDifficulty should be "All"

```swift
@State private var selectedDifficulty = "All"
private let difficulties: [String] = ["All", "Beginner", "Intermediate", "Advanced"]
```

2. Make a ScrollView containing a HStack between the ChefOS title and your recipe cells. The following shows how to allow for horizontal scrolling.

```swift
ScrollView(.horizontal, showsIndicators: false)
```

3. Make a ForEach in this HStack that looks through difficulties. You will need to set it up with the id parameter as well, since difficulties doesn't conform to identifiable.

```swift
ForEach(difficulties, id: \.self) {
    ...
}
```

4. Make these little capsule filter buttons inside the for each. One way to do this is by making each of them a Button. The code / function that the Button actually calls should be as easy as setting selectedDifficulty = Difficulty. Then, make the label a Text component that uses the .background() modifier with a capsule inside

<pre class="language-swift"><code class="lang-swift"><strong>Text(difficulty)
</strong><strong>// fonts and other modifiers
</strong><strong>.background(  Capsule()
</strong>                // more modifiers here for the Capsule specifically
                )
</code></pre>

### Filtering Logic

* You ***do not*** need to handle filter stacking. This is somewhat advanced so we will leave that for extra credit.
* There are many ways to determine if a cell is selected, so I will leave this up to you to decide. Make sure that the currently selected tab is highlighted with a white text color. If you are lost and have no idea where to start, feel free to ask on Ed Discussion or come to office hours.
* To filter the array of recipes, you can use the <mark style="color:red;">`filter`</mark> higher order function. Feel free to look up documentation for this, or just check out A1.

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **This is the stopping point for the midpoint submission. We will grade you for completion based on your GitHub commit history.**

**Please submit a `submission.txt` file on CMSX similar to how you did it for your A3 midpoint submission. You can download the outline below and see an example submission right under it.**
{% endhint %}

{% file src="/files/u2TNyw6cWJJ3Xi2IH5uB" %}

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
Notes: I was having trouble with setting up the UICollectionViewDelegateFlowLayout...
```

## Part IV: Fetching Recipes

***

**Your task is to create a GET request to fetch all recipes from this API:**

```
https://api.jsonbin.io/v3/b/64d033f18e4aa6225ecbcf9f?meta=false
```

You can use Postman to test the HTTP request. You will need to create a <mark style="color:red;">`NetworkManager`</mark> class with a <mark style="color:red;">`shared`</mark> singleton instance. You will be using Alamofire so make sure to import this library. See the lecture, textbook, or A3 for reference.

Error handling is not required but is nice to have. You will know if you integrated it correctly if there are more recipes than the dummy data. As a reminder, the JSON uses snake\_case but Swift uses camelCase.

Networking is one of the most important but difficult concepts to learn and implement. We want you to get as much practice as you can to prepare you for the Hack Challenge. If you are confused, please create a post on Ed Discussion or visit office hours.

**One caveat for SwiftUI is that you will need to call your fetch function (e.g. NetworkManager.fetchRecipes()) inside of a .onAppear modifier instead of viewDidLoad() like in UIKit**

You'll need to update your model for recipe to make ID into a UUID instead of a string, like this:&#x20;

```swift
var id: UUID?
```

Next, add coding keys into your recipe struct:

```swift
enum CodingKeys: String, CodingKey {
    case id, description, difficulty, imageUrl = "image_url", name, rating
}
```

Make two init functions for the recipe struct, one that is a default initializer for your dummy data, and another is a networking initializer for fetching. This is how you should do the networking initializer:

```swift
init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // Convert string ID to UUID
        if let idString = try container.decodeIfPresent(String.self, forKey: .id) {
            self.id = UUID(uuidString: idString)
        } else {
            self.id = nil
        }
        
        // Decode the rest of the properties normally
        self.description = try container.decode(String.self, forKey: .description)
        self.difficulty = try container.decode(String.self, forKey: .difficulty)
        self.imageUrl = try container.decode(String.self, forKey: .imageUrl)
        self.name = try container.decode(String.self, forKey: .name)
        self.rating = try container.decode(Float.self, forKey: .rating)
    }
```

**Finally, check that your networking is actually working. Make sure you see King Pao Chicken in your recipes in the app - that is a recipe that is in the endpoint but not the dummy data.**

{% hint style="danger" %}
**Make sure that filtering still works properly!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Bookmark Recipes

***

**Your task is to implement bookmarking functionality for these recipes.** You will need a way to keep track of bookmarked recipes to save them locally via UserDefaults.

* First, figure out what data structure you will use to keep track of bookmarked recipes. Then, think of a key that you will use to access through UserDefaults. My recommendation is that you use a BookmarkManager that is a singleton instance.
* In your BookmarkManager, you'll want to include:
  * @Published bookmarkRecipesIds, which is a Set\<UUID> (set of UUIDs from your recipe ids).
  * saveBookmarks() function that uses UserDefaults.set
  * loadBookmarks() function that loads from UserDefaults
  * toggleBookmarks() function that adds or removes the ID from bookmarkRecipeIds, and calls saveBookmarks afterwards
  * an init function that calls loadBookmarks()
* Then, in ContentView, RecipePage, and RecipeCell, set up an @StateObject called bookmarkManager that is equal to BookmarkManager.shared. If you don't make it a State object and instead use BookmarkManager.shared directly, your bookmark icons will not be updated!
* You'll need to use the <mark style="color:red;">`.onAppear{}`</mark> modifier on your views to make sure that the view gets the data from BookmarkManager.
* Update the UI so that recipes that are bookmarked should have a bookmark icon in their cell. See the Figma for UI details. See the point below on how to get the bookmark icon.
  * You will need to create a <mark style="color:red;">`ToolbarItem`</mark> to represent the bookmark button in RecipePage. This button will be in the detailed recipe view on the top right corner. If the recipe is already saved, the bookmark button will be filled and tapping on it will remove it from the saved recipes. You can add this to your RecipePage by using the <mark style="color:red;">`.toolbar{}`</mark>modifier at the end of the RecipePage and putting ToolbarItem wrapping a Button wrapping <mark style="color:red;">`Image(systemName: "bookmark")`</mark>  or <mark style="color:red;">`Image(systemName: "bookmark.fill")`</mark>
  * Adding the bookmark to the RecipeCell should be as easy as just putting the bookmark image in an if statement.&#x20;
* All saved recipes should be stored locally. You can check by restarting the app. If the saved recipes do not reset, then you are good to go.

Here is a quick demo of what we are looking for:

{% file src="/files/OJ2hEDPeJJYPDanjBwOq" %}

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Custom Back Button (+1 pt)

**Your task is to create a custom back button.** The [Figma](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1) has a possible design for this, but you are free to use any button you like. This should be a freebie if you finished the task in Part V.

### 2: Stacking Filters (+1)

Right now, you can only select one filter at a time. **Your task is to allow for filter stacking**. All selected filters should be highlighted and the collection view should contain all selected filters.

### 3: Nesting CollectionViews (+1)

Right now, you have two separate collection views: one for the filters and the other for the recipes. Because these collection views have different scrolling directions, if we wanted to make them both scrollable vertically, then we will have to nest collection views. **Your task here is to nest collection views so that the filters scroll with the recipes.** In other words, if I scroll up, the filters should scroll up as well while maintaining its horizontal scrolling attribute.

### 4: Separate Bookmark Page (+2)

**Your task here is to create a page listing out all bookmarked recipes.** The design is up to your creativity, but there needs to be some way to push the detailed recipe view where you can then bookmark/unbookmark. You may also need to use delegation to update this bookmark list, similar to what you did in Part V.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
+1 : ____
+2 : ____
```

6. Fill out this [feedback survey](https://forms.gle/rHSz5t8By1rHocAU8) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# Hack Challenge

Original Author: Vin Bui

### What is the Hack Challenge?

The Hack Challenge is an AppDev courses tradition where students across our 4 courses (iOS, Android, Backend, and DPD) come together to create their own mobile app in 2 weeks.

### Why a Hack Challenge as a final project?

The purpose of our courses is to help our students gain skills that they can take into industry. The best way to develop these skills is by pursuing projects, especially with a team. Additionally, you will be able to put this on your portfolio, which will be an important factor when applying for internships.

### How will the groups be assigned? Where will we find teams?

This depends on the number of students we have across all courses. However, most teams typically consist of 2-3 frontend members, 1-2 backend members and 1 designer. We will do a team matching mixer when the Hack Challenge begins. During this mixer, you will meet students in other courses and form a team.

Each team will also have a frontend mentor as well as a backend mentor to provide any help if needed.

### How will grading work?

As a reminder, the Hack Challenge is worth 30% of your final grade. For iOS, you are required to have the following:

#### Midpoint Submission

* Multiple screens that you can navigate between **OR** at least one scrollable view.

**Final Submission**

* Multiple screens that you can navigate between.
* At least one scrollable view.
* Networking integration with a backend API.

**Note that you can use either UIKit or SwiftUI for the Hack Challenge.**

### Do we win prizes?

Yes! We have prizes and awards for the following:

* 🏆 Best Overall
* 💻 Best Backend
* 📱 Best UI
* 🎨 Most Creative

### Past Projects

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FtoEa9xN9a5U0ggPWNodg%2FUntitled.png?alt=media&amp;token=35eef5bd-d648-4e6d-b463-c42bf059ab1d" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FRdWhPMw5Nr1djUBI7cBN%2FUntitled.png?alt=media&amp;token=3ac9ab08-d011-4b13-b132-d93aa46a10e2" alt=""><figcaption></figcaption></figure>


# FA23 Winners

Fall 2023

{% embed url="<https://www.youtube.com/watch?v=Vy4y2_1u8F0>" %}

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FBy0lOMtz3GKCHs2S3IJF%2FIMG_0459.JPG?alt=media&amp;token=4545a77f-b748-4ca3-a527-77bf70da9958" alt=""><figcaption><p>FA23 Winners</p></figcaption></figure>

## [Ithaca Traveller](https://www.youtube.com/watch?time_continue=13\&v=KVRTgewXVB8\&embeds_referring_euri=https%3A%2F%2Fdocs.google.com%2F\&embeds_referring_origin=https%3A%2F%2Fdocs.google.com\&source_ve_path=Mjg2NjY\&feature=emb_logo) - Best Backend

*Frank Dai, Qiandao Liu, James Tu, Huajie Zhong*

* Account login and registration (with profile image)
* MapKit integration with WeatherAPI
* Create a post and upload images
* Like and delete a post

<div><figure><img src="https://lh7-us.googleusercontent.com/d7f8TRJjQf6RhZKb7dUvaEfREql7vjmNvL8r95F2Dn9MuWOgLSZybUSlH10Cdw-uYzkZtVfq0Ipus6G0RLU4o9grb4kkycJhtcO6xRuzOLpa-Jk1ZUZBfRMoLLxklRLW_iI_uRCOW9nUF01NfXz5zp1QJA=s2048" alt="" width="375"><figcaption><p>Ithaca Traveller</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FBFfzpf2K2DMXFh4p3cIM%2FIMG_2522.jpeg?alt=media&amp;token=0b6ae1f7-9c94-406e-af1a-991c6e1bb7fa" alt="" width="375"><figcaption><p>Ithaca Traveller Team</p></figcaption></figure></div>

## [Latte Link](https://www.youtube.com/watch?v=h__QB02WURo) - Best UI

*Lucy Yang, Kyle Chu, Nicole Qiu, Nathan Chu, Mihili Herath*

A scheduling app that allows Cornell students to connect with coffee chatters and arrange coffee chats from a range of campus organizations.

* Simple yet effective user interface
* Easy on the eyes, not too much information at once
* Consistent design system - typography, colors, etc.
* Lots of explorations on Figma -> seems like everything was thought through pretty well

<div><figure><img src="https://lh7-us.googleusercontent.com/nTx4gL0p-Xc2P31VODMA4OgT2ltJlqtdI0hCrFAJ1ks2ZhKwbCXcbdfV0cUtNRQBki6iZ5qWZ1JHKUR_BGbaPEB5Tv6o5_UB8W81-gOyONFxGlNhpJaaMSpFxUKODD01MczYYcErhKWqwW6ryVz0ClRXgQ=s2048" alt="" width="375"><figcaption><p>Latte Link</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FuB9SuXFtzLqu2FiIxOdH%2FIMG_2523.jpeg?alt=media&amp;token=e28430c7-8e6b-465c-9f33-3f71e9f4773f" alt="" width="375"><figcaption><p>Latte Link Team</p></figcaption></figure></div>

## [ShelterSwipe](https://youtu.be/VuFvTb_Hp1Y?si=4C_xYoFBp6EmPFJh) - Most Creative

*Ilyssa Yan, Claire Wang, Cassidy Xu, Ronald Leung, Andrew Qian, Emily Silkina*

ShelterSwipe is an application where you can swipe through pets available for adoption at local shelters. We hope to match every potential pet-owner with their perfect animal to foster loving relationships and decrease the number of shelter animals.

* Very creative, cute, and wholesome idea
* Have never seen a swipe gesture used in a Hack Challenge before
* Animations when swiping was pretty sick

<div><figure><img src="https://lh7-us.googleusercontent.com/ESLVNjJ7aWT7j0kM1D5mZSd74gdKj848ivVxbNhl5ymH3xYbjGN0kVt-kUM-3hW6gu4XrFai683dylr-a0gBWoivAOtIjqtaaIzGL733NAfsrJ3t1NuW3djvcYDn1TT2fhGBd5562wnhG_zQ2L1CgevYUg=s2048" alt="" width="375"><figcaption><p>ShelterSwipe</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FD5xethWDoGPS2GLJMSnJ%2FIMG_2525.jpeg?alt=media&amp;token=74d6127e-4ec7-498e-93c3-23f4c8d8d452" alt="" width="375"><figcaption><p>ShelterSwipe Team</p></figcaption></figure></div>

## [truscoop](https://www.youtube.com/watch?v=rPHTixbiMac) - Best Overall

*Aidan Talreja, Peter Bidoshi, Daniel Chuang, Daniel Lee, Satya Datla*

AI news platform that determines the political meaning of the news article based on AI and user ratings.

* Summary generated with AI using NLP (natural language processing)
* Clean and slick/simple UI
* Can read articles within the app using WKWebView
* User ratings + ML generated ratings
* Share articles

<div><figure><img src="https://lh7-us.googleusercontent.com/o6i6PLlGOnyTJhS6Z7q4OiIEuM0b3vq5rNrQ-oLYzRIYbzYD3uomuNMUYQyPEPioC-qSsFK9ip-yapFxi5KXUG_VHRvFnZ80ifOcKQnhkq-igTYl4R63sND-f7OUx05u8jM0OxoXpPd6X5DcyJ4qNzeVjg=s2048" alt="" width="375"><figcaption><p>truscoop</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F5Gcmf2Xsauo3tgXmyRSq%2FIMG_2529.jpeg?alt=media&amp;token=c92a9aab-2813-45e8-964e-c0d78e3b1cf0" alt="" width="375"><figcaption><p>truscoop Team</p></figcaption></figure></div>


# Copy of FA25


# Logistics


# Syllabus

Fall 2025

{% hint style="danger" %}
**You will need access to a MacBook running at least Catalina and Xcode 10.14 to participate in the course.**

*Unfortunately, this is because we ran into issues stemming from older Xcode versions and its divergences from our course material.*
{% endhint %}

### Overview

This is a **2 credit S/U course**, but you may enroll for 1 credit to avoid going over the credit limit. If you haven’t already enrolled in the course:

* Enroll in **CS 1998-601** in Student Center.

**Lectures are Monday & Wednesday 8:35 - 9:25 PM in Olin Hall 165.**&#x20;

Our (tentative) course schedule can be found here:

{% content-ref url="/pages/3154CFMXK4MzJJ8P1UC9" %}
[Schedule](/resources/archived-past-semesters/fa25/logistics/schedule)
{% endcontent-ref %}

### Prerequisites

CS 1110 is a **highly recommended** co/prerequisite, but not required. **You will also need access to a MacBook running at least Catalina and Xcode 10.14 to participate in the course** (the Xcode IDE is only available for macOS).

You can check your Xcode version via the Terminal or in Xcode itself. To check within Xcode, navigate to the Menu Bar -> About Xcode. To check using Terminal, see the screenshot attached!

<div data-full-width="false"><figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FqAEd5oPbJkgd4uP96foy%2FScreenshot%202024-02-14%20at%2010.38.49%E2%80%AFAM.png?alt=media&amp;token=1af4101d-9e0f-45f9-b61b-641e297fa8ff" alt="" width="375"><figcaption><p>xcodebuild -version</p></figcaption></figure></div>

### Course Material

This entire course is **project-based** meaning there will not be any exams. There will be a Hack Challenge at the end of the course where you will work with members from our backend and design courses to put what you’ve learned to the test and build your very own mobile app. More information will be provided later.

There are **no required textbooks**. Most of the information you need will be in this course textbook. However, you are welcome to consult other iOS development resources such as *Hacking with Swift* or ***iOS Academy*** on YouTube.

All lecture slides will be posted in this textbook under “Chapters” on the sidebar. Lectures will also be recorded and posted on the [AppDev YouTube channel](https://www.youtube.com/@CornellAppDev). The demo code is located in this [GitHub](https://github.coecis.cornell.edu/intro-to-ios).

### Announcements

All course-wide announcements will be made on [Ed Discussion](https://edstem.org/us/join/DWvTfc)[.](https://edstem.org/us/courses/68540/discussion/)&#x20;

### Grading and Assignments

Our grading policy can be found here:

{% content-ref url="/pages/2spclXy1xuZprwcKHLr3" %}
[Grading](/resources/archived-past-semesters/sp25/logistics/grading)
{% endcontent-ref %}

### Attendance

Attendance will be taken at lectures and will be worth 5% of your final grade. However, in the event that you cannot make them, lectures will also be recorded and uploaded to our [YouTube channel](https://youtube.com/@CornellAppDev).

### Academic Integrity

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

When you work on an assignment, you have the option of working with a partner who can help you work on the assignment without any limitations. You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swif***t** are allowed as long as you understand the code and are not copying it exactly.

**The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.


# Grading

Fall 2025

### Breakdown

| Assignments              |             |                                                        |
| ------------------------ | ----------- | ------------------------------------------------------ |
|                          | A1          | 10%                                                    |
|                          | A2          | 15% <mark style="color:red;">+ 2%</mark>               |
|                          | A3 Midpoint | 5% (completion)                                        |
|                          | A3 Final    | 15% <mark style="color:red;">+ 3%</mark>               |
|                          | A4 Midpoint | 5% (completion)                                        |
|                          | A4 Final    | 15% <mark style="color:red;">+ 5%</mark>               |
| **Assignments Subtotal** |             | **65%&#x20;**<mark style="color:red;">**+ 10%**</mark> |
|                          |             |                                                        |
| **Hack Challenge**       |             | 30%                                                    |
| **Attendance**           |             | 5%                                                     |
|                          |             |                                                        |
| **Total**                |             | **100%**                                               |
| Extra Credit             |             | <mark style="color:red;">+ 0-10%</mark>                |
| **Passing Score**        |             | **70%**                                                |

### Late Policy

{% hint style="danger" %}
**Assignments are due at 11:59pm, but we will continue to accept submissions for 2 days. For example, if the assignment is due Tuesday, the last day we will accept the submission is Thursday.**
{% endhint %}

You are given a total of **4 free slip days**. After all free slip days have been used, there will be a **10% deduction** from that assignment’s grade per day submitted for a maximum of 2 days. In other words, **no late submissions will be accepted the third day after the normal submission deadline.** **Midpoint submissions do not count towards your slip days.** If there are any emergencies or other conflicts out of your control that prevent you from turning in your assignments on time, please reach out to the instructions so we can help you.

### Assignments

There will be a total of 4 assignments throughout the duration of the course. The weighted percentage for each submission is displayed in the table above.

**All final submissions (A1, A2, A3 Final, A4 Final) will be graded for correctness. However, A3 Midpoint and A4 Midpoint will be graded for completion.** As long as you have shown some progress on GitHub, you will receive full credit. Although these midpoint submissions are for completion, we highly recommend that you take these midpoints seriously so that you do not fall behind. We will provide feedback on midpoint submissions if requested to make sure you are on the right track

**You are allowed to work with one other person in the course for A2, A3, and A4. However, A1 must be submitted individually.** We will be using CMS for grading and submission. The submission requirements and details for each assignment will be provided later.

Assignments will be graded and returned, at the latest, one week after the normal submission deadline. **If you feel that the grader make a mistake, create a private Ed post with an explanation about the mistake.**

You will need to put in effort in order to pass this class. We will send out emails to students in jeopardy before the drop deadline. If you have any questions or concerns, please reach out to the course instructors. We care about your learning and want everyone to succeed!

### Extra Credit

There will be extra credit opportunities for every assignment where you can go above and beyond the minimum requirements. These will be challenging but are very rewarding and will definitely help you become a better developer. **You can earn up to a 2% boost for A2, 3% boost for A3 Final, and 5% boost for A4 Final, adding up to a total of 10%.** Details will be provided in the assignment handout.

### Hack Challenge

This final group project is weighted more heavily than the rest of the individual assignments, so if you don’t do so great on the assignments, a solid final project can boost your grade significantly.

**More details coming soon!**


# Office Hours

Fall 2025

{% hint style="info" %}
**Changes and Cancellations will be announced on** [**Ed Discussion**](https://edstem.org/us/courses/87232/discussion)**.**
{% endhint %}

<table><thead><tr><th width="139">Day</th><th width="152.00390625">Time</th><th width="193">Location</th><th>Staff</th></tr></thead><tbody><tr><td>Monday</td><td>3:30-4:30 pm</td><td><strong>KMB B11</strong> (Kimberly Hall)</td><td>Zain, Jiwon</td></tr><tr><td>Tuesday</td><td>12:00-1:00 pm</td><td><strong>UPS 216</strong> (Upson Hall)</td><td>Jay, Angie</td></tr><tr><td>Wednesday</td><td>3:00-4:00 pm</td><td><strong>UPS 102</strong> (Upson Hall)</td><td>Asen, Arielle</td></tr><tr><td>Thursday</td><td>4:30-5:30 pm</td><td><strong>KND 101</strong> (Kennedy Hall)</td><td>Caitlyn, Charles</td></tr><tr><td>Friday</td><td>12:00-1:00 pm</td><td><strong>STL 198</strong> (Statler Hall)</td><td>Andrew, Adelynn</td></tr></tbody></table>

> *Check out* [*this neat resource*](https://scheduling.cornell.edu/academic-scheduling/registrar-building-codes-and-contacts) *for all building codes on campus!*


# Lectures


# Logistics + Swift Basics

Fall 2025

{% hint style="info" %}
**If you are having trouble with anything within the course, please reach out to the instructors or make a post on Ed Discussion.**
{% endhint %}

Pre-Class TODOs

* [ ] Fill out the course application [here](https://forms.gle/dEvYN3QqJmpX6VRW8).
* [ ] Add the [course calendar](https://calendar.google.com/calendar/u/0/embed?src=ebgbel2kraefdhdmf1v55i8ars@group.calendar.google.com\&ctz=America/New_York) to your GCal.
* [ ] Read the Getting Started, Syllabus, and Grading sections on the left.
* [ ] Install Xcode [here](https://apps.apple.com/us/app/xcode/id497799835?mt=12). If you do not have a Mac, please reach out to the instructors.
* [ ] Set up Git and GitHub. Follow [this guide](https://ios-course.cornellappdev.com/guides/git-and-github/git-installation-guide).
  * [ ] Demo Video [here](https://www.youtube.com/watch?v=0b0bTfmPj0k\&t=2s)
* [ ] Join our [Ed Discussion](https://edstem.org/us/join/we3nbK). This is how we know you are taking the course! We will only add people to the Github and CMSX who join the Ed Discussion.&#x20;
* [ ] Enroll on Student Center (CS1998-601) if you want credit for this course.

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1cn4qrp_GP3tACtNvGLpKIuTCm9B5Y89ruEgK8gmAN-0/edit?usp=sharing>" %}

### Lecture Video (no audio ☹️)

{% embed url="<https://youtu.be/LCyxuicRtOo>" %}

### Fall 2024 Lecture Video

{% embed url="<https://youtu.be/x0bhrOiLbhQ?si=Cooc3B8QWgLac4sr>" %}


# UIKit + AutoLayout

Fall 2025

{% hint style="info" %}
**If you are having trouble with anything within the course, please reach out to the instructors or make a post on Ed Discussion.**
{% endhint %}

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1LHjsys5QvcJiGQwst_AfNMp2iB3Kee_EJ9RD_s_fCuo>" %}

### Lecture Video

{% embed url="<https://youtu.be/qdFemDAbvP8>" %}

### Lecture Demo Code

{% embed url="<https://github.com/intro-to-ios/lec2-uikit>" %}
If you prefer to download the ZIP, go to Code > Download ZIP in the Github Repository website.
{% endembed %}

#### Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/lec2-uikit
</strong><strong>OR git clone git@github.com:intro-to-ios/lec2-uikit.git
</strong></code></pre>

#### Checkout Branches

```sh
git checkout origin/1-uilabel
OR git checkout 1-uilabel

git checkout origin/2-uiimageview
OR git checkout 2-uiimageview
```

#### Classes Demo Code

```swift
class Student {
    // Properties
    var name: String
    var major: String
    var age: Int

    // Initializer
    init(name: String, major: String, age: Int) {
        self.name = name
        self.major = major
        self.age = age
    }
}

// Creating an instance of Student
let jay = Student(name: "Jay", major: "CS", age: 67)
// Access properties like below
jay.name
jay.major
jay.age

// NOTE: the super class of `EngineeringStudent` is `Student`
class EngineeringStudent: Student {
    // Inherits all properties and function from 'Student'
    // Define more properties
    var doesShower: Bool

    init(name:String, major:String, age: Int, doesShower: Bool) {
        self.doesShower = doesShower // Initalize property specific to this class
        super.init(name: name, major: major, age: age) // Call the super class's initializer
    }
}

// Creating an instance of EngineeringStudent
let asen = EngineeringStudent(name: "Asen", major: "CS", age: 22, doesShower: false)
asen.doesShower // This works fine since asen is an EngineeringStudent
jay.doesShower  // This DOESN'T work since jay is a Student. `doesShower` 
                //    is a property of EngineeringStudent but not Student
```


# MVC + Navigation + Delegation

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1x1X72SlnxHsWKQznwQZhahUdehg4Ul4ed1ZApFHw0ac>" %}

### Lecture Video

{% embed url="<https://youtu.be/8gQvKuRIpOs>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec3-navigation>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec3-navigation.git
OR git clone git@github.com:intro-to-ios/lec3-navigation.git
```

#### Checkout Branches

```sh
git checkout origin/1-navigation
OR git checkout 1-navigation

git checkout origin/2-delegation
OR git checkout 2-delegation
```


# UITableView

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1lcn8A2jIOewQ9vmJiSBGwcnk8geLEid86JkGoX1MrWM>" %}

### Lecture Video

{% embed url="<https://youtu.be/hRPPwudWbRs>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec4-uitableview>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec4-uitableview.git
OR git clone git@github.com:intro-to-ios/lec4-uitableview.git
```

#### Checkout Branches

```sh
git checkout origin/1-cell
OR git checkout 1-cell

git checkout origin/2-tableview
OR git checkout 2-tableview
```


# UICollectionView

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1n-yAMfgDpmNSUD73p65wDahqxg-H2vFkNQTorpFj1jg>" %}

### Lecture Video

{% embed url="<https://youtu.be/5sRg_SCh2GQ>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec5-uicollectionview>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec5-uicollectionview.git
OR git clone git@github.com:intro-to-ios/lec5-uicollectionview.git
```

#### Checkout Branches

```sh
git checkout origin/1-collectionview
OR git checkout 1-collectionview
```


# Networking I

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1vQjjztDv4YZDetRkXsGFXmggj_PA-JiagG4lmPyQ4dk>" %}

### Lecture Video (no audio 😢)

{% embed url="<https://youtu.be/t7UHFqxVbqY>" %}

### Lecture Demo

Install Postman and create a GET Request: <https://ios-course-backend.cornellappdev.com/api/members>

Docs: <https://ios-course-backend.cornellappdev.com/api/docs/#/>

{% content-ref url="/pages/yn6cHzsajLYZbsC7ylnb" %}
[Postman](/resources/tool-guides/postman)
{% endcontent-ref %}


# Networking II

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/10ZkNx9Tfjm3pASnWPHIokuTYxD8K0CMMUycHDtZGa3Y>" %}

### Lecture Video

{% embed url="<https://youtu.be/gm4zGPa-aeU>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec7-networking2>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec7-networking2.git
OR git clone git@github.com:intro-to-ios/lec7-networking2.git
```

#### Checkout Branches

```sh
git checkout origin/1-get
OR git checkout 1-get

git checkout origin/2-post
OR git checkout 2-post

git checkout origin/3-refresh
OR git checkout 3-refresh
```


# Persistence + SnapKit

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1Gz9r9YqrBae2iUX_YVFzdumrPPvkeTLA9HfwLmUvZs8/>" %}

### Lecture Video

{% embed url="<https://youtu.be/WvqM85xnkrc>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec8-persist-snapkit>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec8-persist-snapkit.git
OR git clone git@github.com:intro-to-ios/lec8-persist-snapkit.git
```

#### Checkout Branches

```sh
git checkout origin/1-userdefaults
OR git checkout 1-userdefaults

git checkout origin/2-snapkit
OR git checkout 2-snapkit
```


# SwiftUI I

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1AGFmg1TdTJKRTT_KidX5jDZZ8U1EJT1OEUKkoR-mZxk>" %}

### Lecture Video

{% embed url="<https://youtu.be/YbFbd21jpRc>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec10-swiftui-1>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
### Part I ###
git clone https://github.com/intro-to-ios/lec10-swiftui-1.git
OR git clone git@github.com:intro-to-ios/lec10-swiftui-1.git
```

#### Checkout Branches

<pre class="language-sh"><code class="lang-sh">### Part I ###
<strong>git checkout origin/1-layouts
</strong>OR git checkout 1-layouts

git checkout origin/2-list
OR git checkout 2-list

git checkout origin/3-refactor
OR git checkout 3-refactor
</code></pre>


# SwiftUI II

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1n695wEZgEV68hwq856KeM_tQTznBv8xWmZmUunhA6Vo>" %}

### Lecture Video

{% hint style="warning" %}
It seems like the code isn't showing for the demo part of the lecture, so we'll add last semester's lecture video below for reference. Sorry about that!
{% endhint %}

{% embed url="<https://youtu.be/YiGw9pUovc8?si=l97vxJzIZ9JiiGeS>" %}

### Spring 2025 Lecture Video

{% embed url="<https://youtu.be/hbpU5hsNm5o?si=-yoBiE3tA-cTuL4m>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec11-swiftui-2.git>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```shellscript
### Part II ###
git clone https://github.com/intro-to-ios/lec11-swiftui-2.git
OR git clone git@github.com:intro-to-ios/lec11-swiftui-2.git
```

#### Checkout Branches

```shellscript
### Part II ###
git checkout origin/1-navigation
OR git checkout 1-navigation

git checkout origin/2-button
OR git checkout 2-button

git checkout origin/3-textfield
OR git checkout 3-textfield
```


# MVVM

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1vYZIn8SsxCJvXYuHU2-x6yEelR03asZZRiAhRJ3BHGg>" %}

### Lecture Video

{% embed url="<https://youtu.be/HEBnp3YlOGQ>" %}

### Lecture Demo

{% embed url="<https://github.com/AsenKimO/demo-mvvm>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```shellscript
### Part II ###
git clone https://github.com/AsenKimO/demo-mvvm.git
OR git clone git@github.com:AsenKimO/demo-mvvm.git
```

#### Checkout Branches

```shellscript
git checkout origin/1-viewmodel
OR git checkout 1-viewmodel

git checkout origin/2-favoriting
OR git checkout 2-favoriting

git checkout origin/3-networking
OR git checkout 3-networking

git checkout origin/4-darkmode
OR git checkout 4-darkmode
```


# (12) Core ML

Fall 2025

{% hint style="info" %}
This lecture is a **guest lecture** featuring two of our most special members from the iOS subteam:\
**Jiwon Jeong** and **Zain Bilal!**
{% endhint %}

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/158tbz3F9ej4YbSeq9kOmxaCRPH2WihNpB1lM9dAXYH8/edit?usp=sharing>" %}

### Lecture Video

{% embed url="<https://youtu.be/X81CZWDJeyM>" %}

### Lecture Demo

{% embed url="<https://github.com/JiwonJeong414/BetterRest>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

### Data

{% file src="/files/fmKdDj8bgeV9tKUnlmFZ" %}

#### Clone the Repository

```shellscript
git clone https://github.com/JiwonJeong414/BetterRest.git
OR git clone git@github.com:JiwonJeong414/BetterRest.git
```


# (13) Deployment

Fall 2025

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/13EwruDqlMMn39XQM88cG3ErV5S0OV1Lgpd8FzFcDdY4/edit?usp=sharing>" %}

**Useful resources:**

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/fqEtWX9Am6RYrp47NG3m" %}
[Project Foundation](/resources/textbook/project-foundation)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/fbjDTQB9Ql31uEsaO6Vh" %}
[CI/CD](/resources/textbook/ci-cd)
{% endcontent-ref %}

{% embed url="<https://developer.apple.com/documentation/xcode/distribution>" %}
\*Look under the **Distribution and continuous integration** section\*
{% endembed %}


# Assignments


# A2: Profile

Original Author: Vin Bui

{% hint style="danger" %}
**Assignment Due: Thursday Oct 30, 2025 11:59pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands). Otherwise, we will create a repository for you.**
{% endhint %}

{% file src="/files/rFSbGbSKutB3htStOdgy" %}

## Overview

***

In this assignment, you will be creating your first ever iOS application using UIKit programmatically. You will be creating a Profile and Edit Profile page, commonly seen in many apps today.

## Learning Objectives

***

**Developer Skills**

* **How to format and structure your code to follow MVC design pattern**
* **How to follow common styling conventions used in industry**
* **How to implement designs created on Figma**
* How to work with Git and GitHub for version control
* How to read documentation from outside resources

**Course Material**

* How to create classes such as a <mark style="color:red;">`UIViewController`</mark>
* How to create and customize a <mark style="color:red;">`UIView`</mark> and position them with <mark style="color:red;">`NSLayout`</mark>
  * <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIButton`</mark>, <mark style="color:red;">`UIImageView`</mark>, <mark style="color:red;">`UIImage`</mark>, <mark style="color:red;">`UITextField`</mark>
* How to navigate between view controllers using a <mark style="color:red;">`UINavigationController`</mark> and popping/pushing
* How to use delegation to communicate between view controllers
* How to implement design system using <mark style="color:red;">`UIFont`</mark> and <mark style="color:red;">`UIColor`</mark>

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/sp25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Creating the Profile Page**</mark>              | <mark style="color:blue;">**\_ / 3**</mark>        |
| ----------------------------------------------------------------------------------- | -------------------------------------------------- |
| UI: Profile Image                                                                   | \_ / 1                                             |
| UI: Name, Bio                                                                       | \_ / 1                                             |
| UI: Hometown and Major                                                              | \_ / 1                                             |
| <mark style="color:blue;">**PART II: Push the Edit Profile Page**</mark>            | <mark style="color:blue;">**\_ / 2**</mark>        |
| UI: Edit Profile Button                                                             | \_ / 1                                             |
| F: Pushes <mark style="color:red;">`EditProfileVC`</mark>                           | \_ / 1                                             |
| <mark style="color:blue;">**PART III: Create the Edit Profile Page**</mark>         | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Profile Image                                                                   | \_ / 1                                             |
| UI: Name, Bio                                                                       | \_ / 1                                             |
| UI: Hometown and Major TextFields                                                   | \_ / 1                                             |
| <mark style="color:blue;">**PART IV: Pop the Edit Profile Page**</mark>             | <mark style="color:blue;">**\_ / 2**</mark>        |
| UI: Save Button                                                                     | \_ / 1                                             |
| F: Pops <mark style="color:red;">`EditProfileVC`</mark>                             | \_ / 1                                             |
| <mark style="color:blue;">**PART V: Delegation**</mark>                             | <mark style="color:blue;">**\_ / 3**</mark>        |
| F: Clicking on <mark style="color:red;">`Save`</mark> updates the main Profile page | \_ / 3                                             |
| <mark style="color:blue;">**OTHER**</mark>                                          | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                     | \_ / 1                                             |
| Styling: <mark style="color:red;">`viewDidLoad`</mark> calls helper functions       | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                      | <mark style="color:green;">**\_ / 15**</mark>      |
| EC: Custom back button                                                              | + 1                                                |
| EC: Edit profile picture                                                            | + 1                                                |
| Deduction: Crash Tax                                                                | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                   | <mark style="color:green;">**\_ / 15 (+2)**</mark> |

## Getting Started

***

### Setting up Figma

You can find the link to the Figma [here](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). If you do not have an account, you can create one under your Cornell email. I will provide details on how to navigate through Figma later.

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the [`Git Installation Section`](https://ios-course.cornellappdev.com/~/revisions/wrtYMFJVea8chxL2Ntds/resources/textbook/git-+-github/git-installation), or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Cloning the Repository

Navigate to a folder on your device where you will keep all of your assignments. You can navigate to the folder using <mark style="color:red;">`cd`</mark> in Terminal.

Clone the repository on GitHub:

* Replace **NETID** with your NetID
* Replace **SEM** with the semester (in this case <mark style="color:red;">`sp25`</mark>)

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-FA25/NETID-a2.git
# Ex: git clone git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a2.git
```

If you have a partner, replace **NETID1** and **NETID2**. Try changing the order if the former does not work.

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-FA25/NETID1-NETID2-a2.git
```

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a2`</mark> should contain an Xcode project called <mark style="color:red;">`A2.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard.

If you expand everything underneath <mark style="color:red;">`A2`</mark> you should see the following:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fmj0x1GlWzLSyfQvY51SH%2FUntitled.png?alt=media&amp;token=c8a86de6-493b-4e02-8ef5-2a2f6ef71976" alt="" width="237"><figcaption></figcaption></figure>

**You will be working on&#x20;**<mark style="color:red;">**`ProfileVC.swift`**</mark>**,&#x20;**<mark style="color:red;">**`EditProfileVC.swift`**</mark>**, and&#x20;**<mark style="color:red;">**`Assets.xcassets`**</mark>**.**

## Assignment Files

***

### `ProfileVC.swift`

You will be creating the *main profile page* in this file, primarily in Parts I and II. You are responsible for creating the UI design based on the [Figma](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). This view controller is the root view controller inside of a <mark style="color:red;">`UINavigationController`</mark> located in <mark style="color:red;">`SceneDelegate.swift`</mark>. You will be asked to push <mark style="color:red;">`EditProfileVC`</mark> onto this navigation stack.

### `EditProfileVC.swift`

You will be creating the *edit profile page* in this file, primarily in Parts III and IV. You will be implementing the UI design based on the [Figma](https://www.figma.com/file/DKuxKTVPuD9wrBi1z1an51/A2%3A-Profile?type=design\&node-id=0%3A1\&mode=design\&t=j6wcHREZ97Q0tawI-1). This view controller will be pushed by <mark style="color:red;">`ProfileVC`</mark> onto the navigation stack. You will be asked to implement popping functionality as well as delegation to save changes from the text field.

### `UIColor+Extension.swift`

**DO NOT EDIT THIS FILE!** This file contains colors that are featured in the Figma design. To use the colors, simply type <mark style="color:red;">`UIColor.a2.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FVxatHYWE39O33tL8yrWX%2FUntitled.png?alt=media&amp;token=b2b2473c-76e3-42c7-baba-194127743474" alt=""><figcaption><p>From the Figma Design</p></figcaption></figure>

## Using Figma and Importing Assets

***

For the scope of this course, we will be teaching you the skills necessary to read a design implemented on Figma. This is widely used both on AppDev and in industry, so it’s important to have this skill in your toolkit. Please read over the [Figma guide](/resources/tool-guides/figma) now.

## Styling

***

Throughout the provided files, you may have noticed the <mark style="color:red;">`// MARK`</mark> comments. These are used to keep the code organized.

* <mark style="color:red;">`Properties (View)`</mark> are used for <mark style="color:red;">`UIView`</mark> objects such as <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIImageView`</mark>, etc. **You should mark these properties as** <mark style="color:red;">`private`</mark> **and make them&#x20;*****constants*****&#x20;(use** <mark style="color:red;">`let`</mark>**).**
* <mark style="color:red;">`Properties (Data)`</mark> are used for data types such as <mark style="color:red;">`String`</mark>, <mark style="color:red;">`Int`</mark>, delegates, etc. **Again, mark these properties as** <mark style="color:red;">`private`</mark> **but it is up to you to decide if they are constants or variables.**
* The <mark style="color:red;">`Set Up Views`</mark> section should be used for initializing your view properties.

You are not limited to these sections and are free to add more (and you should). Because many of your data properties are marked as <mark style="color:red;">`private`</mark>, you ***may*** need to create an <mark style="color:red;">`init`</mark> function.

Follow these steps when implementing the UI:

1. Create the view
2. Initialize the view
3. Constrain the view
4. Run, confirm, and repeat

{% hint style="danger" %}
**Your&#x20;**<mark style="color:red;">**`viewDidLoad`**</mark>**&#x20;method should contain&#x20;*****mostly*****&#x20;function calls to helper functions. We will be grading you on this.**
{% endhint %}

## Part I: Creating the Profile Page

***

**Your task is to create the UI for the&#x20;*****main profile page*****&#x20;in&#x20;**<mark style="color:red;">**`ProfileVC`**</mark>**.** This profile can be for you, your partner, or if you want you can use me (Vin). Do not worry about any functionality here. We will do that in Part II. Your profile will have the following:

* Profile Image: <mark style="color:red;">`UIImageView`</mark>
  * You will need to add the image to <mark style="color:red;">`Assets.xcassets`</mark>. Refer to the Figma guide.
  * To get a perfect circle, set the <mark style="color:red;">`layer.cornerRadius`</mark> of the <mark style="color:red;">`UIImageView`</mark> to the radius (set it to the width of the image divided by 2) and set <mark style="color:red;">`layer.masksToBounds`</mark> to <mark style="color:red;">`true`</mark>.
* Name: <mark style="color:red;">`UILabel`</mark>
  * You can get the colors from Figma under the “Inspect” section. To use the color, type: <mark style="color:red;">`UIColor.a2.<color_name>`</mark>
  * You can get the font **weight** and **size** from Figma under the “Inspect” section. Set the “Code” to `iOS`. To set the font, type: <mark style="color:red;">`.systemFont(ofSize: <size>, <weight>)`</mark>. **Do not use the code. You should only look at the font name and size.**
    * **Make sure you use the weight from the font name instead of the number. For example, even though Figma says a weight of&#x20;**<mark style="color:red;">**`600`**</mark>**, the weight should be&#x20;**<mark style="color:red;">**`.semibold`**</mark>**.**
  * If any of these fields are too long, you can set the <mark style="color:red;">`numberOfLines`</mark> property to <mark style="color:red;">`0`</mark> for unlimited lines.
* Bio: <mark style="color:red;">`UILabel`</mark> (or <mark style="color:red;">`UITextView`</mark>)
  * To make the text italic, use: <mark style="color:red;">`.italicSystemFont(ofSize: <size>)`</mark>
* Hometown: <mark style="color:red;">`UIImageView`</mark> for the icon, <mark style="color:red;">`UILabel`</mark> for the text
* Major: <mark style="color:red;">`UIImageView`</mark> for the icon, <mark style="color:red;">`UILabel`</mark> for the text

Don’t forget to set the title of the view controller to <mark style="color:red;">`“My Profile”`</mark> and background color.

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Push the Edit Profile Page

***

**You task is to create the “Edit Profile” button as well as pushing&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**&#x20;onto the navigation stack.**

Edit Profile Button: <mark style="color:red;">`UIButton`</mark>

* To change the text, use <mark style="color:red;">`setTitle(<text>, for: .normal)`</mark>
* To change the text color, use <mark style="color:red;">`setTitleColor(<color>, for: .normal)`</mark>
* To change the background color, use <mark style="color:red;">`backgroundColor = <color>`</mark>
* To change the corner radius, use <mark style="color:red;">`layer.cornerRadius = <radius>`</mark>. You can get this under “Inspect > Properties” in Figma on the right hand side.
* As a hint, you will need to add the following constraints: leading, trailing, bottom, and height (not width)
* To add functionality to this button when tapped, use <mark style="color:red;">`addTarget(self, #selector(<function_to_call>), for: .touchUpInside)`</mark>

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Create the Edit Profile Page

***

**Your task is to create the UI for the&#x20;*****edit profile page*****&#x20;in&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**.** Do not worry about any functionality here. We will do that in Part IV. Consult Part I for hints on how to implement these views. This page will have the following:

* Profile Image: <mark style="color:red;">`UIImageView`</mark>
* Name: <mark style="color:red;">`UILabel`</mark>
* Bio: <mark style="color:red;">`UILabel`</mark> (or <mark style="color:red;">`UITextView`</mark>)
* Hometown: <mark style="color:red;">`UILabel`</mark> for the text, <mark style="color:red;">`UITextField`</mark> for the text field
  * To set the border width, use <mark style="color:red;">`layer.borderWidth = <width>`</mark>
  * To set the border color, use <mark style="color:red;">`layer.borderColor = <color>`</mark>
    * The color must be a CGColor. Use the following line: <mark style="color:red;">`UIColor.a2.silver.cgColor`</mark>
  * To set the corner radius, use <mark style="color:red;">`layer.cornerRadius = <radius>`</mark>
  * For the text field, you will need to set following constraints: top, leading, trailing, and height (not width)
  * Creating the padding before the text inside of the textfield is not as straight forward, so it’s okay to not have it. However, if you are interested, check [this](https://stackoverflow.com/questions/25367502/create-space-at-the-beginning-of-a-uitextfield) out.
* Major: <mark style="color:red;">`UILabel`</mark> for the text, <mark style="color:red;">`UITextField`</mark> for the text field

You will need to create a data property to store some information. Mark these properties as <mark style="color:red;">`private`</mark> and create an <mark style="color:red;">`init`</mark> function. Make sure to include the following line after initializing your properties: <mark style="color:red;">`super.init(nibName: nil, bundle: nil)`</mark>. The values for these properties will be passed in from <mark style="color:red;">`ProfileVC`</mark>.

{% hint style="info" %}
**If you haven’t realized it yet, for most of the setup functions you can copy and paste from the previous and make slight modifications!**
{% endhint %}

Don’t forget to set the title of the view controller to <mark style="color:red;">`“Edit Profile”`</mark> and background color.

**Once you are done, stage, commit, and push to GitHub.**

## Part IV: Pop the Edit Profile Page

***

**You task is to create the “Save” button as well as popping&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**&#x20;from the navigation stack.**

Save Button: <mark style="color:red;">`UIButton`</mark>

* See Part II for implementation hints

{% hint style="info" %}
**If you implemented Part II correctly, this should be as simple as copy and pasting!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Delegation

***

**You task is to use delegation to update information from&#x20;**<mark style="color:red;">**`ProfileVC`**</mark>**&#x20;based on the text fields in&#x20;**<mark style="color:red;">**`EditProfileVC`**</mark>**.** Remember these steps:

1. Create a protocol with a function
2. Conform <mark style="color:red;">`ProfileVC`</mark> to the protocol (delegate)
   * Implement the function
3. Create a property in <mark style="color:red;">`EditProfileVC`</mark> to reference <mark style="color:red;">`EditProfileVC`</mark> (delegator)
   * Make sure it has <mark style="color:red;">`weak`</mark> before it. If this property is <mark style="color:red;">`private`</mark>, make sure to initialize it in the <mark style="color:red;">`init`</mark> function.
4. Call the function in <mark style="color:red;">`EditProfileVC`</mark>

If you have forgotten how to implement delegation, view the lecture notes or textbook.

To access the text from a <mark style="color:red;">`UITextField`</mark>, use the <mark style="color:red;">`text`</mark> property of the text field. Note that this gives you an optional.

**Double check that your main profile updates when you click save. Then click on “Edit Profile” again and make sure that the text fields in the edit profile page are also updated.**

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="danger" %}
**If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Custom Back Button (+1 pt)

When using a <mark style="color:red;">`UINavigationController`</mark>, there is a default back button. However, it does not look nice with our design so **your task is to customize the back button**. The Figma contains the design for this feature. As a hint, the icon used is known as an **SF Symbol** called <mark style="color:red;">`chevron.left`</mark>. You do not need to export this icon; it is built-in.

### 2: Edit Profile Picture (+1 pt)

This one is ***a lot*** more challenging than the previous feature. **Your task here is to allow the user to edit their profile picture.** You can access their camera roll, photo library, or both.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a2.git
Extra Credit:
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://forms.gle/xD16BJgyUyDumsEs8) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# A3: ChatDev

Original Author: Vin Bui

{% hint style="danger" %}
**Midpoint Due: Wednesday, November 5, 2025 11:59 pm**\
**Final Due: Monday, November 10, 2025 11:59 pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands). Otherwise, we will create a repository for you.**
{% endhint %}

{% file src="/files/0AGMMjho0PH0Np3SRCEd" %}

## Overview

***

In this assignment, you will be creating a “social media” app. You will be using Alamofire to send HTTP requests to a backend endpoint to fetch information.

## Learning Objectives

***

**Developer Skills**

* **How to use Postman to test HTTP requests**
* **How to read code written by other developers**
* **How to read data received from the backend to structure frontend code**
* How to work with Git and GitHub for version control
* How to read documentation from outside resources
* How to format and structure your code to follow MVC design pattern
* How to follow common styling conventions used in industry
* How to implement designs created on Figma

**Course Material**

* How to represent lists of data using a <mark style="color:red;">`UICollectionView`</mark> and a <mark style="color:red;">`UICollectionViewCell`</mark>
* How to send GET requests to a backend API using Alamofire
* How to send POST requests to a backend API using Alamofire
* How to write callbacks (completion handlers) to handle asynchronous calls
* How to create a <mark style="color:red;">`NetworkManager`</mark> singleton class to contain network calls
* How to decode a JSON using a <mark style="color:red;">`JSONDecoder`</mark> in Swift
* How to handle errors with networking calls

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/fa25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

<table data-header-hidden><thead><tr><th width="374"></th><th></th></tr></thead><tbody><tr><td><mark style="color:blue;"><strong>PART I: Creating the UICollectionViewCell</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>UI: Header (name, date, image)</td><td>_ / 1</td></tr><tr><td>UI: Post Message, Like Button, # Likes</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART II: Creating the UICollectionView</strong></mark></td><td><mark style="color:blue;"><strong>_ / 3</strong></mark></td></tr><tr><td>UI: Multiple sections</td><td>_ / 1</td></tr><tr><td>UI: Dynamic number of items/cells (adding a new Post to the array adds a new item/cell)</td><td>_ / 1</td></tr><tr><td>UI: Each cell is unique and represents a different Post</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART III: Fetching Posts</strong></mark></td><td><mark style="color:blue;"><strong>_ / 3</strong></mark></td></tr><tr><td>F: GET Request to Fetch Posts</td><td>_ / 2</td></tr><tr><td>F: Refresh Control</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>PART IV: Creating a Post</strong></mark></td><td><mark style="color:blue;"><strong>_ / 3</strong></mark></td></tr><tr><td>F: POST Request to Create a Post</td><td>_ / 3</td></tr><tr><td><mark style="color:blue;"><strong>PART V: Liking a Post</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>F: POST Request to Like a Post</td><td>_ / 1</td></tr><tr><td>F: ❤️ turns red if liked, # likes goes up</td><td>_ / 1</td></tr><tr><td><mark style="color:blue;"><strong>OTHER</strong></mark></td><td><mark style="color:blue;"><strong>_ / 2</strong></mark></td></tr><tr><td>Feedback Survey</td><td>_ / 1</td></tr><tr><td>Styling: <mark style="color:red;"><code>viewDidLoad</code></mark> calls helper functions</td><td>_ / 1</td></tr><tr><td><mark style="color:green;"><strong>SUBTOTAL</strong></mark></td><td><mark style="color:green;"><strong>_ / 15</strong></mark></td></tr><tr><td>EC: POST Request to Unlike a Post</td><td>+ 1</td></tr><tr><td>EC: Sort by Top/New posts</td><td>+ 1</td></tr><tr><td>EC: Animation when liking a Post</td><td>+ 1</td></tr><tr><td>Deduction: Crash Tax</td><td>-1 point</td></tr><tr><td><mark style="color:green;"><strong>GRAND TOTAL</strong></mark></td><td><mark style="color:green;"><strong>_ / 15 (+3)</strong></mark></td></tr></tbody></table>

## Getting Started

***

### Using Postman

You are encouraged to use [Postman](https://www.postman.com/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

### Using Figma

Similar to A2, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Cloning the Repository

Navigate to a folder on your device where you will keep all of your assignments. You can navigate to the folder using <mark style="color:red;">`cd`</mark> in Terminal.

Clone the repository on GitHub:

* Replace **NETID** with your NetID
* Replace **SEM** with the semester (such as <mark style="color:red;">`fa23`</mark> or <mark style="color:red;">`sp24`</mark>)

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
# Ex: git clone git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a3.git
```

If you have a partner, replace **NETID1** and **NETID2**. Try changing the order if the former does not work.

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID1-NETID2-a3.git
```

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a3`</mark> should contain an Xcode project called <mark style="color:red;">`A3.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard. You should see something like this:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fu2a0T7G9eF0zkAKBpLZp%2FScreenshot%202023-10-31%20at%206.53.19%E2%80%AFPM.png?alt=media&amp;token=57ef94be-459f-45b3-8a6c-5bc18febf589" alt="" width="262"><figcaption></figcaption></figure>

## Assignment Files

***

There is already code written in this file. As developers, we often build on top of what others have written which is why it is important that you practice this skill. You will often see code that you have never seen before, and it is your job to understand it.

### `FeedVC.swift`

This file contains the main view controller that you will be working with throughout the entire assignment. The “Create Post” cell has already been implemented but you will notice that you cannot see it. You will need to finish setting up the collection view. The lecture does not go over how to create different sections; however, the process is very similar to what we went over in lecture and we will guide you in this handout. There are <mark style="color:red;">`TODO`</mark> comments to help guide you.

### `CreatePostCollectionViewCell.swift`

This file represents the cell to create a post. You are free and encouraged to look over this file to help you implement your own custom collection view cell. You can also reference the lecture or textbook chapter [here](broken://pages/QbHalx1aTnlWeCmF8y8e). In addition, you will be asked to write code to send a network request to create a post. There is a <mark style="color:red;">`TODO`</mark> comment indicating where you should implement this logic.

### `NetworkManager.swift`

This file will contain the Alamofire code to send HTTP requests to the backend. Refer to the lectures or textbook chapters [here](broken://pages/E9fBwDbUqFlypMQFRx4o).

### `Date+Extension.swift`

**DO NOT EDIT THIS FILE!** This file contains a function <mark style="color:red;">`convertToAgo`</mark> that returns a string representation of the <mark style="color:red;">`Date`</mark> object indicating how long ago this post was created. You will call this function on the property holding the post’s date when you create your custom collection view cell.

### `UIColor+Extension.swift`

**DO NOT EDIT THIS FILE!** Similar to A2, this file contains colors that are featured in the [Figma](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1) design. To use the colors, simply type <mark style="color:red;">`UIColor.a3.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fq5I0dUR2sGvei9vwAJJl%2FUntitled.png?alt=media&amp;token=0d1e2ed0-6665-44de-8807-4e4392a9cb82" alt="" width="226"><figcaption><p>From the Figma Design</p></figcaption></figure>

## Styling

***

Throughout the provided files, you may have noticed the <mark style="color:red;">`// MARK`</mark> comments. These are used to keep the code organized.

* <mark style="color:red;">`Properties (View)`</mark> are used for <mark style="color:red;">`UIView`</mark> objects such as <mark style="color:red;">`UILabel`</mark>, <mark style="color:red;">`UIImageView`</mark>, etc. **You should mark these properties as** <mark style="color:red;">`private`</mark> **and make them&#x20;*****constants*****&#x20;(use** <mark style="color:red;">`let`</mark>**).**
* <mark style="color:red;">`Properties (Data)`</mark> are used for data types such as <mark style="color:red;">`String`</mark>, <mark style="color:red;">`Int`</mark>, delegates, etc. **Again, mark these properties as** <mark style="color:red;">`private`</mark> **but it is up to you to decide if they are constants or variables.**
* The <mark style="color:red;">`Set Up Views`</mark> section should be used for initializing your view properties.

You are not limited to these sections and are free to add more (and you should). Because many of your data properties are marked as <mark style="color:red;">`private`</mark>, you ***may*** need to create an <mark style="color:red;">`init`</mark> function.

Follow these steps when implementing the UI:

1. Create the view
2. Initialize the view
3. Constrain the view
4. Run, confirm, and repeat

{% hint style="danger" %}
**Your&#x20;**<mark style="color:red;">**`viewDidLoad`**</mark>**&#x20;method should contain&#x20;*****mostly*****&#x20;function calls to helper functions. We will be grading you on this.**
{% endhint %}

## Endpoints

***

* **Endpoint:** [**https://ios-course-backend.cornellappdev.com/api/posts**](https://ios-course-backend.cornellappdev.com/api/posts)

<mark style="color:red;">(EDIT 4/14 23:23: For liking and unliking a post, you'll have to pass in the post ID as a parameter of the URL)</mark>

|                 | Type | Route                       | Request Body                                       |
| --------------- | ---- | --------------------------- | -------------------------------------------------- |
| Fetch all posts | GET  | /api/posts/                 | None                                               |
| Create a post   | POST | /api/posts/create/          | <mark style="color:red;">`message`</mark> (String) |
| Like a post     | POST | /api/posts/{postId}/like/   | <mark style="color:red;">`netId`</mark> (String)   |
| Unlike a post   | POST | /api/posts/{postId}/unlike/ | <mark style="color:red;">`netId`</mark> (String)   |

## Part I: Creating the <mark style="color:red;">`UICollectionViewCell`</mark>

***

**Your task is to create a custom&#x20;**<mark style="color:red;">**`UICollectionViewCell`**</mark> **for the post**. **Create this file inside of the&#x20;**<mark style="color:red;">**`Views`**</mark>**&#x20;folder.** You will need to create a struct or class (struct recommended) to represent a post. **Create this file inside of the&#x20;**<mark style="color:red;">**`Models`**</mark>**&#x20;folder**. As a reference, this is an example post object in JSON fetched from the backend.

```json
{
    "id": "7m03J198pyXFBvCOLNbw",
    "likes": ["vdb23", "rs929"],
    "messsage": "Howdy!",
    "time": "2023-06-12T22:03:23Z"
}
```

You will need to figure out the name and type of your properties for this object. **However, the&#x20;**<mark style="color:red;">**`time`**</mark>**&#x20;property will be a&#x20;**<mark style="color:red;">**`Date`**</mark>**&#x20;object (even though it’s a string in the JSON).** I will show you how to decode this in Part III.

Because you have not implemented networking yet, you will need to create dummy data to test the UI. When creating these dummy data, you can use the code <mark style="color:red;">`Date()`</mark> for the <mark style="color:red;">`time`</mark> property. For the other fields, you can customize it however you like.

Your custom cell class will have the following:

* Name (”Anonymous”)
* Date
* Image (AppDev Logo)
* Post message body
* Like button (use non-filled heart for now)
* Number of likes

Keep in mind the background color, text color, font style, corner radius, etc. You should already have practice in A2 implementing views so I will not guide you as much as A2. Feel free to Google or look at the <mark style="color:red;">`CreatePostCollectionViewCell`</mark> class as a reference. However, your custom cell class differs in that it will need a <mark style="color:red;">`configure`</mark> method. **You can use the&#x20;**<mark style="color:red;">**`convertToAgo`**</mark>**&#x20;function for the date object and assign it to the label’s text to format the “time ago” string.**

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Creating the <mark style="color:red;">`UICollectionView`</mark>

***

**Your task is to create a&#x20;**<mark style="color:red;">**`UICollectionView`**</mark>**&#x20;representing the feed.** There is already some code written that you will need to look over. There is also a custom cell class called <mark style="color:red;">`CreatePostCollectionViewCell`</mark> that represents the “Create Post” cell already implemented for you. You will need to register and use this cell along with the other custom cell you created in Part I.

**This collection view contains 2 sections, each section containing different cell classes.**

* Similar to items, sections are zero-indexed meaning that the first section has index 0. Use this information to implement the functions required to conform to <mark style="color:red;">`UICollectionViewDataSource`</mark>, <mark style="color:red;">`UICollectionViewDelegate`</mark>, and <mark style="color:red;">`UICollectionViewFlowLayoutDelegate`</mark>.
* When creating your FlowLayout, keep in mind the spacing between each item is 16px and between each section is 24px. To add the spacing between sections, implement the <mark style="color:red;">`insetForSectionAt`</mark> function in the <mark style="color:red;">`UICollectionViewDataSource`</mark> extension.

The first section contains only 1 cell and there is no data model associated with it. Again, the custom cell class for this section is <mark style="color:red;">`CreatePostCollectionViewCell`</mark>. I highly recommend that you read and understand the code written in this class. Once you are able to see this cell in your collection view, begin implementing the second section.

The second section contains a variable number of cells indicating that you will need a data model representing the posts. Because you have not implemented networking yet, you will need to create dummy data to test this. If you can see both sections and their cells, you should be good to go.

{% hint style="danger" %}
**Note: For the scope of this course, we will not be handling self-sizing cells. The height for each cell is fixed and there are a maximum of three lines for the post message.**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **This is the stopping point for the midpoint submission. We will grade you for completion based on your GitHub commit history.**

**Please submit a `submission.txt` file on CMSX similar to how you did it for your A2 submission. You can download the outline below and see an example submission right under it.**
{% endhint %}

{% file src="/files/T0mO1eR7fdASVffFG8uk" %}

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
Notes: I was having trouble with setting up the UICollectionViewDelegateFlowLayout...
```

## Part III: Fetching Posts

***

**Your task is to send a GET request using Alamofire to fetch all posts from the backend.** Currently, your posts are all hard-coded dummy data. Of course, we want to be able to receive posts created by other people, so we must integrate networking. In Part I, you were given an example JSON representing a post, and you created your model object based on this JSON. The reason for this is that it makes decoding the JSON received from the backend to your model very simple.

If you have not installed Postman yet, you can install it [here](https://www.postman.com/). Read [this short chapter](https://ios-course.cornellappdev.com/guides/postman) on how to use Postman for this assignment. Then, add a new GET request with the URL: <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/`</mark> . This should return a list of all posts from the backend with a 200 status code.

Your job is to integrate these posts into the frontend. You can decode the <mark style="color:red;">`time`</mark> field to a <mark style="color:red;">`Date`</mark> object if you set the decoder’s <mark style="color:red;">`dateDecodingStrategy`</mark> to <mark style="color:red;">`.iso8601`</mark>. For example:

```swift
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
```

Your callback (completion handler) will take in an array of <mark style="color:red;">`Post`</mark> objects (<mark style="color:red;">`[Post]`</mark>). It will also be very helpful to have proper error handling in your code. Refer to the lecture or textbook chapter [here](broken://pages/Fxlid2ij8oOA7jaHpx5R).

**Once you are able to fetch all posts from the backend, your next task is to add pull to refresh to your collection view.** Follow these steps:

```swift
// 1. Create a UIRefreshControl view property
private let refreshControl = UIRefreshControl()

// 2. Add a function to be called as a target
refreshControl.addTarget(self, action: #selector(fetchAllPosts), for: .valueChanged)

// 3. Assign the collection view’s refresh control
collectionView.refreshControl = refreshControl

// 4. Stop refreshing after the network call is complete
refreshControl.endRefreshing()
```

**Once you are done, stage, commit, and push to GitHub.**

## Part IV: Creating a Post

***

**Your task is to send a POST request using Alamofire to add a post to the backend.**

A good rule of thumb is to always use Postman before writing the code.

1. Add a new request to your collection with a POST method
2. Enter the URL <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/create/`</mark>.
3. Click on the <mark style="color:red;">`Body`</mark> tab, select <mark style="color:red;">`raw`</mark>, and change the blue dropdown from “Text” to <mark style="color:red;">`JSON`</mark>
4. This request expects the following body:

```swift
{
    "message": "<Enter some message here>"
}
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FYndwBChiShY3xHARA3d0%2FScreenshot%202025-04-15%20at%2010.32.00%E2%80%AFAM.png?alt=media&amp;token=99dc5755-3eda-499c-a607-84c96fdad218" alt=""><figcaption></figcaption></figure>

If successful, the server returns a 201 status code with the above JSON data representing the post that was just created. **You do not need to do anything with this information for this assignment, but it is a common practice for the backend to return this data.** If you fetch all posts again, either through Postman or your app, you should see the new post that you created.

Similar to Part III, you will integrate this network call within your app. Follow these steps:

1. Create a function in <mark style="color:red;">`NetworkManager`</mark> that uses Alamofire to make the call. Remember that this is a POST request with a request body parameter called <mark style="color:red;">`message`</mark>. Proper error handling is highly recommended!
2. Call this function inside of <mark style="color:red;">`CreatePostCollectionViewCell.createPost`</mark>. There should be a <mark style="color:red;">`TODO`</mark> comment. As a hint, there is a text field in this class that you will need to use.
3. (Optional) If the call is successful, clear the the textfield. You can pass <mark style="color:red;">`true`</mark> to the callback if successful or <mark style="color:red;">`false`</mark> otherwise.
4. Run the app and try to create a post. For the scope of this assignment, you do not need to have the collection view updated as soon as you create the post. However, refreshing the collection view should contain the new post.

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Liking a Post

***

**Your task is to send a POST request using Alamofire to&#x20;*****like*****&#x20;a post.**

Before you integrate networking, configure the like button to be filled with the color ruby if the post’s liked users contains your NetID.

Just like before, use Postman to test the backend call.

1. Add a new request to your collection with a POST method
2. Enter the URL: <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/{postId}/like/`</mark> <mark style="color:red;"></mark><mark style="color:red;">(EDIT 4/14 23:23: You'll have to pass in the post ID as a parameter of the URL)</mark>
3. Click on the <mark style="color:red;">`Body`</mark> tab, select <mark style="color:red;">`raw`</mark>, and change the blue dropdown from “Text” to <mark style="color:red;">`JSON`</mark>
4. This request expects the following body:

```swift
{
    "netId": "<Enter your NetID>"
}
```

**You will use your NetID (all lowercase).** If the call is successful, you should receive the updated post.

There are many ways you can go about this. My recommendation for you is to pass a boolean to the callback to indicate whether or not the call was successful, similar to Part IV. If the call is successful, make the like button filled and increment the count by 1. Additionally, you should only be able to tap on the button if the button is not already filled red, so you will need to wrap your network request in an if statement.

You may notice that there is a delay before the button turns red when tapping on it. In apps like Instagram, usually the UI changes even if the API call fails. However, for the sake of simplicity and grading, we want the button to only turn red if the network call succeeds.

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Unlike a Post (+1 pt)

**Your task is to send a POST request using Alamofire to&#x20;*****unlike*****&#x20;a post.** This may seem similar to Part V, but it requires some additional frontend logic. When grading for this, we will unlike a post and refresh to make sure the backend is actually updated. If you try to unlike a post in which the given NetID does not already like it, you will get an error. You can test this out on Postman. The URL is <mark style="color:red;">`https://ios-course-backend.cornellappdev.com/api/posts/{postId}/unlike/`</mark>. <mark style="color:red;">(EDIT 4/14 23:23: You'll have to pass in the post ID as a parameter of the URL)</mark>

### 2: Sort by Top/New Posts (+1)

If you take a look at the [Figma](https://www.figma.com/file/kzgaF8pBYQLgjyWDyIzKSh/A3%3A-ChatDev?type=design\&node-id=1%3A1199\&mode=design\&t=zCm1ZPIQJyLxedca-1) file, you should see a design containing the text “Top” and “New”. **Your task here is to sort the posts by the # of likes (top) and the most recent (new)**. For example, if the selected tab is “Top”, the post with the most likes will be at the top. If the selected tab is “New”, the most recent post will be at the top. Make sure that the color of the tab changes depending on what is selected.

### 3: Like Animation (+1)

**Your task here is to add some animation when liking a post**. You could add a scaling animation similar to most social media apps or do some other cool animation. As long as there is some animation when liking a post, you will get full credit.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a3.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
```

6. Fill out this [feedback survey](https://forms.gle/3vZUFcVXcDfZFXVS7) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# A4: ChefOS

Original Author: Vin Bui

{% hint style="danger" %}
**Midpoint Due: Monday November 17, 2025 11:59 pm**\
**Final Due: Tuesday November 25, 2025 11:59 pm**
{% endhint %}

{% hint style="info" %}
**If you are not enrolled in the course but would still like to complete the assignments, you can download the ZIP file below (note that you will not be able to enter any Git commands). Otherwise, we will create a repository for you.**
{% endhint %}

{% file src="/files/Zb0Y6PB0DxgTG0RuWZ84" %}

## Overview

***

In this assignment, you will be creating a recipe book app. You will be able to fetch recipes from a server, filter by category, and save them for later!

## Learning Objectives

***

**Developer Skills**

* **How to organize your project directory**
* How to use Postman to test HTTP requests
* How to read code written by other developers
* How to read data received from the backend to structure frontend code
* How to work with Git and GitHub for version control
* How to read documentation from outside resources
* How to format and structure your code to follow MVC design pattern
* How to follow common styling conventions used in industry
* How to implement designs created on Figma

**Course Material**

* **How to set up multiple collection views and communicate between them**
* **How to filter data using higher order functions**
* **How to save data locally using&#x20;**<mark style="color:red;">**`UserDefaults`**</mark>
* How to represent lists of data using a <mark style="color:red;">`UICollectionView`</mark> and a <mark style="color:red;">`UICollectionViewCell`</mark>
* How to send GET requests to a backend API using Alamofire
* How to write callbacks (completion handlers) to handle asynchronous calls
* How to create a <mark style="color:red;">`NetworkManager`</mark> singleton class to contain network calls
* How to decode a JSON using a <mark style="color:red;">`JSONDecoder`</mark> in Swift
* How to handle errors with networking calls

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/sp25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.** If you are using an external resource such as Stack Overflow, keep in mind that we are using UIKit with Swift 5. If you see anything with @IBOutlet or any weird syntax, then you are most likely looking at a different version.

## Grading Rubric

***

{% hint style="info" %}
**Due to the shrinking of the course, the features implemented up to the midpoint submission will be worth more than after.**
{% endhint %}

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Recipe CollectionView**</mark>                                | <mark style="color:blue;">**\_ / 4**</mark>        |
| ------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| UI: Name, Image, Time, Rating                                                                     | \_ / 2                                             |
| UI: 2 columns, Dynamic number of cells (adding a new item to the array creates a new item/cell)   | \_ / 1                                             |
| UI: Each cell is unique and represents a different Recipe                                         | \_ / 1                                             |
| <mark style="color:blue;">**PART II: Detailed Recipe View**</mark>                                | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Image                                                                                         | \_ / 1                                             |
| UI: Name and Description                                                                          | \_ / 1                                             |
| F: Tapping on a Recipe cell pushes a detailed view                                                | \_ / 1                                             |
| <mark style="color:blue;">**PART III: Filtering**</mark>                                          | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Collection view for filters WITH horizontal scrolling                                         | \_ / 1                                             |
| UI: Selected filter is highlighted (separate from functionality)                                  | \_ / 1                                             |
| F: Tapping on a filter filters the recipe data (one at at time; stacking filters is extra credit) | \_ / 1                                             |
| <mark style="color:blue;">**PART IV: Fetching Recipes**</mark>                                    | <mark style="color:blue;">**\_ / 1**</mark>        |
| F: GET Request to Fetch Recipes                                                                   | \_ / 1                                             |
| <mark style="color:blue;">**PART V: Bookmark Recipes**</mark>                                     | <mark style="color:blue;">**\_ / 2**</mark>        |
| F: Bookmarking from the detailed view updates the collection view using delegation                | \_ / 1                                             |
| F: Saved recipes are stored locally via UserDefaults (restart app to check)                       | \_ / 1                                             |
| <mark style="color:blue;">**OTHER**</mark>                                                        | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                                   | \_ / 1                                             |
| Styling: <mark style="color:red;">`viewDidLoad`</mark> calls helper functions                     | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                                    | <mark style="color:green;">**\_ / 15**</mark>      |
| EC: Custom back button                                                                            | + 1                                                |
| EC: Stacking filters                                                                              | + 1                                                |
| EC: Nesting collection views                                                                      | + 1                                                |
| EC: Separate bookmark page                                                                        | + 2                                                |
| Deduction: Crash Tax                                                                              | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                                 | <mark style="color:green;">**\_ / 15 (+5)**</mark> |

## Getting Started

***

### Using Postman

You are encouraged to use [Postman](https://www.postman.com/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

### Using Figma

Similar to A2 and A3, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Cloning the Repository

Navigate to a folder on your device where you will keep all of your assignments. You can navigate to the folder using <mark style="color:red;">`cd`</mark> in Terminal.

Clone the repository on GitHub:

* Replace **NETID** with your NetID
* Replace **SEM** with the semester (such as <mark style="color:red;">`fa23`</mark> or <mark style="color:red;">`sp24`</mark>)

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
# Ex: git clone git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a4.git
```

If you have a partner, replace **NETID1** and **NETID2**. Try changing the order if the former does not work.

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID1-NETID2-a4.git
```

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

### Opening the Project

Navigate to the repository located on your local computer drive. Inside of the folder <mark style="color:red;">`NETID-a4`</mark> should contain an Xcode project called <mark style="color:red;">`A4.xcodeproj`</mark>. Open up the project.

### Locating the Source Code

Once you have the project opened, on the left side of the screen you should see the Navigator which contains all of the folders and files in the directory. If not, press <mark style="color:red;">`CMD + 0`</mark> (that’s a zero) on your keyboard. You may notice that there is less starter code than in A2 and A3. As developers, directory organization is very important! Look at A2/A3 to see how we organized our directory. **Remember to use those&#x20;**<mark style="color:red;">**`// MARK`**</mark>**&#x20;comments!**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F7SqkVJrERoPKI3c3F7ta%2FScreenshot%202023-10-31%20at%208.56.04%E2%80%AFPM.png?alt=media&amp;token=64f9d82f-8f8b-476f-be56-11345bef5ae8" alt="" width="261"><figcaption></figcaption></figure>

## Assignment Files

***

As mentioned earlier, there is less starter code. You will be required to create your own files and organize them properly. However, there are only two files provided for you.

### `UIColor+Extension.swift`

In contrast to A3, you are free to edit this file if you want to change the colors. This file contains colors that are featured in the [Figma](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1) design. To use the colors, simply type <mark style="color:red;">`UIColor.a4.<color_name>`</mark>. It is good practice to implement the design system before starting any project, making it very easy to use throughout the entire project. **Look over this file to understand how it works and keep note of the colors available for you to use.**

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FqhBkjYdK1XhVX3TWZgdN%2FUntitled.png?alt=media&amp;token=2191df5f-4153-4efc-86c4-f5ca218d87fe" alt="" width="219"><figcaption><p>From the Figma Design</p></figcaption></figure>

### `UIFont+Extension.swift`

This extension allows you to use the SF Pro Rounded font which is used in the Figma design. To use this font, simply add <mark style="color:red;">`.rounded`</mark> to the end of the <mark style="color:red;">`UIFont`</mark>. For example, you can do <mark style="color:red;">`.systemFont(ofSize: 12, weight: .semibold).rounded`</mark>.

## External Libraries

***

The starter code should have Alamofire, SnapKit, and SDWebImage installed. To use these libraries, use the <mark style="color:red;">`import`</mark> statement at the top of the file. You are not required to use SnapKit, but it would save you a lot of time learning how to use it over NSLayout.

{% hint style="info" %}
**Source: All of the recipes used in this assignment are from** [**allrecipes.com**](https://www.allrecipes.com/)**.**
{% endhint %}

## Part I: Recipe CollectionView

***

**Your task is to create a UICollectionView to display the recipes.** We will not guide you as much as we did with the other assignments, but keep the following in mind:

* You are not required to implement the bookmark icon until Part V, but you are free to do so now.
* You will not be implementing the filters until Part III.
* You will need to create dummy data. For the sake of time and convenience, I have them written out for you in this [Pastebin](https://pastebin.com/KPrsHR38). Make sure your model aligns with the given dummy data since the JSON you will be fetching from follows this format.
* We want the collection view to be scrollable even when not full. Simply set <mark style="color:red;">`alwaysBounceVertical = true`</mark>.
* You do not have to worry about dynamic cell size. Set the text labels’ line limit to <mark style="color:red;">`2`</mark> lines and the height of the cell to around <mark style="color:red;">`216`</mark>. The width, however, will depend on the size of the screen. Remember, we want to have two columns. *Hint: We can multiply/divide the screen’s width by a certain factor.*
* **Do not save recipe images in the Assets catalog. We will be using SDWebImage to download images from URLs.**

{% hint style="danger" %}
**While creating this assignment, I ran into a bug with the collection view. Make sure to set the collection view’s&#x20;**<mark style="color:red;">**`alwaysBounceVertical`**</mark>**&#x20;property to&#x20;**<mark style="color:red;">**`true`**</mark>**.**
{% endhint %}

### Using SDWebImage

There are many ways to download images in Swift, but the easiest way in my opinion is using SDWebImage. Using this library is very simple.

1. Import the library using <mark style="color:red;">`import SDWebImage`</mark> at the top of the file.
2. Given a <mark style="color:red;">`UIImageView`</mark>, simply use the <mark style="color:red;">`.sd_setImage(with: <URL>)`</mark> function. Here is an example:

```swift
// Given a UIImageView called `imageView` and a Recipe object with
// the property `imageUrl`
imageView.sd_setImage(with: URL(string: recipe.imageUrl))
```

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Detailed Recipe View

***

**Your task is to create a view controller representing a detailed recipe view.** You will push this view controller when tapping on the collection view cell. This detailed view will be unique to the recipe.

This is very straight-forward and there aren’t any tricks. Just make sure that your <mark style="color:red;">`Recipe`</mark> model aligns with the given dummy data in this [Pastebin](https://pastebin.com/KPrsHR38) (the data type of your fields matter). Remember to use SDWebImage to download the images and to implement the correct function to handle tapping on a cell. You also need to figure out which labels will have multiple lines. Click on every single cell to check for edge cases.

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Filtering

***

**Your task is to create a horizontally scrolling collection view that represents the filter pills as well as adding filtering functionality.**

Here is a quick demo of what we’re expecting:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FjSiKmRla1i22MGjXdrUv%2Fa4_part3.gif?alt=media&amp;token=3acc89cf-2c0d-48b7-9b69-18f748ae33f1" alt="" width="221"><figcaption></figcaption></figure>

### Handling Multiple Collection Views

The tricky part to this task is that there are now two collection views inside of this view controller. Since it’s not possible to create multiple <mark style="color:red;">`cellForItemAt`</mark> functions, for example, then you need to handle the logic within the function itself. You can do this with an <mark style="color:red;">`if`</mark> statement and checking to see if the parameter <mark style="color:red;">`collectionView`</mark> is equal to the collection view property.

```swift
if collectionView == collectionViewOne {
    // Do something here for collectionViewOne
} else if collectionView == collectionViewTwo {
    // Do something here for collectionViewTwo
}
```

### Filter Collection View

* You want the collection view to span over the entire screen’s width so the leading and trailing anchors need to equal to the parent view. To add an inset to the collection view’s content, you can configure the <mark style="color:red;">`contentInset`</mark> property.
* There are 4 filters: All, Beginner, Intermediate, and Advanced. You can create an array of strings as the data model and use the string to configure the collection view cell which you can use a <mark style="color:red;">`UIButton`</mark> to represent.
* If you want, you can disable the scroll indicator for a cleaner scrolling view.
* You ***do not*** have to handle dynamic cell width. A height of <mark style="color:red;">`32`</mark> and width of <mark style="color:red;">`116`</mark> should work.
* The filter collection view ***does not*** have to scroll vertically with the recipe collection view. This requires nesting collection views inside each other which is a very tedious process. You can have the recipe collection view cut off like this if scrolled:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FtOief8CcHvJDOlp1j9fw%2FUntitled.png?alt=media&amp;token=8c750550-7257-45cf-ada8-3b49a3c8382b" alt="" width="306"><figcaption></figcaption></figure>

### Filtering Logic

* You ***do not*** need to handle filter stacking. This is somewhat advanced so we will leave that for extra credit.
* There are many ways to determine if a cell is selected, so I will leave this up to you to decide. Make sure that the currently selected tab is highlighted with a white text color. If you are lost and have no idea where to start, feel free to ask on Ed Discussion or come to office hours.
* There are also many ways to change the value of the selected filter. You can configure <mark style="color:red;">`didSelectItemAt`</mark> or use delegation to communicate from the cell’s button to the view controller.
* To filter the array of recipes, you can use the <mark style="color:red;">`filter`</mark> higher order function. As a hint, you should have two properties containing the array of recipes: one for all recipes and another for filtered recipes.

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **This is the stopping point for the midpoint submission. We will grade you for completion based on your GitHub commit history.**

**Please submit a `submission.txt` file on CMSX similar to how you did it for your A3 midpoint submission. You can download the outline below and see an example submission right under it.**
{% endhint %}

{% file src="/files/u2TNyw6cWJJ3Xi2IH5uB" %}

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
Notes: I was having trouble with setting up the UICollectionViewDelegateFlowLayout...
```

## Part IV: Fetching Recipes

***

**Your task is to create a GET request to fetch all recipes from this API:**

```
https://api.jsonbin.io/v3/b/64d033f18e4aa6225ecbcf9f?meta=false
```

You can use Postman to test the HTTP request. You will need to create a <mark style="color:red;">`NetworkManager`</mark> class with a <mark style="color:red;">`shared`</mark> singleton instance. You will be using Alamofire so make sure to import this library. See the lecture, textbook, or A3 for reference.

Error handling is not required but is nice to have. You will know if you integrated it correctly if there are more recipes than the dummy data. As a reminder, the JSON uses snake\_case but Swift uses camelCase.

Networking is one of the most important but difficult concepts to learn and implement. We want you to get as much practice as you can to prepare you for the Hack Challenge. If you are confused, please create a post on Ed Discussion or visit office hours.

{% hint style="danger" %}
**Make sure that filtering still works properly!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Bookmark Recipes

***

**Your task is to implement bookmarking functionality for these recipes.** You will need a way to keep track of bookmarked recipes to save them locally via UserDefaults.

* First, figure out what data structure you will use to keep track of bookmarked recipes. Then, think of a key that you will use to access through UserDefaults.
* Recipes that are bookmarked should have a bookmark icon in their cell. See the Figma for UI details.
* You will need to create a <mark style="color:red;">`UIBarButtonItem`</mark> to represent the bookmark button. This button will be in the detailed recipe view on the top right corner. If the recipe is already saved, the bookmark button will be filled and tapping on it will remove it from the saved recipes.
* The bookmark icon should change immediately on press. You will also need to use delegation to reload the recipe collection view so that the cells will be properly updated. Remember to use a weak reference!
* All saved recipes should be stored locally. You can check by restarting the app. If the saved recipes do not reset, then you are good to go.

Here is a quick demo of what we are looking for:

{% file src="/files/OJ2hEDPeJJYPDanjBwOq" %}

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Custom Back Button (+1 pt)

**Your task is to create a custom back button.** The [Figma](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1) has a possible design for this, but you are free to use any button you like. This should be a freebie if you finished the task in Part V.

### 2: Stacking Filters (+1)

Right now, you can only select one filter at a time. **Your task is to allow for filter stacking**. All selected filters should be highlighted and the collection view should contain all selected filters.

### 3: Nesting CollectionViews (+1)

Right now, you have two separate collection views: one for the filters and the other for the recipes. Because these collection views have different scrolling directions, if we wanted to make them both scrollable vertically, then we will have to nest collection views. **Your task here is to nest collection views so that the filters scroll with the recipes.** In other words, if I scroll up, the filters should scroll up as well while maintaining its horizontal scrolling attribute.

### 4: Separate Bookmark Page (+2)

**Your task here is to create a page listing out all bookmarked recipes.** The design is up to your creativity, but there needs to be some way to push the detailed recipe view where you can then bookmark/unbookmark. You may also need to use delegation to update this bookmark list, similar to what you did in Part V.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
+1 : ____
+2 : ____
```

6. Fill out this [feedback survey](https://forms.gle/rHSz5t8By1rHocAU8) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# A4: ChefOS - SwiftUI

Original project authored by Vin Bui, adapted to SwiftUI by Daniel Chuang

{% hint style="danger" %}
**Midpoint Due: Monday November 17, 2025 11:59 pm**\
**Final Due: Tuesday November 25, 2025 11:59 pm**
{% endhint %}

{% hint style="info" %}
**For this assignment, please make a blank SwiftUI project. We're starting from scratch! Make sure to submit via your Cornell repo though, we will set up an empty one for you.**
{% endhint %}

## Overview

***

In this assignment, you will be creating a recipe book app. You will be able to fetch recipes from a server, filter by category, and save them for later!

## Learning Objectives

***

**Developer Skills**

* **How to organize your project directory**
* How to use Postman to test HTTP requests
* How to read data received from the backend to structure frontend code
* How to work with Git and GitHub for version control
* How to read documentation from outside resources
* How to format and structure your code to follow MVC design pattern
* How to follow common styling conventions used in industry
* How to implement designs created on Figma

**Course Material**

* **How to set up multiple collection views and communicate between them in SwiftUI**
* **How to filter data using higher order functions**
* **How to save data locally using&#x20;**<mark style="color:red;">**`UserDefaults`**</mark>
* How to represent lists of data using a <mark style="color:red;">`UICollectionView`</mark> and a <mark style="color:red;">`UICollectionViewCell`</mark>
* How to send GET requests to a backend API using Alamofire
* How to write callbacks (completion handlers) to handle asynchronous calls
* How to create a <mark style="color:red;">`NetworkManager`</mark> singleton class to contain network calls
* How to decode a JSON using a <mark style="color:red;">`JSONDecoder`</mark> in Swift
* How to handle errors with networking calls

## Academic Integrity

***

As with any other course at Cornell, the Code of Academic Integrity will be enforced in this class. All University-standard Academic Integrity guidelines should be followed. This includes proper attribution of any resources found online, including anything that may be open-sourced by AppDev. The University guidelines for Academic Integrity can be found [here](https://theuniversityfaculty.cornell.edu/academic-integrity/).

**This assignment can be done with ONE partner.** You are also free to come to the instructors or any course staff for help. Programming forums like *Stack Overflow* or *Hacking with Swift* are allowed as long as you understand the code and are not copying it exactly. **The majority of code (excluding external libraries) must be written by you or your partner.** Code written through AI means such as ChatGPT is **NOT ALLOWED**. However, you may use these resources for assistance, although we highly encourage consulting Ed Discussion or office hours instead.

## Getting Help

***

If you are stuck or need a bit of guidance, please make a post on Ed Discussion or visit [office hours](/resources/archived-past-semesters/sp25/logistics/office-hours). **Please do not publicly post your code on Ed Discussion.**

## Grading Rubric

***

{% hint style="info" %}
**Due to the shrinking of the course, the features implemented up to the midpoint submission will be worth more than after.**
{% endhint %}

The feedback form link is located in the [Submission](#submission) section of this handout.

* <mark style="color:red;">`UI`</mark>: implements the user interface
* <mark style="color:red;">`F`</mark>: implements the functionality
* <mark style="color:red;">`EC`</mark>: extra credit

| <mark style="color:blue;">**PART I: Recipe CollectionView**</mark>                                | <mark style="color:blue;">**\_ / 4**</mark>        |
| ------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| UI: Name, Image, Time, Rating                                                                     | \_ / 2                                             |
| UI: 2 columns, Dynamic number of cells (adding a new item to the array creates a new item/cell)   | \_ / 1                                             |
| UI: Each cell is unique and represents a different Recipe                                         | \_ / 1                                             |
| <mark style="color:blue;">**PART II: Detailed Recipe View**</mark>                                | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Image                                                                                         | \_ / 1                                             |
| UI: Name and Description                                                                          | \_ / 1                                             |
| F: Tapping on a Recipe cell pushes a detailed view                                                | \_ / 1                                             |
| <mark style="color:blue;">**PART III: Filtering**</mark>                                          | <mark style="color:blue;">**\_ / 3**</mark>        |
| UI: Collection view for filters WITH horizontal scrolling                                         | \_ / 1                                             |
| UI: Selected filter is highlighted (separate from functionality)                                  | \_ / 1                                             |
| F: Tapping on a filter filters the recipe data (one at at time; stacking filters is extra credit) | \_ / 1                                             |
| <mark style="color:blue;">**PART IV: Fetching Recipes**</mark>                                    | <mark style="color:blue;">**\_ / 1**</mark>        |
| F: GET Request to Fetch Recipes                                                                   | \_ / 1                                             |
| <mark style="color:blue;">**PART V: Bookmark Recipes**</mark>                                     | <mark style="color:blue;">**\_ / 2**</mark>        |
| F: Bookmarking from the detailed view updates the collection view using delegation                | \_ / 1                                             |
| F: Saved recipes are stored locally via UserDefaults (restart app to check)                       | \_ / 1                                             |
| <mark style="color:blue;">**OTHER**</mark>                                                        | <mark style="color:blue;">**\_ / 2**</mark>        |
| Feedback Survey                                                                                   | \_ / 1                                             |
| <mark style="color:red;">`onAppear`</mark> calls networking functions                             | \_ / 1                                             |
| <mark style="color:green;">**SUBTOTAL**</mark>                                                    | <mark style="color:green;">**\_ / 15**</mark>      |
| EC: Custom back button                                                                            | + 1                                                |
| EC: Stacking filters                                                                              | + 1                                                |
| EC: Nesting collection views                                                                      | + 1                                                |
| EC: Separate bookmark page                                                                        | + 2                                                |
| Deduction: Crash Tax                                                                              | -1 point                                           |
| <mark style="color:green;">**GRAND TOTAL**</mark>                                                 | <mark style="color:green;">**\_ / 15 (+5)**</mark> |

## Getting Started

***

### Using Postman

You are encouraged to use [Postman](https://www.postman.com/) to test out HTTP requests. Please take a look at the [Postman guide](/resources/tool-guides/postman).

### Using Figma

Similar to A2 and A3, we will be using Figma for the design sketches. You can find the link to the Figma [here](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1). If you do not have an account, you can create one under your Cornell email. If you need a refresher, check out the [Figma guide](/resources/tool-guides/figma).

### Creating a new SwiftUI Project

Go to Xcode -> File -> New -> Project -> App -> \[MAKE SURE THAT Interface = SwiftUI] and just proceed from there via clicking Next and Create.

### Using Git

If you are having trouble understanding how we will be using Git in this course, please read the A1 handout under [Understanding Git and GitHub](broken://pages/hIeuzlyHR8Hw5Q4NtZF3#understanding-git-and-github) section, or visit office hours so we can assist you. As a reminder:

1. **Stage:** <mark style="color:red;">`git add .`</mark>
2. **Commit:** <mark style="color:red;">`git commit -m "YOUR MESSAGE HERE"`</mark>
3. **Push:** <mark style="color:red;">`git push`</mark>

### Pushing to the Repository

Navigate to a folder on your device where you will keep all of your assignments. You can navigate to the folder using <mark style="color:red;">`cd`</mark> in Terminal.

Clone the repository on GitHub:

* Replace **NETID** with your NetID
* Replace **SEM** with the semester (such as <mark style="color:red;">`fa23`</mark> or <mark style="color:red;">`sp24`</mark>)

```powershell
git init
git remote add origin git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
# Ex: git remote add origin git@github.coecis.cornell.edu:cs1998-601-fa23/vdb23-a4.git
git add .
git commit -m "Initial commit"
git push origin main
```

If you have a partner, replace **NETID1** and **NETID2**. Try changing the order if the former does not work.

```powershell
git clone git@github.coecis.cornell.edu:cs1998-601-SEM/NETID1-NETID2-a4.git
```

If you are lost or getting any kind of error, create a post on Ed Discussion or come to office hours.

## Assignment Files

***

**Color File**

You may find the following code helpful to put into a <mark style="color:red;">`Color.swift`</mark> file, as it will allow for you to input the hex values of colors you have from Figma into Swift directly.

```swift
// Copy into a file called Color.swift
import SwiftUI

extension Color {
    init(hex: UInt, alpha: Double = 1) {
        self.init(
            .sRGB,
            red: Double((hex >> 16) & 0xff) / 255,
            green: Double((hex >> 08) & 0xff) / 255,
            blue: Double((hex >> 00) & 0xff) / 255,
            opacity: alpha
        )
    }
}
```

You will now be able to make colors via the following syntax. Note that the "0x" at the beginning is telling Swift that the proceeding values should be interpreted in hexadecimal base.

```swift
Color(hex: 0xFAFAFA)
```

## External Libraries

***

You will need to import Alamofire. Please import this via Cocoapods or SwiftPackageManager (SPM). You should be able to figure out how to install via Cocoapods via previous projects, but for SPM, here are the instructions!

1. XCode -> File -> Add Package Dependencies
2. Look up Alamofire -> Add Package
3. Click on the Project Settings Page (the very first icon in your file navigation bar, on the top left)
4. Click on General on the top bar of the newly opened project settings page
5. Scroll down to Frameworks, Libraries, and Embedded Content and add Alamofire.
6. You're ready to import Alamofire into your code and write some solid networking code!

{% hint style="info" %}
**Source: All of the recipes used in this assignment are from** [**allrecipes.com**](https://www.allrecipes.com/)**.**
{% endhint %}

## Part I: Recipe CollectionView

***

**Notice that on Figma, the screens are broken down into the different stages you need to implement.**

**Your first task is to create a "Collection View" to display the recipes.** We encourage using the textbook and the internet for syntax and modifier help! We will not guide you as much as we did with the other assignments, but here is a general blueprint for what to do:

1. Set up your Recipe struct and dummy data using data from this [Pastebin](https://pastebin.com/KPrsHR38) link. Make sure the struct's properties align with the Pastebin format!
2. Make a RecipeCell view in a new file called <mark style="color:red;">`RecipeCell.swift`</mark>
   1. Set up a preview if you'd like!
   2. Add a property to the view called <mark style="color:red;">`recipe`</mark> which should allow for you to input any recipe you want from your dummy data (so your string should be using recipe.\[property])
   3. Use an AsyncImage for putting in the recipe's image. Refer to Swift [documentation](https://developer.apple.com/documentation/swiftui/asyncimage) or the Ed [post](https://edstem.org/us/courses/75579/discussion/6551956) made by Daniel for a reference on how to do this.
3. Now, in ContentView, you'll want to set up a LazyVGrid in order to get the grid with 2 columns. Refer to the Swift [documentation](https://developer.apple.com/documentation/swiftui/lazyvgrid#:~:text=struct-,VerticalSmileys,-%3A%20View%20%7B) for this!&#x20;
   1. Unlike a normal VStack, we need to initialize columns and input that as a parameter, so make sure to do that
   2. After that, just write a ForEach inside of the LazyVGrid. You might need to make sure that your Recipe struct conforms to certain things before you can proceed with this, but XCode should tell you exactly what you need to do in this regard!
   3. Wrap your LazyVGrid with a ScrollView
4. Wrap your LazyVGrid + ScrollView component in a VStack, and add some text right above it in the VStack that says "ChefOS" just how the Figma has it (so the scroll only scrolls through the items, not the ChefOS title)
5. Make your your styling matches the Figma!

Side notes:

* You are not required to implement the bookmark icon until Part V, but you are free to do so now.
* You will not be implementing the filters until Part III.
* You do not have to worry about dynamic cell size. Set the text labels’ line limit to <mark style="color:red;">`2`</mark> lines and the height of the cell to around <mark style="color:red;">`216`</mark>. The width, however, will depend on the size of the screen. Remember, we want to have two columns. *Hint: We can multiply/divide the screen’s width by a certain factor.*
* **Do not save recipe images in the Assets catalog. You must use AsyncImage for displaying these images**

**Once you are done, stage, commit, and push to GitHub.**

## Part II: Detailed Recipe View

***

**Your task is to create a view controller representing a detailed recipe view.** You will push this view controller when tapping on the collection view cell. This detailed view will be unique to the recipe.

**Detailed Recipe Page**

This is very straight-forward and there aren’t any tricks. Make a new view called <mark style="color:red;">`RecipePage.swift`</mark>  and implement what you see on Figma. Make sure that recipe is a property of the view (like before) so that you can input the recipe you want as a parameter.&#x20;

Remember to use AsyncImage to download the images (feel free to copy and paste).

**Navigating to the Detailed Recipe Page**

This is super simple: first, wrap your ENTIRE ContentView in a NavigationView. Then, wrap each of your RecipeCells in the ForEach from before with NavigationLink, with a destination parameter of RecipePage(recipe: recipe). Feel free to refer back to SwiftUI II's lecture for a code snippet on this.

**Once you are done, stage, commit, and push to GitHub.**

## Part III: Filtering

***

**Your task is to create a horizontally scrolling collection view that represents the filter pills as well as adding filtering functionality.**

Here is a quick demo of what we’re expecting:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FjSiKmRla1i22MGjXdrUv%2Fa4_part3.gif?alt=media&amp;token=3acc89cf-2c0d-48b7-9b69-18f748ae33f1" alt="" width="221"><figcaption></figcaption></figure>

### Adding a Filter Collection View

In UIKit, this would be very difficult. Thankfully for you, you're coding in SwiftUI!

1. Make a selectedDifficulty property in ContentView and make a difficulties property in ContentView. Feel free to copy this in, as long as you understand why we will need the @State. Your default selectedDifficulty should be "All"

```swift
@State private var selectedDifficulty = "All"
private let difficulties: [String] = ["All", "Beginner", "Intermediate", "Advanced"]
```

2. Make a ScrollView containing a HStack between the ChefOS title and your recipe cells. The following shows how to allow for horizontal scrolling.

```swift
ScrollView(.horizontal, showsIndicators: false)
```

3. Make a ForEach in this HStack that looks through difficulties. You will need to set it up with the id parameter as well, since difficulties doesn't conform to identifiable.

```swift
ForEach(difficulties, id: \.self) {
    ...
}
```

4. Make these little capsule filter buttons inside the for each. One way to do this is by making each of them a Button. The code / function that the Button actually calls should be as easy as setting selectedDifficulty = Difficulty. Then, make the label a Text component that uses the .background() modifier with a capsule inside

<pre class="language-swift"><code class="lang-swift"><strong>Text(difficulty)
</strong><strong>// fonts and other modifiers
</strong><strong>.background(  Capsule()
</strong>                // more modifiers here for the Capsule specifically
                )
</code></pre>

### Filtering Logic

* You ***do not*** need to handle filter stacking. This is somewhat advanced so we will leave that for extra credit.
* There are many ways to determine if a cell is selected, so I will leave this up to you to decide. Make sure that the currently selected tab is highlighted with a white text color. If you are lost and have no idea where to start, feel free to ask on Ed Discussion or come to office hours.
* To filter the array of recipes, you can use the <mark style="color:red;">`filter`</mark> higher order function. Feel free to look up documentation for this, or just check out A1.

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **This is the stopping point for the midpoint submission. We will grade you for completion based on your GitHub commit history.**

**Please submit a `submission.txt` file on CMSX similar to how you did it for your A3 midpoint submission. You can download the outline below and see an example submission right under it.**
{% endhint %}

{% file src="/files/u2TNyw6cWJJ3Xi2IH5uB" %}

```
Name: Richie Sun
NetID: rs929
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a3.git
Notes: I was having trouble with setting up the UICollectionViewDelegateFlowLayout...
```

## Part IV: Fetching Recipes

***

**Your task is to create a GET request to fetch all recipes from this API:**

```
https://api.jsonbin.io/v3/b/64d033f18e4aa6225ecbcf9f?meta=false
```

You can use Postman to test the HTTP request. You will need to create a <mark style="color:red;">`NetworkManager`</mark> class with a <mark style="color:red;">`shared`</mark> singleton instance. You will be using Alamofire so make sure to import this library. See the lecture, textbook, or A3 for reference.

Error handling is not required but is nice to have. You will know if you integrated it correctly if there are more recipes than the dummy data. As a reminder, the JSON uses snake\_case but Swift uses camelCase.

Networking is one of the most important but difficult concepts to learn and implement. We want you to get as much practice as you can to prepare you for the Hack Challenge. If you are confused, please create a post on Ed Discussion or visit office hours.

**One caveat for SwiftUI is that you will need to call your fetch function (e.g. NetworkManager.fetchRecipes()) inside of a .onAppear modifier instead of viewDidLoad() like in UIKit**

You'll need to update your model for recipe to make ID into a UUID instead of a string, like this:&#x20;

```swift
var id: UUID?
```

Next, add coding keys into your recipe struct:

```swift
enum CodingKeys: String, CodingKey {
    case id, description, difficulty, imageUrl = "image_url", name, rating
}
```

Make two init functions for the recipe struct, one that is a default initializer for your dummy data, and another is a networking initializer for fetching. This is how you should do the networking initializer:

```swift
init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // Convert string ID to UUID
        if let idString = try container.decodeIfPresent(String.self, forKey: .id) {
            self.id = UUID(uuidString: idString)
        } else {
            self.id = nil
        }
        
        // Decode the rest of the properties normally
        self.description = try container.decode(String.self, forKey: .description)
        self.difficulty = try container.decode(String.self, forKey: .difficulty)
        self.imageUrl = try container.decode(String.self, forKey: .imageUrl)
        self.name = try container.decode(String.self, forKey: .name)
        self.rating = try container.decode(Float.self, forKey: .rating)
    }
```

**Finally, check that your networking is actually working. Make sure you see King Pao Chicken in your recipes in the app - that is a recipe that is in the endpoint but not the dummy data.**

{% hint style="danger" %}
**Make sure that filtering still works properly!**
{% endhint %}

**Once you are done, stage, commit, and push to GitHub.**

## Part V: Bookmark Recipes

***

**Your task is to implement bookmarking functionality for these recipes.** You will need a way to keep track of bookmarked recipes to save them locally via UserDefaults.

* First, figure out what data structure you will use to keep track of bookmarked recipes. Then, think of a key that you will use to access through UserDefaults. My recommendation is that you use a BookmarkManager that is a singleton instance.
* In your BookmarkManager, you'll want to include:
  * @Published bookmarkRecipesIds, which is a Set\<UUID> (set of UUIDs from your recipe ids).
  * saveBookmarks() function that uses UserDefaults.set
  * loadBookmarks() function that loads from UserDefaults
  * toggleBookmarks() function that adds or removes the ID from bookmarkRecipeIds, and calls saveBookmarks afterwards
  * an init function that calls loadBookmarks()
* Then, in ContentView, RecipePage, and RecipeCell, set up an @StateObject called bookmarkManager that is equal to BookmarkManager.shared. If you don't make it a State object and instead use BookmarkManager.shared directly, your bookmark icons will not be updated!
* You'll need to use the <mark style="color:red;">`.onAppear{}`</mark> modifier on your views to make sure that the view gets the data from BookmarkManager.
* Update the UI so that recipes that are bookmarked should have a bookmark icon in their cell. See the Figma for UI details. See the point below on how to get the bookmark icon.
  * You will need to create a <mark style="color:red;">`ToolbarItem`</mark> to represent the bookmark button in RecipePage. This button will be in the detailed recipe view on the top right corner. If the recipe is already saved, the bookmark button will be filled and tapping on it will remove it from the saved recipes. You can add this to your RecipePage by using the <mark style="color:red;">`.toolbar{}`</mark>modifier at the end of the RecipePage and putting ToolbarItem wrapping a Button wrapping <mark style="color:red;">`Image(systemName: "bookmark")`</mark>  or <mark style="color:red;">`Image(systemName: "bookmark.fill")`</mark>
  * Adding the bookmark to the RecipeCell should be as easy as just putting the bookmark image in an if statement.&#x20;
* All saved recipes should be stored locally. You can check by restarting the app. If the saved recipes do not reset, then you are good to go.

Here is a quick demo of what we are looking for:

{% file src="/files/OJ2hEDPeJJYPDanjBwOq" %}

**Once you are done, stage, commit, and push to GitHub.**

{% hint style="success" %}
✋🏻 **If you reach this point, you are done with the assignment. However, feel free to challenge yourself with the extra credit features.**
{% endhint %}

## Extra Credit

***

{% hint style="danger" %}
**Extra credit will only be given if the features are&#x20;*****fully*****&#x20;implemented. These are unordered and you can choose as many as you like.**
{% endhint %}

### 1: Custom Back Button (+1 pt)

**Your task is to create a custom back button.** The [Figma](https://www.figma.com/file/rCPlphpMKQZDLFIld6x0Cj/A4%3A-ChefOS?type=design\&node-id=1%3A23\&mode=design\&t=Ms5BRPZtDqKdt41m-1) has a possible design for this, but you are free to use any button you like. This should be a freebie if you finished the task in Part V.

### 2: Stacking Filters (+1)

Right now, you can only select one filter at a time. **Your task is to allow for filter stacking**. All selected filters should be highlighted and the collection view should contain all selected filters.

### 3: Nesting CollectionViews (+1)

Right now, you have two separate collection views: one for the filters and the other for the recipes. Because these collection views have different scrolling directions, if we wanted to make them both scrollable vertically, then we will have to nest collection views. **Your task here is to nest collection views so that the filters scroll with the recipes.** In other words, if I scroll up, the filters should scroll up as well while maintaining its horizontal scrolling attribute.

### 4: Separate Bookmark Page (+2)

**Your task here is to create a page listing out all bookmarked recipes.** The design is up to your creativity, but there needs to be some way to push the detailed recipe view where you can then bookmark/unbookmark. You may also need to use delegation to update this bookmark list, similar to what you did in Part V.

**Once you are done, stage, commit, and push to GitHub.**

## Submission

***

1. Double check that all of your files are properly pushed to GitHub.
2. Clone your repository into a **separate** folder on your local computer drive.
3. Run your project and make sure that your code does not crash and everything works as needed.
4. If you are satisfied, download this TXT file and fill it out. Make sure to use the **Clone SSH path**.

{% file src="/files/ZXdNMAmmGlCLk6zh3jDD" %}

5. Confirm that your <mark style="color:red;">`submission.txt`</mark> is formatted like the following and submit it on [CMS](https://cmsx.cs.cornell.edu/web/guest/).

```
Name: Vin Bui
NetID: vdb23
GitHub Repository: git@github.coecis.cornell.edu:cs1998-601-SEM/NETID-a4.git
Extra Credit:
+1 : ____
+1 : ____
+1 : ____
+1 : ____
+2 : ____
```

6. Fill out this [feedback survey](https://forms.gle/rHSz5t8By1rHocAU8) (worth 1 point).

{% hint style="info" %}
**If you are partnered, make sure to create a group on CMS and put both names in the&#x20;**<mark style="color:red;">**`submission.txt`**</mark>**&#x20;file. Both students must fill out the feedback survey to receive credit.**
{% endhint %}


# Hack Challenge

Original Author: Vin Bui

### What is the Hack Challenge?

The Hack Challenge is an AppDev courses tradition where students across our 4 courses (iOS, Android, Backend, and DPD) come together to create their own mobile app in 2 weeks.

### Why a Hack Challenge as a final project?

The purpose of our courses is to help our students gain skills that they can take into industry. The best way to develop these skills is by pursuing projects, especially with a team. Additionally, you will be able to put this on your portfolio, which will be an important factor when applying for internships.

### How will the groups be assigned? Where will we find teams?

This depends on the number of students we have across all courses. However, most teams typically consist of 2-3 frontend members, 1-2 backend members and 1 designer. We will do a team matching mixer when the Hack Challenge begins. During this mixer, you will meet students in other courses and form a team.

Each team will also have a frontend mentor as well as a backend mentor to provide any help if needed.

### How will grading work?

As a reminder, the Hack Challenge is worth 30% of your final grade. For iOS, you are required to have the following:

#### Midpoint Submission

* Multiple screens that you can navigate between **OR** at least one scrollable view.

**Final Submission**

* Multiple screens that you can navigate between.
* At least one scrollable view.
* Networking integration with a backend API.

**Note that you can use either UIKit or SwiftUI for the Hack Challenge.**

### Do we win prizes?

Yes! We have prizes and awards for the following:

* 🏆 Best Overall
* 💻 Best Backend
* 📱 Best UI
* 🎨 Most Creative

### Past Projects

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FtoEa9xN9a5U0ggPWNodg%2FUntitled.png?alt=media&amp;token=35eef5bd-d648-4e6d-b463-c42bf059ab1d" alt=""><figcaption></figcaption></figure>

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FRdWhPMw5Nr1djUBI7cBN%2FUntitled.png?alt=media&amp;token=3ac9ab08-d011-4b13-b132-d93aa46a10e2" alt=""><figcaption></figcaption></figure>


# FA23 Winners

Fall 2023

{% embed url="<https://www.youtube.com/watch?v=Vy4y2_1u8F0>" %}

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FBy0lOMtz3GKCHs2S3IJF%2FIMG_0459.JPG?alt=media&amp;token=4545a77f-b748-4ca3-a527-77bf70da9958" alt=""><figcaption><p>FA23 Winners</p></figcaption></figure>

## [Ithaca Traveller](https://www.youtube.com/watch?time_continue=13\&v=KVRTgewXVB8\&embeds_referring_euri=https%3A%2F%2Fdocs.google.com%2F\&embeds_referring_origin=https%3A%2F%2Fdocs.google.com\&source_ve_path=Mjg2NjY\&feature=emb_logo) - Best Backend

*Frank Dai, Qiandao Liu, James Tu, Huajie Zhong*

* Account login and registration (with profile image)
* MapKit integration with WeatherAPI
* Create a post and upload images
* Like and delete a post

<div><figure><img src="https://lh7-us.googleusercontent.com/d7f8TRJjQf6RhZKb7dUvaEfREql7vjmNvL8r95F2Dn9MuWOgLSZybUSlH10Cdw-uYzkZtVfq0Ipus6G0RLU4o9grb4kkycJhtcO6xRuzOLpa-Jk1ZUZBfRMoLLxklRLW_iI_uRCOW9nUF01NfXz5zp1QJA=s2048" alt="" width="375"><figcaption><p>Ithaca Traveller</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FBFfzpf2K2DMXFh4p3cIM%2FIMG_2522.jpeg?alt=media&amp;token=0b6ae1f7-9c94-406e-af1a-991c6e1bb7fa" alt="" width="375"><figcaption><p>Ithaca Traveller Team</p></figcaption></figure></div>

## [Latte Link](https://www.youtube.com/watch?v=h__QB02WURo) - Best UI

*Lucy Yang, Kyle Chu, Nicole Qiu, Nathan Chu, Mihili Herath*

A scheduling app that allows Cornell students to connect with coffee chatters and arrange coffee chats from a range of campus organizations.

* Simple yet effective user interface
* Easy on the eyes, not too much information at once
* Consistent design system - typography, colors, etc.
* Lots of explorations on Figma -> seems like everything was thought through pretty well

<div><figure><img src="https://lh7-us.googleusercontent.com/nTx4gL0p-Xc2P31VODMA4OgT2ltJlqtdI0hCrFAJ1ks2ZhKwbCXcbdfV0cUtNRQBki6iZ5qWZ1JHKUR_BGbaPEB5Tv6o5_UB8W81-gOyONFxGlNhpJaaMSpFxUKODD01MczYYcErhKWqwW6ryVz0ClRXgQ=s2048" alt="" width="375"><figcaption><p>Latte Link</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FuB9SuXFtzLqu2FiIxOdH%2FIMG_2523.jpeg?alt=media&amp;token=e28430c7-8e6b-465c-9f33-3f71e9f4773f" alt="" width="375"><figcaption><p>Latte Link Team</p></figcaption></figure></div>

## [ShelterSwipe](https://youtu.be/VuFvTb_Hp1Y?si=4C_xYoFBp6EmPFJh) - Most Creative

*Ilyssa Yan, Claire Wang, Cassidy Xu, Ronald Leung, Andrew Qian, Emily Silkina*

ShelterSwipe is an application where you can swipe through pets available for adoption at local shelters. We hope to match every potential pet-owner with their perfect animal to foster loving relationships and decrease the number of shelter animals.

* Very creative, cute, and wholesome idea
* Have never seen a swipe gesture used in a Hack Challenge before
* Animations when swiping was pretty sick

<div><figure><img src="https://lh7-us.googleusercontent.com/ESLVNjJ7aWT7j0kM1D5mZSd74gdKj848ivVxbNhl5ymH3xYbjGN0kVt-kUM-3hW6gu4XrFai683dylr-a0gBWoivAOtIjqtaaIzGL733NAfsrJ3t1NuW3djvcYDn1TT2fhGBd5562wnhG_zQ2L1CgevYUg=s2048" alt="" width="375"><figcaption><p>ShelterSwipe</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FD5xethWDoGPS2GLJMSnJ%2FIMG_2525.jpeg?alt=media&amp;token=74d6127e-4ec7-498e-93c3-23f4c8d8d452" alt="" width="375"><figcaption><p>ShelterSwipe Team</p></figcaption></figure></div>

## [truscoop](https://www.youtube.com/watch?v=rPHTixbiMac) - Best Overall

*Aidan Talreja, Peter Bidoshi, Daniel Chuang, Daniel Lee, Satya Datla*

AI news platform that determines the political meaning of the news article based on AI and user ratings.

* Summary generated with AI using NLP (natural language processing)
* Clean and slick/simple UI
* Can read articles within the app using WKWebView
* User ratings + ML generated ratings
* Share articles

<div><figure><img src="https://lh7-us.googleusercontent.com/o6i6PLlGOnyTJhS6Z7q4OiIEuM0b3vq5rNrQ-oLYzRIYbzYD3uomuNMUYQyPEPioC-qSsFK9ip-yapFxi5KXUG_VHRvFnZ80ifOcKQnhkq-igTYl4R63sND-f7OUx05u8jM0OxoXpPd6X5DcyJ4qNzeVjg=s2048" alt="" width="375"><figcaption><p>truscoop</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F5Gcmf2Xsauo3tgXmyRSq%2FIMG_2529.jpeg?alt=media&amp;token=c92a9aab-2813-45e8-964e-c0d78e3b1cf0" alt="" width="375"><figcaption><p>truscoop Team</p></figcaption></figure></div>


# Textbook

Recorded Lecture Videos from all ancestors:

* <https://www.youtube.com/@CornellAppDev/playlists>

How to use this textbook:

\[\[TODO]]


# Introduction

### About This Textbook

This textbook was originally created in Fall 2023 by Vin Bui. Over the course of time, more chapters have been added by other instructors (see contributors below). Since the content may become outdated, all chapters will contain date information of when it was written. The lecture videos are from Fall 2023, but feel free to check out other semesters on the [Cornell AppDev YouTube Channel](https://www.youtube.com/@CornellAppDev).

### Contributors

* Peter Bidoshi - *Instructor FA24, iOS Lead FA25*
* Richie Sun - *Instructor FA23/SP24, iOS Lead FA24*
* Vin Bui - *Instructor FA23, iOS Lead SP24*
* Tiffany Pan - *Instructor SP24, iOS Lead FA23*
* Reade Plunkett - *iOS Lead FA22/SP23*


# Git + GitHub

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1cERKTszq2NlvN0TKyYLdVDtqqtNeghSsBbVZdHe5QKk/edit?usp=sharing>" %}

### Lecture Video

{% embed url="<https://www.youtube.com/watch?index=2&list=PLjf6nsEcF5KPwKlfj8Lw5ZmimBs_1uoh0&v=0b0bTfmPj0k>" %}


# Git Installation

Fall 2023 | Vin Bui

### Cornell GitHub

You can access the Cornell GitHub enterprise [here](https://github.coecis.cornell.edu/).

### Install Git *(skip this step if you already have Git installed)*

To check to see if you have git installed, open **Terminal** and run `git --version`. A message will display if you already have it installed.

Follow the instructions [here](https://git-scm.com/download/mac) to install Git. I personally recommend using the **Homebrew** approach (requires you to install [Homebrew](https://brew.sh/)), but the Binary Installer should work as well.

### Generate SSH Key

1. Log in to your GitHub. Go to **Settings > SSH and GPG Keys**. Create a **New SSH key**.
2. Keep the page open. Open up **Terminal** and execute the two commands (replace **YOUR NAME** and **YOUR GITHUB EMAIL**):

   `git config --global user.name "YOUR NAME"`

   `git config --global user.email "YOUR GITHUB EMAIL"`
3. To generate an SSH Key, type `ssh-keygen -t ed25519 -C "YOUR GITHUB EMAIL"`
   1. Press ***enter*** when asked: **“Enter file in which to save the key”**.
   2. If asked “***\[…]*****/.ssh/id\_ed25519 already exists. Overwrite (y/n)?”**, type ***y*** and press ***enter***.
      1. **Note:** If you have previously configured SSH authentication for other services, overwriting your current key will likely cause you to lose access. You will need to reconfigure that service to authenticate using the *new* key in order to regain access.
   3. When asked: “**Enter passphrase (empty for no passphrase):**” just press ***enter***.
   4. When asked: “**Enter same passphrase again:**” just press ***enter***.
   5. Copy the generated key to your clipboard by typing `pbcopy < ~/.ssh/id_ed25519.pub`
4. Go back to the GitHub page from earlier. For the **Title** field, I recommend putting the name of your device (such as “Vin’s Macbook”). The key type is **Authentication Key**. Paste the generated key, then click **Add SSH key**.

### Configure SSH Agent

For **newer Macs** (12, Monterey/Ventura), run

`ssh-add --apple-use-keychain ~/.ssh/id_ed25519`

* If that command fails, try `ssh-add --apple-use-keychain ~/.ssh/id_rsa`

For **older Macs (11, Big Sur)**, run `ssh-add -K ~/.ssh/id_ed2551`

* If that command fails, try `ssh-add -K ~/.ssh/id_rsa`

### Cloning a repository (not needed for installation)

Open up **Terminal** and change the directory to wherever you want the repository files to be located. You can change the directory using the `cd` command.

* For example, if I want the repository files to be located in my Desktop, I would type `cd Desktop`

```powershell
(base) vinnie@dhcp-vl2041-37760 ~ % cd Desktop 
(base) vinnie@dhcp-vl2041-37760 Desktop %
```

To clone a repository, simply type `git clone <ENTER URL HERE>`


# Git Basics

Fall 2023 | Richie Sun

{% hint style="info" %}
**NOTE: Do not include angle brackets `< >`**
{% endhint %}

For more information, check out the [Git Documentation](https://git-scm.com/docs)

### **Sharing and Updating Repositories**

#### Git Pull

```bash
git pull <options> <repository>
```

Pulls changes from a remote repository into the current branch. If the current branch is behind the remote, then by default it will fast-forward the current branch to match the remote.

#### Git Status

```bash
git status
```

Displays paths that have changes between your local repository and the HEAD of the remote repository

#### Git Add

```bash
git add <changes to be staged>
```

This command updates the index using the current content found in the working tree, to prepare the content staged for the next commit. To stage all changes, use `git add .`

#### Git Commit

```bash
git commit -m <"Commit Title">
```

Create a new commit containing the current contents of the index and the given log message describing the changes.

#### Git Push

```bash
git push origin main
```

Updates the main branch of the remote repository based on the last local commit

### Branching and Merging

#### Git Branch:

```bash
git branch
```

Lists all existing branches; the current branch will be highlighted in green and marked with an asterisk

#### Git Checkout:

```bash
git checkout -b <"new branch name">

or

git checkout <existing branch name>
```


# Git+

Spring 2024 | Vin Bui

In the course, we only utilized some basic functionalities of Git such as staging, committing, and pushing. However, Git is a lot more powerful than that which we will discuss in this chapter.

### Branches

In the course, we mainly focused on one working branch known as `main` or `master`. When we made commits, we typically pushed them all into this one branch. When using this approach, collaborating with others was very difficult to do. If we did not fetch and pull from the main branch *before* working, we often had to deal with merge conflicts. Now, imagine if both developers are working on the same branch concurrently — a merge conflict is very likely to occur.

To avoid having to deal with merge conflicts every time we push to a branch, it’s often better to create separate branches when collaborating. To create a new branch and switch to it, use the following command:

```bash
git checkout -b "BRANCH_NAME"
```

### Pull Requests

**Pull requests** (also known as PRs) allows us to discuss changes that were pushed onto a branch before merging it to the base branch. Let’s look at the following scenario.

Suppose we have a branch called `A` whose base branch was from `main`. We push commits and make changes to the branch `A` like how we would if it was the `main` branch. When we are ready to push these changes to the `main` branch, we can submit a pull request through GitHub to merge `A` to `main`. This allows other developers to review our code before merging it to the `main` branch. If changes need to be made, then we can push new commits to our `A` branch and request a review again.

When should we create a PR? There is no right or wrong answer to this question. A PR can be a single line of code or even a thousand lines. A good rule of thumb is to create a PR if it’s important to the state

#### PR Chaining

A huge benefit of creating branches and making PRs is that we can chain them together. Say we have two features, A and B, that need to be implemented. We create a branch off of `main` and call it `A`. When we are done with making changes to `A`, we can create a PR to merge it to `main`.

While the PR is being reviewed, we may need to work on a new feature (in this case feature B). What we can do is create a branch `B` from `A` (not `main`). Now, if we create a PR, we want to create a PR to merge `B` to `A` instead of `main`. This way, we do not have to wait for the previous PR to be reviewed. Additionally, only the changes made between `A` and `B` will be shown in the PR, making it a lot easier to review.

When both PRs are approved, we want to merge in the following order:

1. Merge the PR from `A` to `main`.
2. Delete the `A` branch. The target branch in the second PR will automatically change once `A` gets deleted.
3. Merge the PR from `B` to `main`.

### Resolving Merge Conflicts

There are times when we may want to merge a working branch into another without creating a PR. For example, if we are on a branch `A`, we can simply merge `main` into our branch with the following command:

```bash
git merge main
```

When we run this command, we may receive merge conflicts. In other words, there are conflicts between the changes of the two branches, preventing the merge from happening. My preferred way to resolve merge conflicts is by using GitHub Desktop with Visual Studio Code (VSCode). VSCode will tell us where the conflict is occurring and allow us to resolve it quickly by clicking on “Accept Current Change” or “Accept Incoming Change”. See image below.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FANX5v8gAx5X673YvfOG8%2FUntitled.png?alt=media&amp;token=5a16f230-82d4-49aa-b7b6-29bf7633f83f" alt="" width="563"><figcaption><p>Resolving merge conflicts on VSCode.</p></figcaption></figure>

Of course, we can use our code editor to resolve the merge conflicts, but it can be difficult to locate where exactly the conflict is. GitHub Desktop works seamlessly with VSCode, allowing us to easily pinpoint and resolve the conflicts.

### Undoing a Commit

There are times when we may want to undo a commit, such as when we push sensitive information to a public repository. To undo a commit, we can simply use the following command

```bash
git reset HEAD~2
```

where 2 means move backwards by 2 commits (we can replace this with a number of our choice). Note that this is a soft reset meaning that staged files are not reverted back to a previous state. In other words, we keep the code that we wrote on our local repository.

We can then create a new commit and then **force push** our changes to the repository:

```bash
git push --force
```


# Swift Basics

### Table of Content

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/VEzF3tvLUQyPKJ53hu6u" %}
[Variables and Constants](/resources/textbook/swift-basics/variables-and-constants)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/aEmVwDXKjFHy0UK9XFUl" %}
[Data Types](/resources/textbook/swift-basics/data-types)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/fsiUWKICIjPowDkQWHmX" %}
[Operators](/resources/textbook/swift-basics/operators)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/mzFhswcNwzGeujInRNwA" %}
[Data Structures](/resources/textbook/swift-basics/data-structures)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/jqgTLo5YVdajEKvWReqs" %}
[Conditionals](/resources/textbook/swift-basics/conditionals)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/D71H4xl5ue4w8R84eAgJ" %}
[Loops](/resources/textbook/swift-basics/loops)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/dHUGuHLRVDhiUOtMNhRz" %}
[Functions](/resources/textbook/swift-basics/functions)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/dkrMAGcn1LgVIabfxDMn" %}
[Closures](/resources/textbook/swift-basics/closures)
{% endcontent-ref %}

{% content-ref url="/spaces/-Lwk7443W4ukbAF9S07e/pages/CjzmybKNV8UdhAzfKDKY" %}
[Optionals](/resources/textbook/swift-basics/optionals)
{% endcontent-ref %}

### Lecture Slides


# Variables and Constants

Fall 2023 | Vin Bui

In almost any program that we create, we will need to store data at some point. In Swift, we can store data in two ways: **variables** and **constants**. We can think of both variables and constants as a box holding some value inside. However, there is one key difference between these two. A variable can change its value whenever we want. On the contrary, a constant can hold a value once and can never be changed again.

It may seem pointless to have both variables and constants; however, there are many advantages. If Xcode knows that a value will never change, it will optimize our program to make it run faster. Another advantage is that if we were to make a mistake and change a value of a constant when we don’t need to, Xcode will tell us and our code will not compile.

### Variables

To create a variable, we use the `var` keyword.

```swift
var instructor = "Vin"
```

To change the value of the variable, we can simply do the following.

```swift
var instructor = "Vin"
instructor = "Richie"
```

Let’s try this in the Xcode playground.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FNWZ4FuknSNTNG8wL3Uci%2FUntitled.png?alt=media&amp;token=2d148abf-3280-4e59-a516-f45c78517d97" alt=""><figcaption></figcaption></figure>

Notice how we do not need to use the `var` keyword the second time. We should only use the `var` keyword if we are declaring a new variable. We can test this out in the Xcode playground.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FGJIIfNNqHfaaBYi1n1vs%2FUntitled.png?alt=media&amp;token=636b1726-9cad-4974-a5ae-267ec5f435cf" alt=""><figcaption></figcaption></figure>

### Constants

Now, what if we wanted to use a constant instead of a variable? All we would need to do is to use the `let` keyword instead.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FkES6yb5FZoahl7O9ZnMf%2FUntitled.png?alt=media&amp;token=44906ba5-29c1-4251-bb17-0673d6690b33" alt=""><figcaption></figcaption></figure>

As we can see, changing the `instructor` variable to a constant caused Xcode to get angry. The error message clearly informs us that we are attempting to change the value of a constant.

{% hint style="info" %}
**It is also convention to use camelCase with Swift!**
{% endhint %}


# Data Types

Fall 2023 | Vin Bui

In the variables and constants section above, we assigned a text to a variable. In Swift, this is called a **String** and is one of the most important types we will use. However, there are many more types of data that Swift handles. In the example earlier, let’s try to do the following:

```swift
var instructor
instructor = "Vin"
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FrJLYcAknK2s3YeKnj20k%2FUntitled.png?alt=media&amp;token=751597ef-5019-46df-a421-f9d8f12d0fc6" alt=""><figcaption></figcaption></figure>

There are two ways we can fix this error:

1. Initialize the variable with a value when we create it.
2. Tell Swift what data type the variable will hold on later.

We’ve already seen (1) earlier, but for (2) we can use **type annotations**.

### Type Annotations

```swift
var instructor: String
instructor = "Vin"
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FHCyVgXfOGbeNK6chjKy6%2FUntitled.png?alt=media&amp;token=5e286990-f388-4951-ace5-ac98ed03e097" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**As convention, we only put a space&#x20;*****after*****&#x20;the colon and not before!**
{% endhint %}

The key takeaway here is that Swift is a **statically typed** **language**, meaning that the type of every property, constant and variable that we declare needs to be specified at compile time. This is a good thing because it prevents us from putting anything inside of the “box”. This is known as **type safety**. Let’s demonstrate this by introducing a new data type **Int** (integer).

### Integer and Type Safety

```swift
var instructor: String
instructor = "Vin"

var year: Int
year = 2025
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FoNViABjCFvZ6UZxmmfyp%2FUntitled.png?alt=media&amp;token=ac71e7f3-d042-4cfd-ae43-5c3c86326121" alt=""><figcaption></figcaption></figure>

Everything works fine, but what if we were to swap the values of `instructor` and `year`?

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Ft4iqdAL4w2r5eiIHrb6J%2FUntitled.png?alt=media&amp;token=f635f919-6fea-470b-8058-cfbfe2e59c1e" alt=""><figcaption></figcaption></figure>

Our code no longer compiles because we tried assigning a value whose type does not match the type of the variable at the time it was created.

### Float and Double

We can store decimal numbers by using a **Float** and **Double**. The difference between these two is that a Double has twice the accuracy of a Float, and hence takes up more storage.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FgHN2VxuR4xNHSx9BwZGI%2FUntitled.png?alt=media&amp;token=2d939a3c-0be2-4d1d-99fe-66ecebe264e3" alt=""><figcaption></figcaption></figure>

### Boolean

A **Bool** (boolean) in Swift is a data type that can hold one of two values: `true` or `false`.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Ft9fwuL3YKt5FKEed8qX9%2FUntitled.png?alt=media&amp;token=51de3e24-eafc-4c0a-a2dd-80228f640ba0" alt=""><figcaption></figcaption></figure>

### Type Inferencing

Earlier when we assigned an initial value to a variable,

```swift
var instructor = "Vin"
```

Swift automatically **infers** what data type the variable will hold. This is known as **type inferencing**. We could also specify a data type and provide an initial value at the same time:

```swift
var instructor: String = "Vin"
```

Most of the time, we will not be using type annotations and prefer having Swift infer our types. However, there are times when type annotation should be used. This will come with practice and from seeing how we write our code.


# Operators

Fall 2023 | Vin Bui

We have seen the four basic math operations in elementary school: addition, subtraction, multiplication, and division. In Swift, we can use operators to perform these operations.

### Basic Operators

```swift
var a = 0
a = a + 10
a = a - 5
a = a * a
a = a / 10
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fh8QnGPO1xTJ29kR4O6DN%2FUntitled.png?alt=media&amp;token=4a7a8f1a-b9d3-4dce-b8c3-98e18cf8b5cb" alt=""><figcaption></figcaption></figure>

The following lines are equivalent:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FrFL9F6yFtHOGkwBztG44%2FUntitled.png?alt=media&amp;token=a534677b-73d8-4704-98b8-ed72ce0ac47f" alt=""><figcaption></figcaption></figure>

These operators are self-explanatory; however, if we were to take a closer look at the the line `a = a / 10` we can notice that the output is `2` instead of `2.5`. The reason for this is because the type of `a` is an `Int`. If we were to perform these operations on `a`, then we must also use an `Int`.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fs2h00ZeCKyOGrEA7MtZ8%2FUntitled.png?alt=media&amp;token=7545d270-f7f5-4334-b845-d56e7d144e26" alt=""><figcaption></figcaption></figure>

Then, how do we get the value `2.5`? Because the type of `a` is an `Int`, then we must introduce a new variable of type `Double` or `Float` since we cannot change the type of a variable once initialized. We would also need to make sure that the values in which we apply these operators on must also be a `Double` or `Float`.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fh3XTdb4MBVRzWzLJsl3q%2FUntitled.png?alt=media&amp;token=6b7d119a-931f-47d8-a2b9-7a6daa03d038" alt=""><figcaption></figcaption></figure>

Let's take a look at the line `Double(a)`. This is known as **type casting**. Because `a` is an `Int` and we needed a `Double`, `Double(a)` converts the value `2` to `2.0`. Note that this **does not** change the type of `a`. It only produces a value to be used for that operation.

One more common operator we may see is the **modulus** operator (`%`). This is similar to the `/` operator except we return the remainder.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FmbCb9AYq28jngsumDbqy%2FUntitled.png?alt=media&amp;token=e3390af9-c142-45be-9cf6-4b4d0354ca45" alt=""><figcaption></figcaption></figure>

### Common Operators

The following is a list of common operators that we are likely to use.

| `>`  | greater than             | `\|\|` | or  |
| ---- | ------------------------ | ------ | --- |
| `>=` | greater than or equal to | `&&`   | and |
| `<`  | less than                | `!`    | not |
| `<=` | less than or equal to    |        |     |
| `==` | equal to                 |        |     |
| `!=` | not equal to             |        |     |

### String Interpolation

**String interpolation** is a way of combining variables and constants inside a string. Take a look at this example:

```swift
var name = "Vin"
"My name is \(name)."
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FnxyjnSuAT1DjJgyPOpom%2FUntitled.png?alt=media&amp;token=425aa670-ece5-4c9f-a965-f3d9fe4cae64" alt=""><figcaption></figcaption></figure>

Of course, we could have used the `+` operator to concatenate these strings together.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FRFhRTXqWPUdrtxtAFYtW%2FUntitled.png?alt=media&amp;token=b62f9123-deb1-4558-b623-445e7d54aecf" alt=""><figcaption></figcaption></figure>

The problem with this approach is efficiency especially if we want to concatenate multiple variables. Another issue with using `+` is that Swift does not allow types such as `Int` or `Float` to be glued with a `String`.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FVDQzaoJiwSfCg0mNnIuk%2FUntitled.png?alt=media&amp;token=12003029-b41a-4ddf-b4d5-5292c86845b3" alt=""><figcaption></figcaption></figure>

We could cast `age` to a `String` but that would be expensive.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FbGvjyPCfcBAa1oBdJZUY%2FUntitled.png?alt=media&amp;token=b76f1935-f9c3-47f7-af02-d33a9da6189a" alt=""><figcaption></figcaption></figure>

Using string interpolation is a lot more efficient and looks cleaner too!

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FTg5QCLomIZZ01w57Xfdy%2FUntitled.png?alt=media&amp;token=b6dd8f01-21fd-4288-af3a-ce3ebef94b0e" alt=""><figcaption></figcaption></figure>


# Data Structures

Fall 2023 | Vin Bui

We learned how to use variables and constants to store data, but only explored basic values such as integer numbers and text. However, when we program, we often need to hold more complicated data that requires a specialized format for organizing and retrieving the data. To do this, we use **Data Structures**.

### Arrays

The most common data structure that we will be using is an **array**. Arrays store a group of values together into a single collection, and we can access these values using their position in the array.

```swift
var staff = ["Vin", "Richie", "Tiffany", "Jennifer", "Antoinette", "Elvis"]
staff[0]
staff[1]
staff[2]
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FnimO9Bw6sI0qihT6quBZ%2FUntitled.png?alt=media&amp;token=9647f562-a4e5-445d-a57f-ff553b5a3fad" alt=""><figcaption></figcaption></figure>

We use square brackets `[]` to mark the start and end point of the array and use commas `,` to separate each value.

Swift uses ***type inferencing*** to determine the type of `staff`. Because all of the elements inside of the array are strings, Swift knows that `staff` is an array of strings (`Array<String>`). If we change the value of an element to a different type, our code will not compile.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FnGQ3i74z5u1vh2JT9PQn%2FUntitled.png?alt=media&amp;token=53e0f250-c89a-4db9-975f-1bb76128269d" alt=""><figcaption></figcaption></figure>

Instead of letting Swift infer what types our array will hold, we can specify the type that we want.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FVtwcOLE9Viq4pJ5GCeDT%2FUntitled.png?alt=media&amp;token=331a9255-cd62-4375-b730-8eda4b3d1b99" alt=""><figcaption></figcaption></figure>

As we can see, if we put in a value that does not match with the given type, our code will not compile.

However, it is possible to allow our arrays to hold ***any*** type. We can give it the special `Any` data type:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FAUCMmMMx1GwLu7F1b3pI%2FUntitled.png?alt=media&amp;token=edae7d49-e388-4448-a9ae-921aa33e0c13" alt=""><figcaption></figcaption></figure>

When adding values to our array, we must first initialize it with an original value. The following code will not compile:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F4wX7EPDncHt4izv3soWE%2FUntitled.png?alt=media&amp;token=a5c142d2-093b-4cae-8653-c5d0c9a27c33" alt=""><figcaption></figcaption></figure>

We can initialize our array in the following ways:

```swift
var staff: [String] = []
var staff = [String]()
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FcaRoIzCFDPUHTrIpLnXN%2FUntitled.png?alt=media&amp;token=ca8f72c3-c040-4fbf-a526-0bd5999e7ac3" alt=""><figcaption></figcaption></figure>

Notice that we used an `append` method to add elements to the end of the array. Swift provides many methods that we can use on our array, and we can even add our own! We can also use operators such as `+` to glue arrays together and return a new array. Read more about them in the [Apple Documentation](https://developer.apple.com/documentation/swift/array).

### Dictionaries

Another common data structure that we might encounter are called **dictionaries**. These are similar to arrays except we use a **key** to access a value in the collection. In other words, dictionaries store **key-value pairs**.

```swift
var staffAge: [String: Int] = ["Vin": 19, "Richie": 20, "Antoinette": 4]
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FBbTKk6vZYmU1WyMBxO9i%2FUntitled.png?alt=media&amp;token=e17a418d-5395-45da-83f4-76fa214542c5" alt=""><figcaption></figcaption></figure>

It is also common to break up our dictionary like so to keep things readable:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FEmkci17faYlrNhUgSRap%2FUntitled.png?alt=media&amp;token=cb6ec177-c10f-48a4-9872-6aba22f5459b" alt=""><figcaption></figcaption></figure>

Similar to arrays, Swift provides a lot of methods that we can use with dictionaries. The [Apple Documentation](https://developer.apple.com/documentation/swift/dictionary) provides more information about them.


# Conditionals

Fall 2023 | Vin Bui

If we want to execute a chunk of code only when a condition is met, then in Swift, we can use **if, else if, and else** **statements**. Let’s take a look at the following example:

```swift
var a = 0
if a == 0 {
    print("Zero")
} else {
    print("Not Zero")
}
```

When using conditionals, we must provide a condition which is an expression that evaluates to `true` or `false`. To enclose a block of code in Swift, we use curly brackets (`{` and `}`). In the example above, the expression `a == 0` evaluates to `true` so the block of code containing `print("Zero")` will be executed.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FKroVAJBT5gqdAM9XClA3%2FUntitled.png?alt=media&amp;token=35bce594-7238-408e-819c-1c4d398a0c36" alt=""><figcaption></figcaption></figure>

Now, what if `a == 0` evaluates to `false`? In that case, Swift will read for the next condition, if any. Because the next statement is an `else` statement, there is no condition to check so this block of code will be executed.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FvbdICr3KJAibW2Bm4NJ0%2FUntitled.png?alt=media&amp;token=22e8112f-a548-4ffb-bad2-fbc2e50691f0" alt=""><figcaption></figcaption></figure>

Sometimes, we want to check for multiple conditions? In that case, there is more than one option:

1. Use the `&&` (and) or `||` (or) operators
2. Use an `else if` statement

Let’s take a look at the second option.

```swift
var a = -6
if a < 0 {
    print("Negative")
} else if a % 2 == 0 {
    print("Even")
} else {
    print("Not even or negative")
}
```

First, the expression `a < 0` is evaluated. Since `-6 < 0` evaluates to `true`, Swift executes the block of code containing `print("Negative")`. Now, since the next statement is an else if statement, it will not be executed. The reason is because this else if statement is connected to an if statement. Since the first if statement evaluated to `true`, Swift will not check any other statements that are connected.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FqBcBxjrjMYZJhMISoZTn%2FUntitled.png?alt=media&amp;token=f9a72c3b-de95-4770-99ca-e416c84dcb93" alt=""><figcaption></figcaption></figure>

Now, if we were to change the else if statement to an if statement, Swift will check this statement because it is no longer connected to the first if statement.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Faeojd5pFkmNqtgUwp7Lt%2FUntitled.png?alt=media&amp;token=e52cdbd4-6a0a-4086-a7ae-15c3d1711130" alt=""><figcaption></figcaption></figure>

Because both conditions are met and they are not linked together, `"Negative"` and `"Even"` will both be printed.

### Guard Statement

Sometimes we want to exit our code execution early on for efficiency purposes. This is where the **guard statement** comes in. A guard statement is similar to an if statement except an if statement runs when the condition is `true` while a guard statement runs when the condition is `false`. We can think of a guard statement as using an if statement with a “not equals” (`!=`) or not” (`!`) operator.

The format for a guard statement is as follows:

```swift
guard condition else {
    // block of code
    // control statement: return, break, continue, or throw
}
```

`condition` is an expression that evaluates to `true` or `false`. If `true`, then the block of code is not executed. If `false`, then the block of code is executed. This is the exact opposite of an **if** statement.


# Loops

Fall 2023 | Vin Bui

When we want to repeat a code a certain number of times in Swift, we can either copy and paste the code or even better, we can use **loops**. There are two main loops in Swift: a **for loop** and a **while loop**.

### Looping over a fixed number of times

Let’s say we wanted to print out the numbers `1..10`. In Swift, we can use the **closed range operator** (`...`) which is three periods in a row.

```swift
for i in 1...10 {
    print(i)
}
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FsTLhw3zCcVuexIp2dzRL%2FUntitled.png?alt=media&amp;token=8f000630-776e-477a-90a9-022b8dac81de" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**In a couple of these examples, we used `i` as the loop variable. This is a common convention used by programmers, but we can name it whatever we want.**
{% endhint %}

The variable `i` is known as a **loop variable** which is a variable that lives within the scope and lifetime of the loop. For every iteration, the value of `i` will change. Now, what if we didn’t need to use `i` and just wanted to print `"Hello Vin and Richie"` 10 times? We could still use `for i in 1...10`; however, it would be better to use an underscore (`_`) instead.

```swift
for _ in 1...10 {
    print("Hello Vin and Richie")
}
```

Why is `...` called a *closed range operator*? Well, that’s because there is also an **open range operator** (`..<`). The difference between these two is that the *closed range operator* is inclusive whereas the ***open range operator*** is not. The following code will only be executed 9 times. It goes up to but not including 10.

```swift
for _ in 1..<10 {
    print("Hello Vin and Richie")
}
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FYcGrcOcarx0rkqmtYbig%2FUntitled.png?alt=media&amp;token=643de1e6-f97b-4fc4-8579-f31e7d9cad63" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**The print statement is very useful for debugging purposes. The user will not be seeing the output when using the app. It is only for the programmer.**
{% endhint %}

### Looping over arrays

Swift provides a nice way to loop over the elements of an array using the **for-in** loop.

```swift
var staff = ["Vin", "Richie", "Tiffany", "Jennifer", "Antoinette", "Elvis"]
for person in staff {
    print(person)
}
```

In this code, the loop variable is `person`. For every iteration of this loop, the value of `person` will be the value of every element inside of the array `staff`, in order.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FTEji0jumTirRTyBimPCh%2FUntitled.png?alt=media&amp;token=895d508a-9e3c-41bb-b434-d3b30910791b" alt=""><figcaption></figcaption></figure>

Instead of looping over the ***element*** of the array, we could have looped over the ***indices*** of the array. The following code is equivalent:

```swift
var staff = ["Vin", "Richie", "Tiffany", "Jennifer", "Antoinette", "Elvis"]
for i in 0..<staff.count {
    print(staff[i])
}
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FG6W2QGOQ6MUryYBQZwNy%2FUntitled.png?alt=media&amp;token=c737c6a9-736e-438a-ac05-feb35a20a65a" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**We can also nest for loops inside of other for loops!**
{% endhint %}

### While Loops

If we don’t know exactly how many times to repeat a block of code, but do know that we want to repeat it while a condition is true, then we can use a **while loop**.

```swift
var i = 0
while i < 10 {
    print(i)
    i += 1
}
```

The above code will print out the value of `i` and increment the value of `i` by 1 ***while*** `i < 10` evaluates to `true`.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FiQtbmCotc2lQr0HOa8kr%2FUntitled.png?alt=media&amp;token=f9cd76bd-0057-49f5-ac18-a9e882bf3ab8" alt=""><figcaption></figcaption></figure>

However, be very careful when using while loops because we can create an infinite loop. In the code below, the value of `i` never changes and will always be less than 10. In this case, there will be an infinite loop:

```swift
var i = 0
while i < 10 {
    print(i)
    // i += 1 commented out
}
```

{% hint style="info" %}
**We can use `break` or `continue` to stop/continue the loop but we it is not recommended.**
{% endhint %}


# Functions

Fall 2023 | Vin Bui

Imagine a large scale application with thousands of lines of code. The codebase would be very messy! To solve this, we need to be able to reuse our code. We can do this with **functions**.

Functions allow us to define reusable blocks of code. We define a function by using the `func` keyword followed by the name of the function (`myName`) and open/close parentheses:

```swift
func myName() {
    print("My name is Vin")
}
```

If we were to just define this function in the playground, nothing will be printed out. This is because we also need to **call** the function. We can call the function we previously defined with the following code:

```swift
myName()
```

Let’s test this in the playground:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F6KO2qvMm4trVPaNZ1jTV%2FUntitled.png?alt=media&amp;token=6cc9ccdc-ad07-4f0b-b1bc-e0a25058cf65" alt=""><figcaption></figcaption></figure>

### Parameters and Arguments

The nice thing about functions is that we can pass in **arguments** to make our functions a lot more useful. Using the example above, let’s customize our function to make it a lot more versatile:

```swift
func myName(name: String) {
    print("My name is \(name)")
}
```

This function has a **parameter** called `name` which is of type `String` and uses string interpolation to output the name. We would then need to pass in an **argument** to the function call:

```swift
myName(name: "Vin")
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FneaZnLPFk5zXFdiw4UJl%2FUntitled.png?alt=media&amp;token=ede6fbb2-2514-45d7-83f5-70417e268430" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**Parameters and arguments are commonly confused by many. Arguments are passed into the function through the&#x20;*****function call*****. Parameters are variables in the&#x20;*****header*****&#x20;of the&#x20;*****function definition*****.**
{% endhint %}

### External and Internal Parameter Names

In Swift, we can change the way parameters are named in the function call and inside of the function definition.

```swift
func myName(name str: String) {
    print("My name is \(str)")
}

myName(name: "Vin")
```

In this example, the name of the parameter within the function definition is `str` but when we call the function, we use `name`. `str` is known as an **internal parameter** and `name` is called an **external parameter**. This may not seem useful at first glance, but it is a very powerful feature once we begin writing code.

We can also use an underscore (`_`) as the ***external parameter***.

```swift
func myName(_ name: String) {
    print("My name is \(name)")
}

myName("Vin")
```

By doing this, we do not need to provide the external parameter name when passing in our argument in the function call.

{% hint style="info" %}
**Common external parameter names include `in`, `for`, and `with`.**
{% endhint %}

### Returning Values

The functions that we defined earlier did not have any **return value**, meaning that when we called the function, nothing gets sent back to the function caller. However, many of the functions we create will have a return value. To do this in Swift, we use the right arrow (`→`) followed by the return type.

```swift
func isEven(num: Int) -> Bool {
    if num % 2 == 0 {
        return true
    }
    return false
}
```

The function above will return `true` if the argument that we pass in is an even number and `false` otherwise.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FgB9XzOFLPyF4anz8h10K%2FUntitled.png?alt=media&amp;token=a8742119-d3b3-456d-ba85-33175431b6c2" alt=""><figcaption></figcaption></figure>

Because this function returns a value, we can do many things with this function call such as assigning the returned value to a variable.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fj6RNWdEN35wZxp9b4grv%2FUntitled.png?alt=media&amp;token=94900265-3a1d-45ad-ae68-b8318f13cbbc" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
**If our function returns a value with only one line of code, we can omit the `return` keyword. This is commonly seen in SwiftUI.**
{% endhint %}


# Closures

Fall 2024 | Peter Bidoshi

Now that we have learned a bit about functions and how they work, we will discuss something more general, called ***Closures***.&#x20;

Closures are self-contained blocks of functionality that can be passed around and utilized within your code. The most simple example of closure is a function, but there exist others that are very important to understand before exploring future topics.

Imagine we have a function, which is a type of closure:

```swift
func getData() -> String {
    return "Fetched Data"
}
```

One way we could use the return of this function is as follows:

```swift
// Same code from above
func getData() -> String {
    return "Fetched Data"
}

// Save the string returned from the function in a variable
var data = getData()
// Print the variable
print(data)
```

Pretty simple right? However, we could also achieve this differently by using a ***Closure Expression.*** Closure expressions allow us to pass a piece of code as an argument to a function. To incorporate this, we need to change the method signature of our "getData" function.

```swift
// This is the syntax to indicate that this 
// function takes in another function!
// "handler" is just the name of the variable,
// and we can call it whatever we want
func getData(handler: (String) -> Void) {
    handler("Fetched Data")
}
```

What is going on here? Let's first talk about the method signature. You will notice we added an argument to the function that is called "handler". This argument has a type of "(String) -> Void". This represents a function that needs to take in a String and return nothing (void). The "getData" function then passes the String "Fetched Data" into that function. Now, let's change the other part of our code.

```swift
// Same function from above
func getData(handler: (String) -> Void) {
    handler("Fetched Data")
}

func printData(data: String) -> Void {
    print(data)
}

getData(handler: printData)
```

Here, we created a function called "printData" that takes a string and returns nothing (void). Notice that this signature (string -> void) is the same signature as our "handler" argument. We then pass the "printData" function as an argument to our "getData" function. with this, our "getData" function will pass the String "Fetched Data" to the "printData" function that was passed to it. This will achieve the same result as the original code.&#x20;

However, this can be simplified! Instead of writing out a whole other function, let's provide the code right into the function! This is what a ***Closure Expression*** is all about.

```swift
// Same function from above
func getData(handler: (String) -> Void) {
    handler("Fetched Data")
}

getData(handler: { data in
    print(data)
})
```

Nice! "data in" is a tricky syntax that you will have to remember. The "data" represents a String that will be returned to the handler after the getData function is run. Swift is smart, so it can automatically infer the type of "data" as a String due to the getData method signature.


# Optionals

Fall 2023 | Vin Bui

{% hint style="info" %}
**This is one of the most important concepts in iOS development!**
{% endhint %}

Sometimes we may want to show that our data does not have any value. If we were using Strings, then an empty string may be a good indicator for “no value”. What about integers? We could use 0 or -1. The problem with this is that we are creating imaginary rules for ourselves. Swift solves this issue by introducing **optionals**.

### Indicating an optional

To indicate an optional in Swift, we use a `?` succeeding the data type. For example, a string optional (or optional string) is represented by `String?`. This String optional can hold two things:

1. a String value
2. `nil`

`nil` means “nothing” or “no value”. To better understand optionals, let’s look at the following example:

```swift
func getSubteamLead(subteam: String) -> String? {
    if subteam == "ios" { return "Tiffany Pan" }
    if subteam == "design" { return "Christina Zeng" }
    if subteam == "marketing" { return "Eddie Chi" }
    if subteam == "android" { return "Emily Hu" }
    if subteam == "backend" { return "Joyce Wu" }

    return nil
}
```

This function returns a *String optional* with value `“iOS is the best subteam”` if the argument is `"ios"` and `nil` otherwise. Let’s put this in the playground and try to store this value into a variable:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FrKSgFrUVRtyQXUjoPcBf%2FUntitled.png?alt=media&amp;token=13fb115d-91c1-43cc-8669-78f5fda56617" alt=""><figcaption></figcaption></figure>

What is the issue with this code? Well, the type of the variable `iosLead` is a `String` but the function returns a `String?`. These two data types are ***different***. In that case, we could change the data type of `iosLead` to `String?`.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fpwx8YFdhRUkQY6K297MW%2FUntitled.png?alt=media&amp;token=8aa27d25-e371-4454-96ec-9f6f998f44ed" alt=""><figcaption></figcaption></figure>

Okay, but what if there was a function that only takes in a `String` and not a `String?` but we still want to use the value returned from `getSubteamLead`?

```swift
func getSubteamLead(subteam: String) -> String? {
    if subteam == "ios" { return "Tiffany Pan" }
    if subteam == "design" { return "Christina Zeng" }
    if subteam == "marketing" { return "Eddie Chi" }
    if subteam == "android" { return "Emily Hu" }
    if subteam == "backend" { return "Joyce Wu" }

    return nil
}

func cheerLead(name: String) {
    print("Woo! Go \(name)!")
}

cheerLead(name: getSubteamLead(subteam: "ios"))
```

This code will not execute because `getSubteamLead` returns a `String?` but the function `cheerLead` takes in a `String`. In this case, we would need to unwrap the optional.

### Safely unwrapping optionals

In order to grab the non-nil value of an optional, we must **unwrap** it. There are three ways to do this:

1. `if let`
2. `guard let`
3. Force unwrapping (`!`)

The first two provides a safe way to unwrap the optional. Using the example from earlier, let’s try to unwrap the optional:

```swift
func getSubteamLead(subteam: String) -> String? {
    if subteam == "ios" { return "Tiffany Pan" }
    if subteam == "design" { return "Christina Zeng" }
    if subteam == "marketing" { return "Eddie Chi" }
    if subteam == "android" { return "Emily Hu" }
    if subteam == "backend" { return "Joyce Wu" }

    return nil
}

func cheerLead(name: String) {
    print("Woo! Go \(name)!")
}

if let leadName = getSubteamLead(subteam: "ios") {
    cheerLead(name: leadName)
}
```

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FD2ykxl574tYy1RmwqzYE%2FUntitled.png?alt=media&amp;token=07754767-3173-4f12-a070-bea480f8df23" alt=""><figcaption></figcaption></figure>

The constant `leadName` holds the unwrapped value returned from the function call `getSubteamLead`. We would then use `leadName` within the **if** statement. Now, if the function returned `nil` instead, then the block of code will not be executed.

We could also use a `guard let` statement:

```swift
func getSubteamLead(subteam: String) -> String? {
    if subteam == "ios" { return "Tiffany Pan" }
    if subteam == "design" { return "Christina Zeng" }
    if subteam == "marketing" { return "Eddie Chi" }
    if subteam == "android" { return "Emily Hu" }
    if subteam == "backend" { return "Joyce Wu" }

    return nil
}

func cheerLead(name: String) {
    print("Woo! Go \(name)!")
}

// Create a custom error
enum myError: Error {
    case incorrectSubteam
}

guard let leadName = getSubteamLead(subteam: "ios") else {
    // Usually we would return something here but because this is not
    // a function, we had to throw an error
    throw myError.incorrectSubteam
}

cheerLead(name: leadName)
```

The main difference between using an `if let` versus a `guard let` statement is the scope of the variable/constant. The constant `leadName` lives *within* the block of code in an `if let` statement whereas in a `guard let` statement, it lives *outside* of it. As we can see above, we are able to use the constant `leadName` outside of the `guard let` statement.

{% hint style="info" %}
**We would want to use a `guard let` statement if we want to use the value many times outside of the block of code, or when we want to terminate the code early when a condition is false for efficiency purposes.**
{% endhint %}

### Force unwrapping optionals

Another (not recommended) approach to unwrap an optional is to force unwrap it using an exclamation mark (`!`).

{% hint style="danger" %}
**Be careful! If we try to unwrap an optional that is holding `nil`, our program will crash!**
{% endhint %}

Let me emphasize this again. Our code will crash if we unwrap an optional that is holding `nil`. We should only use this approach if we are 100% certain that the optional holds an actual value. However, most of the time we should not have to use this. Let’s use the code from earlier:

```swift
func getSubteamLead(subteam: String) -> String? {
    if subteam == "ios" { return "Tiffany Pan" }
    if subteam == "design" { return "Christina Zeng" }
    if subteam == "marketing" { return "Eddie Chi" }
    if subteam == "android" { return "Emily Hu" }
    if subteam == "backend" { return "Joyce Wu" }

    return nil
}

func cheerLead(name: String) {
    print("Woo! Go \(name)!")
}

let leadName = getSubteamLead(subteam: "ios")
cheerLead(name: leadName!)
```

In this case, we know that the code will not crash because we are certain that `leadName` will not hold `nil`. However, `leadName` *could* hold nil and our code will crash if it does.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FWabolWCM8Piu1TTYKkTa%2FUntitled.png?alt=media&amp;token=cf781ea5-0b26-48a9-a068-e31faa7fb0a1" alt=""><figcaption></figcaption></figure>

### Implicitly unwrapped optionals

Earlier, we mentioned that we can indicate an optional by using a question mark (`?`). For example, we can indicate a String optional by doing `String?`. We can also use an exclamation mark (`!`) such as `String!`. The difference between these two is that the constant or variable with the data type that contains the exclamation mark, does not need to be unwrapped before it is used. This is called an **implicitly unwrapped optional**. We unwrap the optional the moment the variable or constant is initialized. We are very likely to see this when we get into UIKit.

{% hint style="info" %}
**Be careful because our code will still crash if this variable/constant holds `nil`.**
{% endhint %}

### Optional chaining

It can get very annoying having to unwrap optionals using `guard let` or `if let` statements and can clutter our code a lot. This may cause many people to be tempted to force unwrap an optional which we should already know is not good. Let’s take a look at the following code:

```swift
func getSubteamLead(subteam: String) -> String? {
    if subteam == "ios" { return "Tiffany Pan" }
    if subteam == "design" { return "Christina Zeng" }
    if subteam == "marketing" { return "Eddie Chi" }
    if subteam == "android" { return "Emily Hu" }
    if subteam == "backend" { return "Joyce Wu" }

    return nil
}

let uppercaseDesign = getSubteamLead(subteam: "design").uppercased()
```

If we put this code in the playground, Xcode will give us an error.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FVAm7jKNFtebLNpoMpf7H%2FUntitled.png?alt=media&amp;token=3a5e87ef-53a5-48bf-8380-4fd461257792" alt=""><figcaption></figcaption></figure>

The problem is that the `uppercased` method is only available for `String` types, not `String?` types. Since `getSubteamLead` returns a `String?` we would need to unwrap it before we can use it in the `uppercased` method. However, this is very annoying to do and can make our code cluttered. Thankfully, Swift allows us to use **optional chaining**:

```swift
let uppercaseDesign = getSubteamLead(subteam: "design")?.uppercased()
```

That extra `?` after the call to `getSubteamLead` is the ***optional chaining***. This means everything after the `?` will only be run if everything before it has a value and is not `nil`. Try this in the playground and the error message will go away.

### Nil coalescing operator

Another clean way to handle optionals in our code is to use the **nil coalescing operator**. The following code is an example of how to use it:

```swift
let designLead = getSubteamLead(subteam: "design") ?? "Invalid"
```

The `??` is the ***nil coalescing operator*** and it provides a default value if the optional is holding `nil`. In the code above, if the call `getSubteamLead(subteam: "design")` returned `nil`, then the constant `designLead` will hold the default value `"Invalid"` instead of `nil`. This is very nice because we do not have to unwrap anything and ensures that there is an actual value.


# UIKit + AutoLayout

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1CGUTF6QCLnKyRWsAEaGqje04_-tWODyS-mTSZx7kqvE/edit?usp=sharing>" %}

### Lecture Video

{% embed url="<https://www.youtube.com/watch?v=y6s9ooFwzV8>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec2-uikit>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

<pre class="language-sh"><code class="lang-sh"><strong>git clone https://github.com/intro-to-ios/lec2-uikit
</strong><strong>OR git clone git@github.com:intro-to-ios/lec2-uikit.git
</strong></code></pre>

#### Checkout Branches

```sh
git checkout origin/1-uilabel
OR git checkout 1-uilabel

git checkout origin/2-uiimageview
OR git checkout 2-uiimageview
```

#### Classes Demo Code

```swift
class Student {
    // Properties
    var name: String
    var major: String
    var age: Int

    // Initializer
    init(name: String, major: String, age: Int) {
        self.name = name
        self.major = major
        self.age = age
    }
}

let vin = Student(name: "Vin", major: "Info Sci", age: 20)
vin.major // Prints "Info Sci"

class EngineeringStudent: Student {
    // Inherits properties from the superclass, but you can
    // define other properties specific to this class
    var doesShower: Bool

    // Initializer
    init(name: String, major: String, age: Int, doesShower: Bool) {
        self.doesShower = doesShower // Initialize properties specific to this class
        super.init(name: name, major: major, age: age) // Call superclass' initializer
    }
}

let archit = EngineeringStudent(name: "Archit", major: "CS", age: 20, doesShower: false)
archit.name // Good
archit.doesShower // Good
vin.doesShower // Does not work

```


# Classes

Fall 2023 | Richie Sun

In Swift, there are two ways that we can build complex data types beyond the given basic types like `Int`, `Float`, and `String`. Classes are one such way that we can build some of these complex data types that we'll see later on in the UIKit framework as well as many other Swift packages.

### Defining a Class

If you have taken CS 1110 or 2110, then classes may already be familiar to you, but essentially; Classes can be thought of as blueprints. Within these blueprints, there are many different specifications and **properties**, for what we want the **objects** of the class to possess.

Thus, under the same analogy, objects are the houses that are built from the class blueprints

* Class = Blueprint
* Object = House built from blueprint

For example, let's suppose we define the following class for a house below:

```swift
class House {
    var color: String
    var material: String
    var owner: String

    init(color: String, material: String, owner: String) {
        self.color = color
        self.material = material
        self.owner = owner		
    }

    func paintHouse(color: String) {
	self.color = color
    }
}
```

Within the house class, there are many **properties** such as color, material, and owner along with their specified type, as well as any methods associated with the class.

### Instantiation and Objects

However, with properties alone, the class is not complete, we need to also define an initializer as shown above. Essentially what the initializer does, is that it instantiates an object of the class.

In the code chunk above, notice the keyword `self`. The `self` keyword is used to represent **an instance (or object) of the given class**. In this case, the initializer creates the instance of the House class, which is then represented by the `self` keyword. Then, the properties **color,** **material**, and **owner** are initialized through `self`.

As shown below, the initializer is a function that is the same name as that of the Class, where we are able to pass in the desired values for the specified properties.

```swift
let blueHouse = House(color: "blue", material: "brick", owner: "Vin")
let redHouse = House(color: "red", material: "wood", owner: "Richie")
```

`blueHouse` and `redHouse` are both objects (or instances) of the same House Class

Now that we have an instance of that class we can then access its properties and call any class methods as shown below:

```swift
let house = House(color: "white", material: "wood", owner: "Reade")
house.color // white
house.paintHouse(color: "blue")
house.color // blue
```

### Inheritance

Classes can also be built based on other classes, this is known as class inheritance. This is a prominent technique that we'll see used extensively throughout UIKit, even in the most basic apps, so it's something we will need to eventually get familiar with.

Lets move back to our scenario with the `House` class that has properties `color`, `material`, and `owner`, and methods like the initializer and `paintHouse` method.

```swift
class House {
    var color: String
    var material: String
    var owner: String

    init(color: String, material: String, owner: String) {
        self.color = color
        self.material = material		
	self.owner = owner		
    }

    func paintHouse(color: String) {
	self.color = color
    }
}
```

Supposed we wanted to define a new class to represent a `TreeHouse`, which includes all the properties that the House object does, but also includes new properties like `treeType` and `slideColor`.

Of course, it may seem logical at first to take all the code defined in the `House` class and copy it over to the TreeHouse, but this repetition of code may come back to bite us later on when we want to change the `House` class and also want the same changes to `TreeHouse`. We would have to change the same code twice!

Luckily, Swift offers a smarter solution with **class inheritance**: We can define the `TreeHouse` class based on our existing `House` class

```swift
class TreeHouse: House {
    // Class implementation here
}
```

The colon above is what establishes this inheritance, it indicates that `TreeHouse` is a **subclass** of `House`, or `House` is the **superclass** of `TreeHouse`; thus, `TreeHouse` will inherit all **properties** and **methods** from the `House` class.

```swift
let treeHouse = TreeHouse(color: "red", material: "wood", owner: "Tiffany")
treeHouse.color // red
treeHouse.paintHouse(color: "blue")
treeHouse.color // blue
```

However, we are not quite there yet, we also want to add the properties `treeType` and `slideColor`, and also change the `paintHouse` method so that we also have a color option to paint the slide.

```swift
class TreeHouse: House {
    var treeType: String
    var slideColor: String
		
    init(color: String, material: String, owner: String, treeType: String, slideColor: String) {
        self.treeType = treeType
	self.slideColor = slideColor
        super.init(color: color, material: material, owner: owner)
    }
}
```

Notice that we did not redefine any of the properties that already exist in `House` since they are inherited. In the initializer, notice a new keyword `super`. The keyword `super` represents the superclass, where in this case we are calling the initializer from the superclass `House`, which initializes the original 3 properties.

Now let us change the `paintHouse` function:

```swift
override func paintHouse(color: String, slideColor: String) {
    self.color = color
    self.slideColor = slideColor
}
```

Notice the keyword `override`. In Swift, override indicates that a method is implemented in the superclass, but we want to change it for the subclass. Thus, if we want to redefine the `paintHouse` function to apply for `TreeHouse`, we need to “override” the existing method

{% hint style="info" %}
**If we don't use `override` Swift won't let us change a method we got from our superclass.**
{% endhint %}


# UIKit

Fall 2023 | Richie Sun

### What is UIKit?

UIKit provides a variety of features for building apps, including components we can use to construct the core structure of our iOS apps. The framework provides the core objects that we need to build apps for iOS. We use these objects to display our content onscreen, to interact with that content, and to manage interactions with the system. Apps rely on UIKit for their basic behavior, and UIKit provides many ways for us to customize that behavior to match our specific needs.

### Create Views in UIKit

The UIKit framework provides an extensive library of classes that represent different kinds of views that we can utilize in our mobile apps. Thus, in order to create and customize these views, we need a basic understanding of classes, properties, methods, and inheritance. For example, suppose we wanted to display a title with a single line of text, we would first call upon the constructor to create an instance of `UILabel`:

```swift
let titleLabel = UILabel()
```

Every view has a different set of properties that we can utilize to customize our frontend view. In the case of the UILabel, we can define many elements of the text such as, `text`, `font`, `textColor`, `textAlignment`, etc.

```swift
titleLabel.text = "UIKit is Awesome!"
titleLabel.font = UIFont(named: "Comic-Sans", size: 16)
titleLabel.textColor = UIColor.red
titleLabel.textAlignment = .center
```

Thus, we are able to change the properties of the UILabel to display a customized view for our iOS App.

### Setting Up a UIKit Project Programmatically

{% hint style="info" %}
**Note that we will provide you with the setup in the assignments. However, this will be helpful for when you create a project on your own such as the Hack Challenge.**
{% endhint %}

Before we write any code, let's make sure to properly set up our Swift files as detailed below. In this class we mainly teach UIKit with programmatic layout, and we DO NOT use Storyboard Swift. Follow the guide here:

{% content-ref url="/pages/gSAUCWmERbIhYt6ueSH0" %}
[Xcode Project Setup](/resources/tool-guides/xcode-project-setup)
{% endcontent-ref %}


# AutoLayout

Fall 2023 | Richie Sun

Now that we know how to define class and utilize UIKit views, how do we position and organize these views in our apps? There are multiple ways to layout views to a screen in iOS development – some examples include **frame-based**, **storyboards**, and **programmatic AutoLayout**. However, the method we will be learning in this course is programmatic AutoLayout.

### What is AutoLayout?

AutoLayout is a constraint-based organization system used for UI development in iOS applications. This constraint layout system allows for adaptive UI which adapts to screens of different sizes and orientations, using a **relational** layout structure to organize views with respect to one another. Thus, this method tends to be less error-prone and does not require us to worry about the coordinates of individual elements on the screen.

### Important Terminology

When dealing with AutoLayout and constraints, there are a few terms that are important to understand before jumping in:

| Superview:  | The superview is the immediate ancestor of the current view. In other words, it is the view that the current view is contained within.                                                                                                     |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Subview:    | Subviews are the children of the current view. In other words, they are the views which are contained within by the current view.                                                                                                          |
| Constraint: | In general, constraints must define both the size and the position of a view, in order for that view to display properly within its superview. Think of them as the support beams that keep a view in place.                               |
| Anchors:    | Every UIView has a set of anchors that define its layouts rules. The most important ones are: widthAnchor, heightAnchor, leadingAnchor, trailingAnchor, topAnchor, bottomAnchor, centerXAnchor and centerYAnchor (Examples in image below) |

<div><figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FlHzXQYFw7c8IksWVgRXD%2FUntitled.png?alt=media&amp;token=61d9c824-4f3e-4567-af5f-79a8aea1056a" alt=""><figcaption></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fu0DJK4hmuiMkwDnE22pF%2FUntitled.png?alt=media&amp;token=f7641616-6056-4a3e-b3d0-32a1a7cdd90b" alt=""><figcaption></figcaption></figure></div>

### NSLayout and Setting Constraints

Before we begin setting up anchors and constraints, the view needs to be added to the base view of the NavigationController, or any superview. To do that, we call the following function:

```swift
superview.addSubview(currentView)
```

In the code chunk above, superview is the view that we want to contain the currentView

Every subview of UIView has these four properties: **topAnchor**, **leadingAnchor**, **bottomAnchor**, and **trailingAnchor**. As the names imply, topAnchor refers to the view’s top edge, leadingAnchor refers to the view’s left edge, bottomAnchor refers to the view’s bottom edge, and trailingAnchor refers to the view’s right edge.

An **IMPORTANT** note to always remember is that in order for us to use these anchors to create constraints (layout our views), we must remember to set the view’s **translatesAutoresizingMaskIntoConstraints** property to be **false** before setting these anchors.

Suppose we want to constrain a UILabel called labelA 50 pixels from the top of the screen, and horizontally aligned to the center of the screen like shown below:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FnDMzv9GF3XucNVLDnAYi%2FUntitled.png?alt=media&amp;token=b025cd18-1592-4ad3-b4ba-d7610d5ffb0d" alt="" width="375"><figcaption></figcaption></figure>

This is how we would do that:

```swift
let labelA = UILabel()

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Don't forget this step!!
    labelA.translatesAutoresizingMaskIntoConstraints = false

    // We need to add labelA to the base view of the Navigation Controller
    view.addSubview(labelA)
    
    // We have to activate our constraints in order to
    NSLayoutConstraint.activate([
        // Here, we can insert all the constraints that we want activated
        labelA.topAnchor.constraint(equalTo: view.topAnchor, constant: 50)
	labelA.centerXAnchor.constraint(equalTo: view.centerXAnchor)
    ])
}
```


# MVC + Navigation + Delegation

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/1rb9v4VqH7i46g_gEqNUVeEdEdkvor4qRwYSi9xjxtVg/edit?usp=sharing>" %}

### Lecture Video

{% embed url="<https://youtu.be/DKXLf3zebUA>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec3-navigation>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec3-navigation.git
OR git clone git@github.com:intro-to-ios/lec3-navigation.git
```

#### Checkout Branches

```sh
git checkout origin/1-navigation
OR git checkout 1-navigation

git checkout origin/2-delegation
OR git checkout 2-delegation
```


# MVC

Fall 2023 | Vin Bui

In the previous chapter, we learned *what* views are and *how* to create views in UIKit. We also learned how to use AutoLayout to position our views on the screen. However, our views contained hard coded data and did not have any functionality at all. When we create apps, we want our views to respond and update to user interactions.

**MVC (Model-View-Controller)** is a ***software design pattern*** which is a set of rules that govern the architecture that we follow when writing our code. There are other design patterns out there such as MVVM (Model-View-ViewModel) but we will be using MVC throughout this course. To better understand MVC, let’s take a deeper look at each component.

### Model

**Models** are objects that represent our application’s data. Let’s look at an app we are familiar with, **Eatery**. The models in **Eatery** are the dining halls, the dishes and food items, the user’s information, etc. In other words, models contain information about our application and are often updated based on user interaction or from a backend service.

#### Classes vs Structs

Notice that we often use structs instead of classes when representing our models. The difference between these two is that structs are *value* *types* whereas classes are *reference* *types*. What this means is that if we were to change a property of an instance of a struct, the entire instance changes. On the other hand, if we change a property of an instance of a class, the instance does not change.

For example, consider a `User` model with the property `name`. For a class object (reference type), if we changed the value of `name`, all locations that have a reference to that object have the new updated value for `name`. If this were to be a struct object (value type), changing the value of `name` in one location DOES NOT update other locations because a new instance is being created. We can think of reference types as sharing a Google Doc with other collaborators. If one person were to change something on their side, the others would be able to see those changes. For structs, we can think of it as making a copy of the Google Doc.

One advantage of using a class is inheritance. In other words, we can use properties and methods already defined by a parent class, commonly seen in UIKit. However, there are times when we don't need to use all of these properties and methods, making structs more preferable. This is commonly seen in SwiftUI and why using structs is a lot faster than classes.

### View

**Views** are the visible components that are used to build the user interface (UI). This includes buttons, labels, images, etc. In **Eatery**, *everything* we see is a view. For example, the name of the dining hall is a UILabel which contains information from the dining hall model. We don’t see models. We see views that contain information from the models.

### **Controller**

**Controllers** belong in the middle between models and views. The main goal of a controller is to establish a connection between models and views. The controller is also in charge of processing the logic to update the models and views. For example, in **Eatery**, there is a User model that represents the logged in user. When we sign in, we are interacting with views. How does the model update based on what we passed into the text field? Well the controller handles that logic. If we provided the correct credentials, it will modify the models and update the views such as showing a logout button. If we provided invalid credentials, then the controller will still update the view and show a red error message.

### Putting everything together

One important thing to keep note of is that views and models are separate. They cannot directly interact with each other, but rather, they must go through a controller to make that connection.

We can think of MVC as watching television: the TV is the view, the remote is the controller, and the channels/content is the model. How does the TV (view) change the channel (model)? It can’t! We must use a remote (controller) in order to do that. When we change channels using the remote, we made changes to the model and tell the TV to update its view.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FgEstFBqw6w7EtFnC3YSn%2FUntitled.png?alt=media&amp;token=d66a7a20-cfd2-48eb-bb86-27502f3542f3" alt=""><figcaption></figcaption></figure>


# Navigation

Fall 2023 | Vin Bui

So far, we've only worked with one screen which may contain many views. For this single screen, we controlled the models and views with a single `UIViewController`. However, many of the apps that we use today contain multiple screens that we can navigate between. In UIKit, we represent every distinct screen with a separate `UIViewController`. There are two ways to navigate between screens: 1) **pushing/popping** and 2) **presenting/dismissing**.

### Pushing/Popping

Before we dive in to the technical details, let’s observe what pushing and popping looks like.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2Fl8dHiEm5M6aNpJN9oZMo%2Fpushing_popping.gif?alt=media&amp;token=fe64c117-092a-4292-9e1f-6b0a878384fc" alt="" width="188"><figcaption></figcaption></figure>

As we can see, when we tap on one of the cells, a new screen shows up. Each new screen that we push is a separate `UIViewController`. So then, how do we keep track of the view controllers that have been pushed to figure out which one needs to be popped? We use a **navigation stack**. Every time a view controller is pushed, it goes on top of the navigation stack. Think of the navigation stack as a stack of books where each book is a view controller. The last item to be pushed into this stack will be the first one to be popped out (LIFO). How do we represent this navigation stack in UIKit? We use a **`UINavigationController`**.

Inside of `SceneDelegate.swift` add this code to the function `scene`:

```swift
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // 1. Capture the scene
    guard let windowScene = (scene as? UIWindowScene) else { return }
    
    // 2. Create a new UIWindow and pass in a UIWindowScene
    let window = UIWindow(windowScene: windowScene)
    
    // 3. Create a view hierarchy programmatically
    let rootVC = ViewController()
    let navController = UINavigationController(rootViewController: rootVC)
    
    // 4. Set the navigation controller as the window's root view controller
    window.rootViewController = navController
    
    // 5. Set the window and call makeKeyAndVisible()
    self.window = window
    window.makeKeyAndVisible()
}
```

The important step to remember here is step 3 where we first initialize the view controller (`rootVC`) that we want to be displayed when the app launches. Now, we have to place `rootVC` into the navigation stack by creating a `UINavigationController` with `rootVC` as the root view controller.

One thing to keep in mind is that the line `let rootVC = ViewController()` creates a view controller whose class name is `ViewController`. When we create a new project, by default, a class called `ViewController` is created for us. If we created a new class or renamed the class to `HomeViewController`, then we would use `HomeViewController()` instead.

Now, to push and pop a view controller is very simple:

```swift
// Push
navigationController?.pushViewController(_ viewController: UIViewController, animated: Bool)

// Pop
navigationController?.popViewController(animated: Bool)
```

`UIViewController` will be the view controller object that we want to push. Most of the time, we want to set `animated` to `true`. For example, if we had a class called `ProfileViewController` and wanted to *push* it, we would write the following code in the view controller class that is pushing it (not inside `ProfileViewController`):

```swift
let profileVC = ProfileViewController()
navigationController?.pushViewController(profileVC, animated: true)
```

To *pop* the `ProfileViewController`, we would write this code in `ProfileViewController`:

```swift
navigationController?.popViewController(animated: true)
```

We could then link this code to some action such as a tapping on a button, cell, image, etc.

### Presenting/Dismissing

Let’s observe what presenting and dismissing looks like.

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FM8ypLpe546Jla0lT9Sjy%2FUntitled.gif?alt=media&amp;token=b1aee7f4-d7b2-4060-92df-d808ac57ad6f" alt="" width="188"><figcaption></figcaption></figure>

As we can see, a modal sheet is presented from the bottom of the screen and gradually transitions up. This is **presenting**. To **dismiss**, we can simply click on the cancel button or more commonly, swipe downwards from the top of the modal sheet. The view controller that is being presented is displayed on top of the previous view controller. **There is not a navigation stack at play here ⇒ No `UINavigationController`.**

To present/dismiss a view controller:

```swift
// Presenting
present(_ viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?)

// Dismissing
dismiss(animated: Bool, completion: (() -> Void)?)
```

For example, if we had a class called `ProfileViewController` and wanted to *present* it, we would write the following code in the view controller class that is pushing it (not inside `ProfileViewController`):

```swift
let profileVC = ProfileViewController()
present(profileVC, animated: true)
```

To *dismiss* the `ProfileViewController`, we would write this code in `ProfileViewController`:

```swift
dismiss(animated: true)
```

As we may have notice from the function header above, there is an optional parameter called `completion`. This is known as a **completion handler** which is a function that gets executed when the function call is complete. We will discuss this in detail once we get into networking.


# Delegation

Fall 2023 | Vin Bui

{% hint style="info" %}
**This is one of the most important concepts to understand regarding iOS development using UIKit, and is one of concepts that students in the past have struggled with the most. Please read this section over and over again until you understand this concept. Feel free to ask the course staff if you are still confused.**
{% endhint %}

The main purpose of the **delegate pattern** is to **allow a child to communicate back with its parent without the child knowing its parent’s type**. This makes it much easier to maintain and write reusable code. Delegation is a 1:1 relationship with a child and its parent.

### Protocols

To implement delegation in Swift, we use **protocols**. According to Swift’s official documentation,

> A *protocol* defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be *adopted* by a class, structure, or enumeration to provide an actual implementation of those requirements. Any type that satisfies the requirements of a protocol is said to *conform* to that protocol.

In other words, protocols are a set of properties and methods that classes must implement when conforming to it (similar to interfaces in Java).

```swift
protocol SomeProtocol: AnyObject {
    // Protocol definition here
}
```

You can learn more about protocols [here](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/protocols/), but for our purpose, we will only need to define functions inside of the protocol. For example, If we wanted to create a protocol so that a child can tell its parent to update some text, we could do the following:

```swift
protocol UpdateTextDelegate: AnyObject {
    func updateText(newText: String)
}
```

{% hint style="danger" %}
**Make sure to conform the protocol to `AnyObject`!**
{% endhint %}

It’s convention to name our protocol with its purpose followed by the word `Delegate` at the end. We also created a function called `updateText` that takes in a string called `newText`. Now, if we had a class called `ParentViewController` and we wanted to conform to this protocol, we could do the following:

```swift
// Include `UpdateTextDelegate` in the class header
class ParentViewController: UIViewController, UpdateTextDelegate {
    // Class definition here

    // Must implement the function `updateText`
    func updateText(newText: String) {
        // Update some text given `newText`
    }
}
```

Now, it’s common to use an **extension** to implement these functions to keep our code a lot more neat:

```swift
// Remove `UpdateTextDelegate` from the class header
class ParentViewController: UIViewController {
    // Class definition here
}

// Add `UpdateTextDelegate`
extension ParentViewController: UpdateTextDelegate {
    func updateText(newText: String) {
        // Update some text given `newText`
    }
}
```

The only changes that we made was removing `UpdateTextDelegate` from the original class header and moved it to the extension header, followed by the function implementation required by the protocol.

### Delegate vs Delegator

In the code above, we conformed `ParentViewController` to the `UpdateTextDelegate` protocol. The class `ParentViewController` is known as the **delegate**. The **delegate** is the class that conforms to that protocol.

Now, if we had a view controller called `ChildViewController` that wants to communicate back with the parent, then this view controller is known as the **delegator**. The **delegator** is the class that wants the **delegate** to do something by calling the delegate.

We’ve looked at the code required by the ***delegate***, but what about the **delegator**? Inside of `ChildViewController`, we would create a property whose type will be `UpdateTextDelegate`:

```swift
class ChildViewController: UIViewController {
    // Class definition here

    // Create the property
    // If we make this private, an initializer is required
    weak var updateTextDelegate: UpdateTextDelegate?
}
```

How does this child class know who the delegate is? The parent class would need to specify that it itself is the delegate:

```swift
// Assume this class conforms to `UpdateTextDelegate`
class ParentViewController: UIViewController {
    // Class definition here

    // When we create an instance to `ChildViewController`, pass in
    // `self` as the delegate
    
    private func pushChildVC() {
        let childVC = ChildViewController()
        childVC.updateTextDelegate = self
        navigationController?.pushViewController(childVC, animated: true)

        // If the property `updateTextDelegate` is private, we will need
        // an initializer in `ChildViewController` that initializes it
	// and use this line instead
        let childVC = ChildViewController(updateTextDelegate: self)
    }
}
```

Now, once the child has a reference to its parent (specifically, a *weak* reference, will explain this in another chapter), we can now call that function:

```swift
class ChildViewController: UIViewController {
    // Class definition here

    // Create the property
    // If we make this private, an initializer is required
    weak var updateTextDelegate: UpdateTextDelegate?

    // Communicate with parent
    private func communicateBack() {
        let newString = "Here you go parent"
	updateTextDelegate.updateText(newText: newString)
    }
}
```

Note: In the example code above, we created the functions `pushChildVC` and `communicateBack`. These functions could be anything. What’s important is the code inside of the function.

### Putting everything together

There was a lot of code and it could be quite difficult to wrap our head around, so let's put everything together.

There are two classes: `ParentViewController` (**delegate**) and `ChildViewController` (**delegator)**. `ParentViewController` is the **delegate** so it conforms to the protocol, meaning that it is required to implement the functions and properties defined by that protocol. When `ParentViewController` creates the `ChildViewController`, it will need to tell it that it itself is the delegate. We do this by creating a property in `ChildViewController` containing the reference of the delegate (which is `ParentViewController`). To communicate from the child to the parent, the child calls the function defined in the protocol using the delegate property that was created earlier. This child could then pass in whatever it wants to the function (since it’s the *delegator*) and the parent (the **delegate**) will use whatever the child passed in and do whatever it needs to do.

Let’s take a real life example to understand this better. Say we went to a bar to have a couple of drinks. The bar contains a menu, a bartender, and a customer. The menu is the **protocol**, the bartender is the **delegate**, and the customer is the **delegator**. The bartender must conform to the menu. In other words, the bartender can only make drinks that are on the menu. But how does the bartender know what drinks to make? Well, the customer (delegator), tells the bartender (delegate) what drinks to make. In other words, the customer cannot make the drinks themself but requires the bartender to do it for them.


# UITableView

### Lecture Slides

{% embed url="<https://docs.google.com/presentation/d/15y5djQ4_2vFzc_04A6xnTxDrseHihS6OEU7o-Y9Jp84/edit?usp=sharing>" %}

### Lecture Video

{% embed url="<https://youtu.be/ObvjkEgLIY4>" %}

### Lecture Demo

{% embed url="<https://github.com/intro-to-ios/lec4-uitableview>" %}
If you prefer to download the ZIP, go to Code > Download ZIP.
{% endembed %}

#### Clone the Repository

```sh
git clone https://github.com/intro-to-ios/lec4-uitableview.git
OR git clone git@github.com:intro-to-ios/lec4-uitableview.git
```

#### Checkout Branches

```sh
git checkout origin/1-cell
OR git checkout 1-cell

git checkout origin/2-tableview
OR git checkout 2-tableview
```


# What is a UITableView?

Fall 2023 | Vin Bui

So far, we only created static, non-moving views. However, many apps today have views that are scrollable. One way to implement a scrollable view with UIKit is with a `UITableView`.

### What is a UITableView?

A `UITableView` is a subclass of `UIScrollView` which is a view that users can scroll through. We can think of a `UITableView` as a list of data. Each item inside of this list is represented by a view called a `UITableViewCell`. Each cell tends to look very similar to one another but are holding different data.

### Examples of a UITableView

<div><figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2F7no5faGAhDD6BlpT9doP%2FUntitled.jpeg?alt=media&amp;token=3ec16239-08f5-4ed2-8b52-47d21aa71fea" alt="" width="375"><figcaption><p>Spotify Playlist</p></figcaption></figure> <figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FvOPRkrTgGM8DyGDOnGOk%2FUntitled.png?alt=media&amp;token=5d325ad5-54e9-4609-91d1-ff93cc4d4bf7" alt="" width="375"><figcaption><p>iOS Settings</p></figcaption></figure></div>

### Breaking Down a UITableView

A `UITableView` contains **sections** where each section contains **rows**, and each row being represented by a **cell**. Let’s take a look at Settings:

<figure><img src="https://1509678725-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Lwk7443W4ukbAF9S07e%2Fuploads%2FXuuv9vkrVQn7BAmdL57g%2FUntitled.png?alt=media&amp;token=1b42f343-8888-4b07-95ff-c5ec61c0183c" alt=""><figcaption></figcaption></figure>

As we can see, a `UITableView` can contain as many sections as it wants, and each section can contain as many rows as it wants. The rows are represented by a `UITableViewCell` which is a view. In the image above, we can see that each cell looks very similar to one another. Each cell contains a `UIImageView` representing the icon as well as a `UILabel` describing that cell. In the next section of this chapter, we’ll learn how to create these custom cells.


# UITableView Setup

Fall 2023 | Vin Bui

### Create a Custom UITableViewCell

Creating a `UITableViewCell` is very similar to how we have been creating views inside of a `UIViewController`. We still define properties for the view and data, initialize those views, add them as a subview, and constrain those views. However, when working inside of a `UITableViewCell` there are some slight modifications that we will need to make. Follow these steps:

1. Our custom class needs to be a subclass of `UITableViewCell`
   * `class CustomTableViewCell: UITableViewCell { }`
2. Create the following initializer:

   ```swift
   override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
       super.init(style: style, reuseIdentifier: reuseIdentifier)
   }

   // `required init` here
   ```
3. Determine what views to create and write a helper function to initialize its properties.
   * For example, if we need to display some text, we would create a `UILabel` and create a helper function to initialize its font, font color, etc. Note that we do not know anything about the data yet, so the property `.text` of the `UILabel` will not be initialized **yet**.
4. Inside of the helper function, add the views we created as a subview to `contentView` and constrain the view with respect to `contentView`. Then call the helper function inside of the initializer.
   * **This is one of the main differences from what we have been doing before. Instead of referencing `view`, we will be using `contentView`. Note that we do not need to use `safeAreaLayoutGuide` here.**
5. Create a `configure` function (do not make `private`) that will take in some data as a parameter, and configure our views.
   * For example, we could write a function that takes in a `String` and sets `UILabel.text` property equal to the value passed in.
6. Create a reuse identifier for this cell: `static let reuse = "<reuse_identifier>"`
   * See “Dequeuing Cells” below for more information.

```swift
// 1. Subclass of `UITableViewCell`
class CustomTableViewCell: UITableViewCell {
    // 3. Create view properties
    private let label = UILabel()

    // 6. Create a reuse identifier
    static let reuse = "CustomTableViewCellReuse"

    // 2. Create the following init
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        // 4. Call helper functions
	setupLabel()
    }
		
    // 2. `required init` here

    // 5. `configure` function (do not make private)
    func configure(newText: String) {
	label.text = newText
	// Configure additional views here
    }

    // 3. Set Up View Helpers
    private func setupLabel() {
	// 3. Initialize the label's properties

	// 4. Add as subview to `contentView`

	// 4. Constrain with respect to `contentView`
    }
}
```

### Dequeuing Cells

In Step 6 above, notice that we have a **reuse identifier**. First, let’s imagine we have a table view that contains a list of all students at Cornell. How many cells would we have? Thousands! Remember, each cell is a separate view and if we have thousands of views, that’s a lot of memory being used! The workaround for this would be to create only the views needed on the screen at one time. If a cell were to go off of the screen, Swift will ***dequeue*** this cell for another cell to be created. This is the reason why the cells in a `UITableView` look very similar! It makes it very efficient to dequeue a cell and reuse it.

How does Swift know which cell to “pick up” and reuse? A **reuse identifier** is used to associate a cell that is being dequeued with another cell that is about to be rendered.

### Setting Up a UITableView

A `UITableView` is just like any other `UIView` that we've worked with thus far. We've initialized the view by doing the following steps:

1. Create the view
2. Configure the view by changing its properties
3. Adding the view as a subview to some parent view
4. Enable auto layout and set up constraints

With a `UITableView`, we do the exact same thing but with 3 additional steps:

5. **Register a `UITableViewCell`**
   * For example, if we had a custom class called `CustomTableViewCell` with a static reuse constant called `reuse`, we would use the following code:

```swift
tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CustomTableViewCell.reuse)
```

6. **Set the `UITableView` delegate** (create an extension just like any other protocol)
   * See [UITableViewDelegate](#6-uitableviewdelegate) section below
7. **Set the `UITableView` dataSource** (create an extension just like any other protocol)
   * See [UITableViewDataSource](#7-uitableviewdatasource) section below

### 6: UITableViewDelegate

The purpose of a `UITableViewDelegate` is to add functionality to the table view. A class conforming to the protocol `UITableViewDelegate` **does not** have any required functions to implement; however, the two most common functions to implement are: `heightForRowAt` and `didSelectRowAt`.

```swift
// If our cell has a fixed height, then implement this function.
// If our cell has a dynamic height, do not implement this function and rely on AutoLayout.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return <height> // the height of the cell
}
```

```swift
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    // Perform some operation when cell is tapped
}
```

{% hint style="info" %}
**Tip: If we start typing `heightForRowAt` or `didSelectRowAt`, Xcode will autofill the function header for us!**
{% endhint %}

### 7: UITableViewDataSource

In contrast to `UITableViewDelegate`, there are ***two*** **required** *functions* to implement: `cellForRowAt` and `numberOfRowsInSection`.

For `numberOfRowsInSection`, we want to provide the number of rows (cells) for a section. Usually, this is the size of our data model array. For example, if our table view listed out all students at Cornell, we would have a data model representing an array of Student objects. The number of rows would be the size of the array (use `.count` to get the size).

```swift
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return dataModelArray.count
}
```

The purpose of `cellForRowAt` is to determine the cell class to use (in addition to registering the cell) as well as configuring the cell (by calling the `configure` function). The following code is for a custom cell class called `CustomTableViewCell`:

```swift
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: CustomTableViewCell.reuse, for: indexPath) as? CustomTableViewCell else { return UITableViewCell() }
    
    let dataModel = dataModelArray[indexPath.row]
    cell.configure(...) // pass in our dataModel to the configure function in our custom cell class
    return cell
}
```

Let’s go over this function line by line:

1. First, we ***dequeue*** the cell with the given *reuse identifier*. This gives us a `UITableViewCell`. Now, we need to *cast* it to our custom type by using the `as?` keyword. This returns an optional type of our custom cell. We unwrap it by using a `guard let` (or we could use an `if let`). If the casting failed and the optional holds `nil`, we return a basic `UITableViewCell`.
2. Then, we need to identify which data this cell will hold. Most of the time, we will have some data model array (such as an array of students). To determine the position a cell is located inside of a table view, we use `indexPath.row` which returns an `Int`. We could then use this value to access an element inside of our data model array.
3. Next, we would need to configure our cell with the data model that we retrieve in Step 2. We can pass this information into our custom cell class’s `configure` function that we implemented earlier to configure the cell’s views such as changing a UILabel’s text.
4. Finally, we return the configured custom cell.

### Complete Code

```swift
class ViewController: UIViewController {
    // 1. Create the view
    private let tableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Additional setup here

	setupTableView() // 2. Configure the view
    }
		
    // 2. Configure the view
    private func setupTableView() {
        // 5. Register Custom Cell
        tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: CustomTableViewCell.reuse)
        tableView.delegate = self // 6
	tableView.dataSource = self // 7
		
	view.addSubview(tableView) // 3
	tableView.translatesAutoresizingMaskIntoConstraints = false // 4
		
	// 4. Set constraints
    }
}

// 6. Conform to `UITableViewDelegate`
extension ViewController: UITableViewDelegate {
    // `heightForRowAt` (optional)
    // `didSelectRowAt` (optional)
    // Additional functions here
}

// 7. Conform to `UITableViewDataSource`
extension ViewController: UITableViewDataSource {
    // `cellForRowAt`
    // `numberOfRowsInSection`
    // Additional functions here
}
```




---

[Next Page](/llms-full.txt/1)

