How to access and refresh a UITableView from another class in Swift

后端 未结 4 504
清歌不尽
清歌不尽 2021-01-03 09:24

I have a tab bar application and a tab whose view controller is controlled by a UITableView class. I have a class that is used to download data from the server that then sav

相关标签:
4条回答
  • 2021-01-03 09:58

    I think the easiest way to do what you want to do is use a delegate.

    protocol UpdateDelegate {
        func didUpdate(sender: Updates)
    }
    

    So in your updates class, where you want to refresh the table view you would call the delegates didUpdate function. (You will have to set the delegate before it starts the update for the method to be called.) The weak keyword is important, if it isn't there, neither of the classes will be GC'd, which will lead to memory leaks.

    class Updates {
       weak var delegate: UpdateDelegate?
    
       ...
    
        //Indicates progress finished
        self.delegate.didUpdate(self)
    

    In your tableView class you would subscribe to that delegate by adding UpdateDelegate to the top of the class

    class ConnectTableVC: UITableViewController, UpdateDelegate {
        ...
    
        let updates = Updates()
        updates.delegate = self
    
        ...
        func didUpdate(sender: updates) {
           dispatch_async(dispatch_get_main_queue()) {
              self.tableView.reloadData()
           }
        }
     }
    

    I would recommend against using the NSNotificationCenter, the biggest reason is anyone anywhere can listen to the notification (which might be unlikely in your case, but it is still worth noting).

    0 讨论(0)
  • 2021-01-03 10:09

    For Swift 3

    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "newDataNotificationForItemEdit"), object: nil)
    
    NotificationCenter.default.addObserver(self, selector: #selector(self.shouldReload), name: NSNotification.Name(rawValue: "newDataNotificationForItemEdit"), object: nil)
    
    func shouldReload() {
        self.tableView.reloadData()
    }
    
    0 讨论(0)
  • 2021-01-03 10:22

    There are many ways you can do this. The most standard way is to use delegation. Delegation is a very common pattern in iOS, you are using it with UITableViewDataSource. Your view controller is the delegate of the UITableView, meaning it conforms to the UITableViewDataSource protocol. So what you should do is create a protocol for your Updates class like this:

    protocol UpdatesDelegate {
        func didFinishUpdates(finished: Bool)
    }
    

    Your Updates class would have a delegate property that conforms to this protocol:

    class Updates {
        var delegate: UpdatesDelegate?
    

    Then you put this line where the //indicates progress finished comment was:

    self.delegate?.didFinishUpdates(finished: true)
    

    Your ConnectTableViewController would conform to the protocol and reload the table view from there:

    extension ConnectTableViewController: UpdatesDelegate {
        func didFinishUpdates(finished: Bool) {
            guard finished else {
                // Handle the unfinished state
                return 
            }
            self.tableView.reloadData()
        }
    }
    

    Where ever you created your instance of the Updates class, be sure to set the delegate property to your ConnectTableViewController.

    P.S. Your classes need to start with an uppercase letter. I've edited your question to reflect this.

    0 讨论(0)
  • 2021-01-03 10:23

    You can use protocol or NSNotificationCenter

    Example of NSNotificationCenter :

    From the UIViewController that downloads the data, you can post a notification after finishing downloading the data and tell other objects that there is new data:

    NSNotificationCenter.defaultCenter().
                        postNotificationName("newDataNotif", object: nil)
    

    And any other object that wants to listen to this notification should register to observe (in your case the UITableViewController):

    NSNotificationCenter.defaultCenter().
                         addObserver(self, #selector(shouldReload), 
                         name:"newDataNotif", object: nil)
    

    and then you need to implement the method to be called when receive the notification:

    func shouldReload() {
      self.tableView.reloadData()
    }
    

    Note that the notification can send data also of type [NSObject : AnyObject]? example:

    NSNotificationCenter.defaultCenter().
                         postNotificationName("newDataNotif", 
                         object: nil, userInfo: ["data":[dataArray]])
    

    And the observer will be like:

    NSNotificationCenter.defaultCenter().
                         addObserver(self, #selector( shouldReload(_:)),
                         name:"newDataNotif", object: nil)
    

    And the method like:

    func shouldReload(notification:NSNotification) {
      println(notification.userInfo)
    }
    

    and finally in your deinit you should remove observer :

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
    0 讨论(0)
提交回复
热议问题