Reputation: 3952
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
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 ItemListProvider
s 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 ItemListProvider
s have different instances of ItemListProvider
and do not have access to the same items.
Upvotes: 2