Laurence Wingo
Laurence Wingo

Reputation: 3952

Better Understanding Reference vs. Value Types in Swift

After reading the Swift documentation and various online tutorials, it still a little hard to wrap my head around reference types versus value types.

I'm following a tutorial from a Swift TDD book to understand OOP architecture in Swift. The tutorial is based on creating a to do list app. In the beginning of the book we created a struct to resemble each to do item. Next we created an class called ItemManger to manage the array that holds to do items and another array to hold checked off to do items. I can understand the idea of to do items being made from a struct because its a value type which creates a new instance every time its instantiated and the itemManager being made from a class since we only need one itemManger to keep track of to do items. The question that I've come up with is when we create an instance of the ItemManager type (which is a class) inside another class or view controller, will this refer to the same class we created before in which we'll be able to access the to do item arrays?

Before this book, I assumed in order to keep track of variables from a class, we have to mark them as static.

Here is the itemManager class:

import Foundation

class ItemManager {

    var toDoCount: Int {return toDoItems.count }

    var doneCount: Int {return doneItems.count }

    private var toDoItems: [ToDoItem] = []

    private var doneItems: [ToDoItem] = []


    func add(item: ToDoItem) {

        if !toDoItems.contains(item){
            toDoItems.append(item)
        }

    }

    func checkItem(at index: Int) {
        let item = toDoItems.remove(at: index)
        doneItems.append(item)
    }

    func doneItem(at index: Int) -> ToDoItem{
        return doneItems[index]
    }

    func item(at index: Int) -> ToDoItem{
        return toDoItems[index]
    }

    func removeAll(){

        toDoItems.removeAll()
        doneItems.removeAll()
    }

}

Here is another class where we create an instance variable of the ItemManager type:

import UIKit

enum Section: Int {
    case toDo
    case done
}

class ItemListDataProvider: NSObject, UITableViewDataSource, UITableViewDelegate {

    var itemManager: ItemManager?


    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {


        guard let itemManager = itemManager else{return 0}

        guard let itemSection = Section(rawValue: section)else{ fatalError() }

        let numberOfRows: Int

        switch itemSection {
        case .toDo:
            numberOfRows = itemManager.toDoCount
        case .done:
            numberOfRows = itemManager.doneCount
        }

        return numberOfRows
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "ItemCell", for: indexPath) as! ItemCell

        guard let itemManager = itemManager else { fatalError() }

        guard let section = Section(rawValue: indexPath.section) else { fatalError() }

        let item: ToDoItem

        switch section {
        case .toDo:
            item = itemManager.item(at: indexPath.row)
        case .done:
            item = itemManager.doneItem(at: indexPath.row)
        }

        cell.configCell(with: item)

        return cell
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
}

Upvotes: 0

Views: 108

Answers (1)

naglerrr
naglerrr

Reputation: 2854

In the code you posted you are not creating an instance of ItemManager.

Here is another class where we create an instance variable of the ItemManager type:

ItemListDataProvider can have a ItemManager but it does not create one. Creating an instance of a class works by calling it's constructor like this:

// Creates an instance of ItemManager and assigns it to itemManager
let itemManager = ItemManager()  

Because you did not show where your item manager is created, the question

will this refer to the same class we created before in which we'll be able to access the to do item arrays?

can not really be answered. Where did you create an instance of ItemManager and what did you do with it?

Here is an example:

let itemManagerA = ItemManager()

let itemListDataProviderA() = ItemListDataProvider()
itemListDataProviderA.itemManager = itemManagerA

let itemListDataProviderB() = ItemListDataProvider()
itemListDataProviderB.itemManager = itemManagerA

In this example both ItemListProviders have the same ItemManager and thus have access to the same item arrays.

On the contrary if you are doing something like this:

let itemManagerA = ItemManager()
let itemListDataProviderA() = ItemListDataProvider()
itemListDataProviderA.itemManager = itemManagerA

let itemManagerB = ItemManager() // <-- This creates a SECOND instance of ItemManager
let itemListDataProviderB() = ItemListDataProvider()
itemListDataProviderB.itemManager = itemManagerB // <-- We use the SECOND instance instead of the first one for itemListDataProviderB

both ItemListProviders have different instances of ItemListProvider and do not have access to the same items.

Upvotes: 2

Related Questions