0

What I am trying to do in general:
1. Generate a table with all registered users (stored in core data).
2. Then allow the user to select a registered-user by pressing on a row.
3. When user selects a row, a new page opens with detailed user info.

I am trying to solve this by:
1. First storing the UserName from the given cell into "UserDefaults.standard".
2. Then on the second page, accessing the stored UserName from "UserDefaults.standard" and using that dynamic value to retrieve Core Data for more detailed user information.

Problems:
I am certain that the data that is passed into "UserDefaults.standard" is the full table and not data from a specific cell. I have seen this by using "Print()", is actually show all of the rows instead of only the one row that is selected.
So the UserName that is then generated into the second page is a random row that is further down (see picture).
enter image description here



    public class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

 var userNameobject : [NSManagedObject] = []

    @IBAction func pushTwo(_ sender: Any) {
    }

    @IBOutlet weak var usersList: UITableView!

    override public func viewDidLoad() {
        super.viewDidLoad()

        usersList.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    }

    public override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
            return }

        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Users")

        do {
                userNameobject = try managedContext.fetch(fetchRequest)

                                            } catch let error as NSError {
                                                print("Could not fetch. \(error), \(error.userInfo)")
                                            }
    }

      public func tableView(_ usersList: UITableView, numberOfRowsInSection section: Int) -> Int {
        return userNameobject.count

    }

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

            let person = userNameobject[indexPath.row]
            let cell = usersList.dequeueReusableCell(withIdentifier: "CellTwo", for: indexPath) as UITableViewCell
                cell.textLabel?.text = person.value(forKeyPath: "userName") as? String

            // STORE USERNAME
            let defaults = UserDefaults.standard
            defaults.set(person.value(forKeyPath: "userName"), forKey: "userNameDefault")

            return cell

    }
}

    public func tableView(_ userList: UITableView, didSelectRowAt indexPath: IndexPath)
    {

    }
Swift123
  • 53
  • 6
  • 2
    Never use `UserDefaults` to share data between controllers. Use a segue and pass the `NSManagedObject` at the index path. And create a `NSManagedObject` subclass from the entity, this is more convenient. And why `value(forKeyPath`? There is a `key` but no `path`. – vadian Sep 10 '18 at 12:16
  • Why should I never user UserDafults? Can you provide med with a segue solution compatible with my code above so I can try it out? – Swift123 Sep 10 '18 at 12:20
  • 4
    `UserDefaults` is the wrong place for temporary data. Create a new ***Master-Detail App*** project in Xcode, there you get almost the entire code for free. – vadian Sep 10 '18 at 12:23
  • PS: And – another ***never*** – never `guard` `AppDelegate`. Force unwrap it! Your app won't even reach this line if `AppDelegate` was missing. – vadian Sep 10 '18 at 12:36
  • I really recommend that you read [this answer](https://stackoverflow.com/a/31934786/3985749) to a similar question. – pbasdf Sep 11 '18 at 06:50

2 Answers2

0

1- Connect segue source to VC not to cell

func tableView(_ userList: UITableView, didSelectRowAt indexPath: IndexPath)
{ 
   self.performSegue(withIdentifier: "toSecond", sender:userNameobject[indexPath.row])
}

2- Implement

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    if let des = segue.destination as? SecondVC {
         des.person = sender as! NSManagedObject
    }

}

3-

class SecondVC:UIViewController {

    var person: NSManagedObject?

}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • Thank you for the solution. I have implemented this and it seems to be working. The only problem is that I cannot see if the value for that specific row is passed. The only value I get when printing is "[]". How to you propose I convert this object to String so I get generate the user name? – Swift123 Sep 10 '18 at 13:21
-2

I solved this by making giving "Sender:" the exact same line that generates each given cell the User Name. It works perfectly now!

public func tableView(_ userList: UITableView, didSelectRowAt indexPath: IndexPath)
{
    let person = userNameobject[indexPath.row]
    let two =  person.value(forKeyPath: "userName") as? String
    self.performSegue(withIdentifier: "userLinkSegue", sender: two!)

    print(two!)

     // STORE USERNAME
     let defaults = UserDefaults.standard
     defaults.set(two!, forKey: "userNameDefault")

}
Swift123
  • 53
  • 6