Intro to iOS Development
  • Welcome
    • β˜€οΈIntroduction
    • 🐣Getting Started
    • 🐦Course Staff
  • Logistics
    • πŸ“œSyllabus
    • πŸ—“οΈSchedule
    • πŸ–ŠοΈGrading
    • πŸ™‹β€β™‚οΈOffice Hours
    • Ed Discussion
  • Assignments
    • 🍼A1: Swift Basics
    • πŸ§‘A2: Profile
    • πŸ’¬A3: ChatDev
    • πŸ‘¨β€πŸ³A4: ChefOS
    • πŸ‘¨β€πŸ³A4: ChefOS - SwiftUI
    • πŸ“±Hack Challenge
      • πŸ†FA23 Winners
  • Lectures
    • 1️⃣Logistics + Swift Basics
    • 2️⃣UIKit + AutoLayout
  • 3️⃣MVC + Navigation + Delegation
  • 4️⃣UITableView
  • 5️⃣UICollectionView
  • 6️⃣Networking I
  • 7️⃣Networking II
  • 8️⃣SwiftUI I
  • 9️⃣SwiftUI II
  • πŸ”ŸPersistence + SnapKit
  • πŸ””(11) Notifications
  • 🌎(12) Deployment and MapKit
  • Chapters
    • πŸ–οΈIntroduction
    • ☁️Git + GitHub
      • 1️⃣Git Installation
      • 2️⃣Git Basics
      • βž•Git+
    • 🐣Swift Basics
      • 1️⃣Variables and Constants
      • 2️⃣Data Types
      • 3️⃣Operators
      • 4️⃣Data Structures
      • 5️⃣Conditionals
      • 6️⃣Loops
      • 7️⃣Functions
      • 8️⃣Closures
      • 9️⃣Optionals
    • 🧰UIKit + AutoLayout
      • 1️⃣Classes
      • 2️⃣UIKit
      • 3️⃣AutoLayout
    • πŸ“ΊMVC + Navigation + Delegation
      • 1️⃣MVC
      • 2️⃣Navigation
      • 3️⃣Delegation
    • πŸ“UITableView
      • 1️⃣What is a UITableView?
      • 2️⃣UITableView Setup
    • πŸ“šUICollectionView
      • 1️⃣What is a UICollectionView?
      • 2️⃣UICollectionView Setup
    • 🌐Networking I
      • 1️⃣HTTP Requests
      • 2️⃣Callbacks
      • 3️⃣Codable
    • 🌍Networking II
      • 1️⃣Alamofire
      • 2️⃣GET Requests
      • 3️⃣POST Requests
      • 4️⃣URLSession
    • πŸ’ΎPersistence + SnapKit
      • 1️⃣Persistence
      • 2️⃣SnapKit
    • πŸ•ŠοΈSwiftUI
      • 1️⃣Introduction to SwiftUI
      • 2️⃣Getting Started with SwiftUI
      • 3️⃣Views + Modifiers
      • 4️⃣Layouts
      • 5️⃣Navigation
      • 6️⃣Property Wrappers
    • πŸŽ›οΈWidgets
      • 1️⃣Introduction to Widgets
      • 2️⃣Setting Up Widgets
      • 3️⃣Building Widgets
      • 4️⃣Configuring Widgets
    • 🧱Project Foundation
    • βœ…Testing
      • 1️⃣Unit Testing
    • πŸ‘£Debugging
      • 1️⃣OSLog
      • 2️⃣Crashlytics
      • 3️⃣Analytics
    • ☁️CI/CD
      • 1️⃣Xcode Cloud
      • 2️⃣AppStore Shipping
  • Guides
    • πŸ”¨Xcode Project Setup
    • 🎨Figma
    • πŸ“¬Postman
    • πŸ₯₯CocoaPods
    • 🧰UIKit Handbook
    • πŸ“‘Tab Views
      • UITabBarController
      • TabView
  • Work in progress
    • 🧡Concurrency
    • 2️⃣UI Testing
    • πŸ•Reactive Programming
    • 🧠Memory Management
      • πŸ”ARC
    • πŸ“¦Storage
    • πŸ“£Notifications
  • Archived
    • SP24
      • Logistics
        • πŸ“œSyllabus
        • πŸ—“οΈSchedule
        • πŸ–ŠοΈGrading
        • πŸ™‹β€β™‚οΈOffice Hours
      • Assignments
        • 🍼A1: Swift Basics
        • πŸ§‘A2: Profile
        • πŸ’¬A3: ChatDev
        • πŸ‘¨β€πŸ³A4: ChefOS
        • πŸ“±Hack Challenge
          • πŸ†FA23 Winners
      • Lecture
        • 0️⃣Course Intro + Logistics + Git Setup
        • 1️⃣Swift Basics
        • 2️⃣UIKit + AutoLayout
        • 3️⃣MVC + Navigation + Delegation
        • 4️⃣UITableView
        • 5️⃣UICollectionView
        • 6️⃣Networking I
        • 7️⃣Networking II
        • 8️⃣Persistence + SnapKit
        • πŸ”ŸSwiftUI
        • πŸ”’TabViews
    • FA23
      • Logistics
        • 🐣Getting Started
        • 🐦Course Staff
        • πŸ“œSyllabus
        • πŸ—“οΈSchedule
        • πŸ–ŠοΈGrading
        • πŸ™‹β€β™‚οΈOffice Hours
      • Assignments
        • 🍼A1: Swift Basics
        • πŸ§‘A2: Profile
        • πŸ’¬A3: ChatDev
        • πŸ‘¨β€πŸ³A4: ChefOS
        • πŸ“±Hack Challenge
          • πŸ†FA23 Winners
      • Lectures
        • 0️⃣Course Intro + Logistics
        • 1️⃣Swift Basics
        • 2️⃣UIKit + AutoLayout
        • 3️⃣MVC + Navigation + Delegation
        • 4️⃣UITableView
        • 5️⃣UICollectionView
        • 6️⃣Networking I
        • 7️⃣Networking II
        • 8️⃣Persistence + SnapKit
        • πŸŽ›οΈWidgets
          • πŸ‘ΌIntroduction to Widgets
          • βš’οΈSetting Up Widgets
          • 🧱Building Widgets
          • πŸ‘¨β€πŸ’»Configuring Widgets
        • πŸ”ŸSwiftUI
    • SP23
      • Logistics
        • Lecture Schedule
        • Syllabus
        • Grading
        • SP23 Office Hours
      • Chapters
        • 1. Intro to Swift & Xcode
          • Lecture Handout
          • Lecture Demo
          • 🍼Project: Swift Basics
        • 2. UIKit and AutoLayout
          • Lecture Handout
          • Lecture Demo
          • πŸ›’Project: UIKit + AutoLayout
        • 3. Navigation, MVC, and Delegation
          • Lecture Handout
          • Lecture Demo
          • Project: Navigation + Delegation
        • 4. UITableView
          • Lecture Handout
          • Lecture Demo
          • Project: UITableView
        • 5. UICollectionView
          • Lecture Handout
          • Lecture Demo
          • Project: UICollectionView
        • 6. Networking I
          • Lecture Handout
          • Lecture Demo
          • Project: Persistence
        • 7. Networking II
          • Lecture Handout
          • Lecture Demo
            • Message Board
          • Project: Networking II
        • 8. Swift UI
        • 9. CocoaPods
          • 🍫Lecture Handout
          • πŸ§‘β€πŸ³Lecture Demo
      • Cheat Sheets
        • Setting Up a New Xcode Project
        • Submitting Your Projects
        • Setting Up CocoaPods
    • 2022
      • SwiftUI
    • 2021
      • Adding Flare
      • Project: UIView Animations (Optional - Extra Credit)
      • UIView Animations
      • Xcode Tips and Tricks
    • 2019
      • Firebase
      • Persistence: UserDefaults
  • Swift Guide (ARCHIVED)
    • About this Textbook
    • Documentation
    • Constants and Variables
      • Variable Properties
      • Lazy and Static Variables
    • Functions
    • Ranges
    • Arrays
      • Basic Array Operations
      • Iteration and Enumeration
      • Advanced Array Operations
    • Tuples
    • Conditions and While Loops
    • For Loops
    • Enums and Switches
      • Enums with Associated Values
      • Indirect Enums
    • Classes and Structs
    • Optionals
    • Dictionaries
      • Dictionary Implementation
    • Closures
    • Constraints
    • Generics
    • Protocols
      • Protocols With Associated Types
    • Casting
    • Errors
    • Networking
      • Result
    • Inout
