I want to load values saved in UserDefaults into another View

Asked 2 years ago, Updated 2 years ago, 39 views

When I tap the cell of TableVie in the VieController, I was able to display the information in the cell in the RegisterViewController in the previous question, but I would like to create a new ListViewController and tap the button in the upper right corner of the RegisterViewController.

The ViewController and ListViewController also allow TabBar movement.
I don't want to go back to Navigation from ListViewController because RegisterView is an accessory to ViewController, so I want to add cells with information to ListViewController but not transition after registration.

I will pass the value without transition, so I will pass the value only by UD, but I would like to use NSCoding because it is CustomCell's UD, so I would like to use NSKeyedUnarchiver.
When the Register item is addedListTapped, I put it in the ListView list and made TableViewcell listNameLabel and listDateLabel with xib, so I would like to display it on it, but it does not appear as a candidate, so please tell me how to write it.

ItemModelClass

class Item:NSObject,NSCoding {
    
    var name —String
    vardate:String
    
    init(name:String, date:String) {
        self.name = name as String
        self.date=date as String
    }
    
    funcencode (with code:NSCoder) {
        code.encode(self.name, forKey: "name")
        code.encode(self.date, forKey: "date")
    }
    
    required init?(coder:NSCoder) {
        self.name=coder.decodeObject(forKey: "name") as!String
        self.date=coder.decodeObject(forKey: "date") as!String
    }
}

ViewController

class ViewController:UIViewController {

    @IBOutlet weak variable:UITableView!
    variables: Item = Item()
    
    override func viewDidLoad(){
        super.viewDidLoad()
        
        table.register (TableViewCell.nib(), forCellReuseIdentifier: TableViewCell.identifier)

        table.delegate=self
        table.dataSource=self
        
        self.setupItems()
    }
    
