I used the delegate option using UserDefaults to store and load arrays into a table view and it works good but I am trying to use the singleton database option now.I have everything in my app working right except when I add a player to myRoster or draftOrder it doesn't add the player.My data:import Foundation
import UIKit
class PlayerData: Codable {
var num: Int = 0
var name: String = ""
var team: String = ""
var position: String = ""
var strikeThrough: Bool = false
var color: Bool = false
var accessory: Bool = false
var rosterPosition: Int = -1
var draftPosition: Int = -1
init(num: Int, name: String, team: String, position: String) {
self.num = num
self.name = name
self.team = team
self.position = position
}
}
var objectsArray = [PlayerData]()
var myRoster: [PlayerData] = []
var draftOrder: [PlayerData] = []
class Database {
static let shared = Database()
fileprivate var allPlayers: [PlayerData]
fileprivate func playerDataURL() -> URL {
let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in:.userDomainMask).last!
return documentDirectoryURL.appendingPathComponent("playerData.json")
}
fileprivate func playersReadFromDisk() -> [PlayerData]? {
let filePlayerURL = playerDataURL()
guard FileManager.default.fileExists(atPath: filePlayerURL.path) else {
return nil
}
do {
let fileContents = try Data(contentsOf: filePlayerURL)
let list = try JSONDecoder().decode([PlayerData].self, from: fileContents)
return list
} catch let error as NSError {
NSLog("Error reading file: \(error.localizedDescription)")
}
return nil
}
fileprivate func playersWriteToDisk() {
do {
let data = try JSONEncoder().encode(allPlayers)
try data.write(to: playerDataURL())
} catch let error as NSError {
NSLog("Error reading file: \(error.localizedDescription)")
}
}
func changeMade() {
playersWriteToDisk()
}
func playerList(position: String) -> [PlayerData] {
return allPlayers.filter({ $0.position == position })
}
func rosterList() -> [PlayerData] {
let rosteredPlayers = allPlayers.filter { ($0.rosterPosition >= 0)}
return rosteredPlayers.sorted(by: { $0.rosterPosition < $1.rosterPosition })
}
func draftList() -> [PlayerData] {
let draftedPlayers = allPlayers.filter({ $0.draftPosition >= 0 })
return draftedPlayers.sorted(by: { $0.draftPosition < $1.draftPosition })
}
func addToRosterList(player: PlayerData) {
let maxRosteredIndex = allPlayers.map({ $0.rosterPosition }).max()!
player.rosterPosition = maxRosteredIndex + 1
}
func addToDraftList(player: PlayerData) {
let maxDraftedIndex = allPlayers.map({ $0.draftPosition }).max()!
player.draftPosition = maxDraftedIndex + 1
}
func removeFromRosterList(player: PlayerData) {
let currentRosterPosition = player.rosterPosition
player.rosterPosition = -1 // No longer on the rosterList. Gets all players on roster at a higher index.
let higherNumberedRosterPlayers = allPlayers.filter({ $0.rosterPosition > currentRosterPosition}) // Their rosterPositions have now gone down by one.
for otherPlayer in higherNumberedRosterPlayers {
otherPlayer.rosterPosition -= 1 // Decrease position by 1.
}
}
init() {
allPlayers = [PlayerData]()
if let playerList = playersReadFromDisk() {
allPlayers = playerList
} else {
allPlayers = [
// Quarterbacks
PlayerData(num: 1, name: "Patrick Mahomes", team: "KC", position: "QB"),
PlayerData(num: 2, name: "Deshaun Watson", team: "HOU", position: "QB"),
PlayerData(num: 3, name: "Aaron Rodgers", team: "GB", position: "QB"),
PlayerData(num: 4, name: "Matt Ryan", team: "ATL", position: "QB"),
PlayerData(num: 5, name: "Baker Mayfield", team: "CLE", position: "QB"),
PlayerData(num: 6, name: "Carson Wentz", team: "PHI", position: "QB"),
PlayerData(num: 7, name: "Jared Goff", team: "LAR", position: "QB"),
PlayerData(num: 8, name: "Cam Newton", team: "CAR", position: "QB"),
PlayerData(num: 9, name: "Andrew Luck", team: "IND", position: "QB"),
PlayerData(num: 10, name: "Drew Brees", team: "NO", position: "QB"),
PlayerData(num: 11, name: "Ben Roethlisberger", team: "PIT", position: "QB"),
PlayerData(num: 12, name: "Dak Prescott", team: "DAL", position: "QB"),
PlayerData(num: 13, name: "Russell Wilson", team: "SEA", position: "QB"),
PlayerData(num: 14, name: "Kyler Murray", team: "ARI", position: "QB"),
PlayerData(num: 15, name: "Tom Brady", team: "NE", position: "QB"),
PlayerData(num: 16, name: "Lamar Jackson", team: "BAL", position: "QB"),
PlayerData(num: 17, name: "Mitchell Trubisky", team: "CHI", position: "QB"),
PlayerData(num: 18, name: "Jameis Winston", team: "TB", position: "QB"),
PlayerData(num: 19, name: "Philip Rivers", team: "LAC", position: "QB"),
PlayerData(num: 20, name: "Kirk Cousins", team: "MIN", position: "QB")
]
}
}
}myRoster view controllerimport UIKit
class MyTeam_2019_2020: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
myRoster = Database.shared.rosterList()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myRoster.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let player = myRoster[indexPath.row]
let str = "\(player.name), \(player.team) - \(player.position)"
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "\(indexPath.row+1). \([str])"
cell.textLabel?.adjustsFontSizeToFitWidth = true
cell.textLabel?.font = UIFont.systemFont(ofSize: 22)
return cell
}
func save() {
let defaults = UserDefaults.standard
defaults.set(myRoster, forKey: "saveMyRoster")
defaults.set(draftOrder, forKey: "saveDraftOrder")
}
@IBOutlet weak var myTeam_20192020: UILabel!
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
}Top_30_Quartebacks view controllerimport UIKit
@available(iOS 11.0, *)
class Top_30_Quarterbacks: UIViewController, UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objectsArray.count
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
objectsArray = Database.shared.playerList(position: "QB")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let num = objectsArray[indexPath.row].num
let name = objectsArray[indexPath.row].name
let team = objectsArray[indexPath.row].team
cell.textLabel?.text = "\(num). \(name), \(team)"
cell.textLabel?.adjustsFontSizeToFitWidth = true
cell.textLabel?.font = UIFont.systemFont(ofSize: 22)
if objectsArray[indexPath.row].strikeThrough == false && objectsArray[indexPath.row].accessory == false && objectsArray[indexPath.row].color == false {
cell.textLabel?.text = "\(num). \(name), \(team)"
cell.textLabel?.attributedText = noStrikeThroughText("\(num). \(name), \(team)")
cell.accessoryType = UITableViewCell.AccessoryType.none
cell.backgroundColor = .none
}
else if objectsArray[indexPath.row].strikeThrough == true && objectsArray[indexPath.row].accessory == true && objectsArray[indexPath.row].color == true {
cell.textLabel?.text = "\(num). \(name), \(team)"
cell.textLabel?.attributedText = strikeThroughText("\(num). \(name), \(team)")
cell.accessoryType = UITableViewCell.AccessoryType.checkmark
cell.backgroundColor = .systemGray3
} else {
cell.textLabel?.text = "\(num). \(name), \(team)"
cell.textLabel?.attributedText = strikeThroughText("\(num). \(name), \(team)")
cell.accessoryType = UITableViewCell.AccessoryType.none
cell.backgroundColor = .systemGray2
}
return cell
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let cell = self.top30QuarterbacksTable.cellForRow(at: indexPath)
let str: String = (cell?.textLabel!.text)!
let player = objectsArray[indexPath.row].name
if cell?.textLabel?.attributedText == strikeThroughText(str) {
strikeThroughTextBool = true
} else {
strikeThroughTextBool = false
}
if strikeThroughTextBool == false {
let add = UIContextualAction(style: .normal, title: "Add") { (contextualAction, view, actionPerformed: @escaping (Bool) -> Void) in
let alert = UIAlertController(title: "Add Player", message: "Are you sure you want to add '\(player)' to your roster?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { (alertAction) in
actionPerformed(false)
}))
alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { (alertAction) in
self.addPlayer(index: indexPath)
let okayAlert = UIAlertController(title: "Player Added!", message: "You added '\(player)' to your roster?", preferredStyle: .alert)
okayAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (alertAction) in
actionPerformed(true)
}))
self.present(okayAlert, animated: true)
}))
self.present(alert, animated: true)
}
add.backgroundColor = .systemGreen
let taken = UIContextualAction(style: .normal, title: "Taken") { (contextualAction, view, actionPerformed: @escaping (Bool) -> Void) in
let alert = UIAlertController(title: "Player Taken", message: "Are you sure you want to mark '\(player)' as taken and not available?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { (alertAction) in
actionPerformed(false)
}))
alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { (alertAction) in
self.markAsTaken(index: indexPath)
let okayAlert = UIAlertController(title: "Taken Player", message: "You marked '\(player)' as taken and not available!", preferredStyle: .alert)
okayAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (alertAction) in
actionPerformed(true)
}))
self.present(okayAlert, animated: true)
}))
self.present(alert, animated: true)
}
taken.backgroundColor = .systemRed
let config = UISwipeActionsConfiguration(actions: [taken, add])
config.performsFirstActionWithFullSwipe = false
return config
} else {
let undo = UIContextualAction(style: .normal, title: "Undo") { (contextualAction, view, actionPerformed: @escaping (Bool) -> Void) in
let alert = UIAlertController(title: "Undo", message: "Are you sure you want to undo the action for '\(player)'?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: { (alertAction) in
actionPerformed(false)
}))
alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { (alertAction) in
self.removePlayer(index: indexPath)
let okayAlert = UIAlertController(title: "Action Undone", message: "The previous action for '\(player)' has been undone!", preferredStyle: .alert)
okayAlert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (alertAction) in
actionPerformed(true)
}))
self.present(okayAlert, animated: true)
}))
self.present(alert, animated: true)
}
undo.backgroundColor = .systemBlue
let config = UISwipeActionsConfiguration(actions: [undo])
config.performsFirstActionWithFullSwipe = false
return config
}
}
func addPlayer(index: IndexPath) {
let player = objectsArray[index.row]
player.strikeThrough = true
player.accessory = true
player.color = true
Database.shared.addToRosterList(player: player)
Database.shared.addToDraftList(player: player)
top30QuarterbacksTable.reloadData()
Database.shared.changeMade()
}
func markAsTaken(index: IndexPath) {
let player = objectsArray[index.row]
player.strikeThrough = true
player.color = true
player.accessory = false
top30QuarterbacksTable.reloadData()
Database.shared.changeMade()
}
func removePlayer(index: IndexPath) {
let player = objectsArray[index.row]
player.strikeThrough = false
player.color = false
player.accessory = false
top30QuarterbacksTable.reloadData()
Database.shared.changeMade()
}
@IBOutlet weak var top30QuarterbacksTable: UITableView!
@IBOutlet var view1: UIView!
@IBOutlet weak var view2: UIView!
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}