Powered by GitBook
On this page
  • Creating a NetworkManager Class
  • Creating a GET Request
  • Calling the Network Request
  • Using weak self

Was this helpful?

Export as PDF
  1. Chapters
  2. Networking II

GET Requests

Fall 2023 | Vin Bui

In this section, we will be using Alamofire and callbacks to perform network requests, specifically GET requests.

Creating a NetworkManager Class

It is common in iOS development to create a class that represents our backend calls. Let’s create this class and name it NetworkManager. Make sure to import Alamofire.

import Alamofire

class NetworkManager {
    /// Shared singleton instance
    static let shared = NetworkManager()
    
    // Prevent other instances from being created
    private init() { }
}

We create this static variable called shared that holds a singleton and make the initializer private. This guarantees that only one instance of this class is created. To access this variable, we can simply use NetworkManager.shared

Creating a GET Request

Inside of this NetworkManager class, we write functions to be called by our application. These functions will use Alamofire to send HTTP requests.

Assume there is a struct called Member that represents an AppDev member.

struct Member: Codable {
    let name: String
    let subteam: String
    let position: String
}

We can write the following code to fetch the AppDev roster.

// 1. Create the function
func fetchRoster(completion: @escaping ([Member]) -> Void) {
    // 2. Specify the endpoint
    let endpoint = "<Enter URL String Here>"
    
    // 3. Create a decoder
    let decoder = JSONDecoder()
    // decoder.dateDecodingStrategy = .iso8601 // Only if needed
    // decoder.keyDecodingStrategy = .convertFromSnakeCase // Only if needed
    
    // 4. Create the request
    AF.request(endpoint, method: .get)
        .validate()
        .responseDecodable(of: [Member].self, decoder: decoder) { response in
	    // 5. Handle the response
            switch response.result {
            case .success(let members):
                print("Successfully fetched \(members.count) members")
                completion(members)
            case .failure(let error):
                print("Error in NetworkManager.fetchRoster: \(error)")
            }
        }
}