    func setupItems(){
        items = [Items(name:"a", date:"1"), item(name:"b", date:"2", item(name:"c", date:"3", item(name:"d", date:"4", item(name:"e", date:"5"),]
    }
}
hereinafter abbreviated

RegisterViewController

class RegisterViewController:UIViewController {
    
    @IBOutlet weak var registeredNameLabel:UILabel!
    @IBOutlet weak var registeredDateLabel:UILabel!
    @IBOutlet var addListButton: UIBarButtonItem!
    
    // Item type
    variable item —Item!
    
    override func viewDidLoad(){
        super.viewDidLoad()
        
        // Buttons to add to MovieList
        addListButton=UIBarButtonItem(title: "Add to List", style: .plain, target:self, action:#selector(addListTapped(_:)))
        self.navigationItem.rightBarButtonItems= [addListButton]
        
        registeredNameLabel.text=item.name
        registeredDateLabel.text=item.date
    }
    
    @objc funcaddListTapped(_sender:UIBarButtonItem){
        print("Tapped")
        // Questions
}

ListViewController

classListViewController:UIViewController {
    
    var list: Item = [ ]
    var allList: Item = [ ]
    var selectedList: Item = [ ]
    
    @IBOutlet weak variable:UITableView!
    
    @ IBAction function segmentSelcted(_sender:UISegmentedControl){
        
        switch sender.selectedSegmentIndex{
        case0:
            list = allList
        case1:
            list = selectedList
        default:
            fatalError("case cannot cover)")
        }
        table.reloadData()
    }
    
    override func viewDidLoad(){
        super.viewDidLoad()

        table.delegate=self
        table.dataSource=self
        
        // Read UD
     
    }
}
extensionListViewController:UITableViewDelegate,UITableViewDataSource{
    
    functableView(_tableView:UITableView, numberOfRowsInSection section:Int) - > Int{
        list.count
    }
    
    functableView(_tableView:UITableView, cellForRowAtindexPath:IndexPath) - >UITableViewCell{
        letcell=tableView.dequeueReusableCell (with Identifier: ListTableViewCell.identifier, for:indexPath) as!ListTableViewCell
        cell.setcell (item:list [indexPath.row])
        return cell
    }
}

ListTableViewCell

 func setcell(item:Item){
        self.listNameLabel.text=item.name as String
        self.listDateLabel.text=item.date as String
    }

swift ios

2022-09-30 19:49

1 Answers

Now, as I wrote in the comment, it's not particularly difficult to create Singleton, so the answer to the question that says "Save with UserDefaults" is a bit of a pushover.

  • Using Singleton without UserDefaults

I would like to write an answer with this policy.

Now, for those who have just started iOS programming, defining their own classes (other than UIViewController and UIView) may seem difficult to understand, but if you get used to it rather than learn it, you'll find it not that difficult.

Basically, all you have to do is write classes in this format.

class MyData{
    // Define a singleton named for `UserDefaults`
    staticlet standard=MyData()

    // Other required features are described
    //...
}

As far as the comments are concerned,

  • Operate the data displayed in ListViewController in RegisterViewController

This seems to be the main focus, so we will move allList and selectedList of ListViewController to MyData.

class MyData{
    // Define a singleton named for `UserDefaults`
    staticlet standard=MyData()

    // Variables accessed by multiple view controllers are summarized together with highly relevant variables
    private(set)var allList: Item = [ ]
    private(set) var selectedList: Item = [ ]
    
    funcadd(_item:Item, isSelected:Bool=false){
        allList.append(item)
        if isSelected {
            selectedList.append(item)
        }
    }
    
    // To put a part of `allList` into `selectedList`, define it here if you need any action
    //...
}
  • private(set) is attached because it can be inconsistent if array operations are performed at various locations without permission.

  • Singleton property names such as shared and default may be popular(?), but UserDefaults which also use Singleton seems to have no resistance, so it is set to standard.

  • Any information you can handle on your computer is "data", so MyData is a pretty bad naming sense.Please use a better name for the actual app.

private(set) is attached because it can be inconsistent if array operations are carried out in various places.

shared and default are popular properties names for Singleton, but there seems to be no resistance to using UserDefaults, which also uses Singleton, so it is set to standard.

Any information you can handle on your computer is "data", so MyData is a pretty bad naming sense.Please use a better name for the actual app.

Using MyData above, the RegisterViewController looks like this:

  • Some parts of the comment are left in the comments to make it easier to understand where to delete (and move), but if you want to try it, please delete it quickly.
class RegisterViewController:UIViewController {
    
    @IBOutlet weak var registeredNameLabel:UILabel!
    @IBOutlet weak var registeredDateLabel:UILabel!
    @IBOutlet var addListButton: UIBarButtonItem!
    
    // Item type → Avoid Implicitly Unwrapped as much as possible
    varitem —Item?//<-
    
    override func viewDidLoad(){
        super.viewDidLoad()
        
        // Buttons to add to MovieList
        addListButton=UIBarButtonItem(title: "Add to List", style: .plain, target:self, action:#selector(addListTapped(_:)))
        self.navigationItem.rightBarButtonItems= [addListButton]
        
        // It is better to process data from other screens with 'viewWillAppear' instead of 'viewDidLoad'
//        registeredNameLabel.text=item?.name
//        registeredDateLabel.text=item?.date
    }
    
    override func viewWillAppear(_animated:Bool){
        super.viewWillAppear(animated)
        
        guard letter item=item else {
            print("item is nil")
            // Other error handling if necessary
            return
        }
        
        // Process data from other screens here
        registeredNameLabel.text=item.name
        registeredDateLabel.text=item.date
    }
    
    @objc funcaddListTapped(_sender:UIBarButtonItem){
        print("Tapped")
        // Questions
        guard letter item=item else {
            print("item is nil")
            // Other error handling if necessary
            return
        }
        // Perform data operations only through the 'MyData' method
        MyData.standard.add (item, isSelected: false)
    }
}
    You have changed the
  • item data type from Item! to Item?. It is recommended that you remember that you do not use Implicitly Unwrapped Optional (!) except for a regular pattern like @IBOutlet.

Similarly, replacing the ListViewController with the MyData version will look like this.

classListViewController:UIViewController {
    
    // Instead of copying arrays whenever there is a change, "calculate" one of the necessary arrays each time
    var list: Item {
        switch segmentedControl.selectedSegmentIndex{
        case0:
            return MyData.standard.allList
        case1:
            return MyData.standard.selectedList
        default:
            fatalError("case cannot cover)")
        }
    }
    // Move variables accessed by multiple view controllers to 'MyData' with highly relevant variables
//    var allList: Item = [ ]
//    var selectedList: Item = [ ]
    
    @IBOutlet weak variable:UITableView!
    // Add IBOutlet to make `list` a calculated property, keep it connected correctly
    @IBOutlet weak var segmentedControl:UISegmentedControl!
    
    @ IBAction function segmentSelcted(_sender:UISegmentedControl){
        Making //`list` a computational property eliminates the need to copy arrays here
//        switch sender.selectedSegmentIndex{
//        case0:
//            list = allList
//        case1:
//            list = selectedList
//        default:
//            fatalError("case cannot cover)")
//        }
        // However, `table.reloadData()` is required
        table.reloadData()
    }
    
    override func viewDidLoad(){
        super.viewDidLoad()
        
        table.delegate=self
        table.dataSource=self
        
        // All the necessary data is stored in 'MyData' so there is no need to load it at this time.
    }
    
    If you do not call `table.reloadData()` in // `viewWillAppear(_:)`, the screen may not be updated.
    override func viewWillAppear(_animated:Bool){
        super.viewWillAppear(animated)
        
        table.reloadData()
    }
}
  • Among the above, rewriting the list to computational properties is not a must, and I can't say "better" from any point of view, but the condition of "must update multiple arrays consistently" is very difficult to manage as the program grows.

I omitted the part of the code that was omitted in the question, but I don't think it's necessary to make such a big correction. What do you think?

It may be a binding issue that requires the use of UserDefaults, but if not, I would definitely like you to try it.


2022-09-30 19:49

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.