Thank you for the reply! I am following this tutorial here if this helps you understand my problem more, https://code.tutsplus.com/tutorials/ios-from-scratch-with-swift-building-a-shopping-list-application-1--cms-25515
It has grocery items in the array
Here is the code for the Item class, let me know if you need other code. Sorry I am a beginner so I'm unsure what is needed.
import UIKit
class Item: NSObject, NSCoding {
func encode(with coder: NSCoder) {
coder.encode(uuid, forKey: "uuid")
coder.encode(name, forKey: "name")
coder.encode(price, forKey: "price")
coder.encode(inShoppingList, forKey: "inShoppingList")
}
var uuid: String = NSUUID().uuidString
var name: String = ""
var price: Float = 0.0
var inShoppingList = false
// MARK: -
// MARK: Initialization
init(name: String, price: Float) {
super.init()
self.name = name
self.price = price
}
// MARK: -
// MARK: NSCoding Protocol
required init?(coder decoder: NSCoder) {
super.init()
if let archivedUuid = decoder.decodeObject(forKey:)("uuid") as? String {
uuid = archivedUuid
}
if let archivedName = decoder.decodeObject(forKey:)("name") as? String {
name = archivedName
}
price = decoder.decodeFloat(forKey:)("price")
inShoppingList = decoder.decodeBool(forKey:)("inShoppingList")
}
func encodeWithCoder(coder: NSCoder) {
coder.encode(uuid, forKey: "uuid")
coder.encode(name, forKey: "name")
coder.encode(price, forKey: "price")
coder.encode(inShoppingList, forKey: "inShoppingList")
}
}
Post
Replies
Boosts
Views
Activity
Thanks for the help, im getting a few more errors now which I put comments next to so you can see
let ud = UserDefaults.standard
if !ud.bool(forKey: "UserDefaultsSeedItems") {
if let filePath = Bundle.main.path(forResource: "seed", ofType: "plist"), let seedItems = NSArray(contentsOfFile: filePath) {
print("seedItems", seedItems)
// Items
var items = [Item]()
// Create List of Items
for seedItem in seedItems {
let name = seedItem.name //ERROR Value of type 'Any' has no member 'name'
let price = seedItem.price //ERROR Value of type 'Any' has no member 'price'
print("\(name) - \(price)")
// Create Item
let item = Item(name: name, price: price)
// Add Item
items.append(item)
}
}
print(items) //ERROR Cannot find 'items' in scope
if let itemsPath = pathForItems() {
// Write to File
if NSKeyedArchiver.archiveRootObject(items, toFile: itemsPath) { //ERROR Cannot find 'items' in scope
ud.set(true, forKey: "UserDefaultsSeedItems")
}
}
}
}
}
Sorry I am still new so some of the questions are hard for me to understand, that worked perfectly thank you so much for all the help!!!!
Thank you so much!! that fixed those errors. I am now getting a caution that says: "archiveRootObject(_:toFile:)' was deprecated in iOS 12.0: Use +archivedDataWithRootObject:requiringSecureCoding:error: and -writeToURL:options:error: instead"
Are you able to help with this?
// Write to File
if NSKeyedArchiver.archiveRootObject(items, toFile: itemsPath) {
ud.set(true, forKey: "UserDefaultsSeedItems")
}
}
Thanks for the reply, I have used google and fixed all the other errors due to the API being deprecated. This is the last error I have that I wasn't able to fix.
I have added this code and i'm getting these errors now
extension Notification.Name { // Declaration is only valid at file scope
public static let kShoppingChanged = Notification.Name("ShoppingListDidChangeNotification")
}
NotificationCenter.default.addObserver(self, #selector: Notification(updateShoppingList(_:)), name: .kShoppingChanged, object: nil) //'default' label can only appear inside a 'switch' statement
so I moved the declaration to the top and now it looks like this
NotificationCenter.default.addObserver(self, selector: #selector(updateShoppingList(_:)), name: .kShoppingChanged, object: nil)
and the error is Cannot find 'updateShoppingList' in scope
this is the updateShoppingList function:
func updateShoppingList(notification: NSNotification) {
loadItems()
}
Thank you for the reply, I have added this line but now I am getting this error, Type 'UIPushBehavior' has no member 'addItem(sender:)'
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(UIPushBehavior.addItem(sender:)))
Thank you for all the help everyone!
Perfect that worked great thank you!
Now when I click save I get the same error appears "[Shopping_List.AddItemViewController save:]: unrecognized selector sent to instance ..."
//
// AppDelegate.swift
// Shopping List
//
// Created by Deepak Prasad on 1/10/22.
//
import UIKit
protocol AddItemViewControllerDelegate {
func controller(controller: AddItemViewController, didSaveItemWithName name: String, andPrice price: Float)
}
class AddItemViewController: UIViewController {
@IBOutlet var nameTextField: UITextField!
@IBOutlet var priceTextField: UITextField!
var delegate: AddItemViewControllerDelegate?
// MARK: -
// MARK: View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: -
// MARK: Actions
@IBAction func cancel(sender: UIBarButtonItem) {
dismiss(animated: true, completion: nil)
}
@IBAction func save(sender: UIBarButtonItem) {
if let name = nameTextField.text, let priceAsString = priceTextField.text, let price = Float(priceAsString) {
// Notify Delegate
delegate?.controller(controller: self, didSaveItemWithName: name, andPrice: price)
// Dismiss View Controller
dismiss(animated: true, completion: nil)
}
}
}
I don't recieve the runtime error anymore, however the item does not save into the shopping list
//
// AppDelegate.swift
// Shopping List
//
// Created by Deepak Prasad on 1/10/22.
//
import UIKit
extension Notification.Name { // Declaration is only valid at file scope
public static let kShoppingChanged = Notification.Name("ShoppingListDidChangeNotification")
}
class ShoppingListViewController: UITableViewController {
let CellIdentifier = "Cell Identifier"
var items = [Item]() {
didSet {
buildShoppingList()
}
}
var shoppingList = [Item]() {
didSet {
tableView.reloadData()
}
}
// MARK: -
// MARK: View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
// Set Title
title = "Shopping List"
// Load Items
loadItems()
// Register Class
tableView.register(UITableViewCell.classForCoder(), forCellReuseIdentifier: CellIdentifier)
// Add Observer
NotificationCenter.default.addObserver(self, selector: #selector(updateShoppingList), name: .kShoppingChanged, object: nil) //'default' label can only appear inside a 'switch' statement
}
// MARK: -
// MARK: Table View Data Source Methods
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return shoppingList.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// Dequeue Reusable Cell
let cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier, for: indexPath as IndexPath)
// Fetch Item
let item = shoppingList[indexPath.row]
// Configure Table View Cell
cell.textLabel?.text = item.name
return cell
}
// MARK: -
// MARK: Notification Handling
@objc func updateShoppingList(notification: NSNotification) {
loadItems()
}
// MARK: -
// MARK: Helper Methods
func buildShoppingList() {
shoppingList = items.filter({ (item) -> Bool in
return item.inShoppingList
})
}
private func loadItems() {
if let filePath = pathForItems(), FileManager.default.fileExists(atPath: filePath) {
if let archivedItems = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? [Item] {
items = archivedItems
}
}
}
private func pathForItems() -> String? {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
if let documents = paths.first, let documentsURL = NSURL(string: documents) {
return documentsURL.appendingPathComponent("items")?.path
}
return nil
}
}