Let’s break down this code.

  1. Create a function called fetchRoster that takes in a callback (completion handler) as an argument. This callback takes in an array of Member objects.

  2. Specify the endpoint which is the URL that we will call to fetch the data. We can test this with Postman.

  3. Create a decoder to decode the data. If our object contains a Date property, then we need to specify the date decoding strategy. If the JSON contains fields with snake_case, then we also need to specify the key decoding strategy.

  4. Create the request using Alamofire.

    • Pass in the endpoint and specify the method (.get for GET, .post for POST, etc).

    • Validate the request to ensure that the status code is 2xx and if the content type matches.

    • Decode the response to [Member] using the decoder we created in Step 3.

  5. Perform a switch statement on the response’s result.

    • If successful, pass to the callback the decoded response. A print statement is optional but recommended.

    • If failed, print an error statement about the error.

Note that we do not have to create the decoder inside of the function call. We can create a JSONDecoder object and store it as a property in our NetworkManager class to be used for all functions. The same can be applied to the endpoint variable containing a String value of our endpoint.

Calling the Network Request

There is a problem with this code that will be discussed in the next section below.

NetworkManager.shared.fetchRoster { fetchedMembers in
    // Do something with the data such as...
    self.members = fetchedMembers
    
    DispatchQueue.main.async {
        // Perform UI updates such as...
        self.collectionView.reloadData()
    }
}

We call the function that we just created inside of the NetworkManager class. Remember to use NetworkManager.shared. To access the value passed into the callback, we simply use the in keyword. For example, earlier we passed in an array of Member objects to the callback. In this case, fetchedMembers is holding the value that was passed in. We can call the variable whatever we want but it is very helpful to make it representative of the data.

Then, we do whatever we want with the data that we just fetched. If we are referencing a property outside of this function call, we will need to use self.

Next, if we need to perform any UI updates such as updating a collection view, we put that in a DispatchQueue.main.async block. This runs any code inside of the block on the main queue asynchronously. This is an advanced topic but the reason for this is so that the UI does not freeze while we are sending a network request.

Using weak self

Although the above code works, there is one major issue: we are retaining a strong reference to self inside of a closure which can cause retain cycles (causing memory leaks). To go around this, we will retain a weak reference to self inside of the closure and then unwrap a strong reference. We do this by adding [weak self] in our closure and using a guard let to unwrap a strong reference.

NetworkManager.shared.fetchRoster { [weak self] fetchedMembers in
    // Unwrap a strong reference
    guard let self = self else { return }

    // Do something with the data such as...
    self.members = fetchedMembers
    
    DispatchQueue.main.async {
	// Perform UI updates such as...
        self.collectionView.reloadData()
    }
}

You may have noticed that we also use weak when creating our delegate properties. This is an advanced topic that we will discuss later, but for now, make sure to use weak self every time we need to use self in our networking calls.

PreviousAlamofireNextPOST Requests

Last updated 1 year ago

Was this helpful?

🌍
2️⃣