Nimit Pattanasri
Nimit Pattanasri

Reputation: 1602

Best practice to send "reloading" signal to UITableView from one view to another

My goal is to notify a UITableView to refresh itself every time some configurations have changed. The problem is that the configuration view is "not" on the same view that produces the signal. (Yes, I used Tabbed Application.)

Currently I use a sort of global variable in AppDelegate for detecting the change in one view, and do the check in another view. This is fine but the code is not readable as it is so tightly coupling. Is there an elegant method for doing this? Do I miss something in this programming framework?

If there were such an elegant way, I suppose the refreshing process of UITableView should happen as soon as the notification occurs. In this case, I would like to know whether it's possible to delay UITableView from refreshing itself until viewDidAppear occurs.

Upvotes: 3

Views: 2714

Answers (4)

lnafziger
lnafziger

Reputation: 25740

I would use KVO (Key Value Observing) to keep track of when it changes:

 - (void)viewDidLoad {
      [super viewDidLoad];  

      // Note that you can use the options to get the new value passed when it
      // changes if you want to update immediately.
      [configurationObject addObserver:self forKeyPath:@"configurationItem" options:0 context:nil];
 }

 - (void)viewDidUnload {
      [super viewDidUnload];
      [configurationObject removeObserver:self forKeyPath:@"configurationItem"];
 }

 // Note that I would refresh in viewWillAppear instead of viewDidAppear
 - (void)viewWillAppear:(BOOL)animated {
      [super viewWillAppear:animated];
      if (self.needToRefreshData == YES) {
           [self.tableView refreshData];
      }
 }

 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
      if (keyPath isEqualToString:@"configurationItem") {
           [self.needToRefreshData = YES];
      }
 }

Upvotes: 2

Semere Taézaz Sium
Semere Taézaz Sium

Reputation: 4036

Use Delegation Design Pattern to pass data from one View Controller to the Other.

For example, let's say one Tab shows a list of cars in a UITableViewController and you have another view that let's a user add a new car to the list. You can let the UITableViewController

  • Adopt AddCarViewController's protocol
  • Set itself as a Delegate for AddCarViewController's protocol
  • Implement its protocol method
  • Execute the protocol method when informed

You can then let the AddCarViewController

  • Create a Protocol
  • Declare object reference Delegate with getter and setter methods
  • Define a method under that protocol
  • Inform the Delegate when the Save action is performed

Take a look at the following sample code for your UITableViewController

@interface ViewController : UITableViewController <AddCarViewControllerDelegate>

             :
             :

// The addCar: method is invoked when the user taps the Add button created at run time.
- (void)addCar:(id)sender
{
// Perform the segue named ShowAddCar
[self performSegueWithIdentifier:@"ShowAddCar" sender:self];
}

             :
             :

// This method is called by the system whenever you invoke the method     performSegueWithIdentifier:sender:
// You never call this method. It is invoked by the system.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    NSString *segueIdentifier = [segue identifier];

    if ([segueIdentifier isEqualToString:@"ShowAddCar"]) {

        // Obtain the object reference of the destination view controller
        AddCarViewController *addCarViewController = [segue destinationViewController];

        // Under the Delegation Design Pattern, set the addCarViewController's delegate to be self
        addCarViewController.delegate = self;

        // Instantiate a Save button to invoke the save: method when tapped
        UIBarButtonItem *saveButton = [[UIBarButtonItem alloc]
                                       initWithBarButtonSystemItem:UIBarButtonSystemItemSave
                                       target:addCarViewController action:@selector(save:)];

        // Set up the Save custom button on the right of the navigation bar
        addCarViewController.navigationItem.rightBarButtonItem = saveButton;

    }

}

                 :
                 :


- (void)addCarViewController:(AddCarViewController *)controller didFinishWithSave:    (BOOL)save {
                 :
                 :
}

Sample code for the AddCarViewController is here

@protocol AddCarViewControllerDelegate;

@interface AddCarViewController : UIViewController

@property (nonatomic, strong) IBOutlet UITextField *carMake;
@property (nonatomic, strong) IBOutlet UITextField *CarName;
@property (nonatomic, assign) id <AddCarViewControllerDelegate> delegate;

// The keyboardDone: method is invoked when the user taps Done on the keyboard
- (IBAction)keyboardDone:(id)sender;

// The save: method is invoked when the user taps the Save button created at run time.
- (void)save:(id)sender;

@end

/*
 The Protocol must be specified after the Interface specification is ended.
 Guidelines:
 - Create a protocol name as ClassNameDelegate as we did above.
 - Create a protocol method name starting with the name of the class defining the protocol.
 - Make the first method parameter to be the object reference of the caller as we did below.
 */
@protocol AddCarViewControllerDelegate
- (void)addCarViewController:(AddCarViewController *)controller didFinishWithSave:(BOOL)save;
@end

Upvotes: 2

wattson12
wattson12

Reputation: 11174

You could store the configuration in core data and use an NSFetchedResultsController with the dependant view controller set as a delegate. This way your view controller will get a callback whenever the data is changed.

Apple has some boilerplate code to handle the updates as well

Upvotes: 1

Daniel
Daniel

Reputation: 22405

Well, one approach would be to have some common class (singleton perhaps which app delegate kind of is) that keeps track of your model, when the settings viewController detects a change it can mark the model as changed, then when the view in question comes in to view, ie, viewDidAppear gets called, it can query the model to see if the changed flag has been set, if it has then you know to reload the table view, otherwise you dont...

Another way could be to use notification center for it, if your view is loaded it can sign up for the notifications of the model change, in which at point it sets a flag that it needs to reload the table view next time it comes on screen..

hope this helps

Upvotes: 1

Related Questions