将“重新加载”信号从一个视图发送到另一个视图的最佳实践

时间:2012-01-11 16:10:30

标签: ios uitableview view notifications

我的目标是每次更改某些配置时通知UITableView刷新自己。问题是配置视图在产生信号的同一视图上“不”。 (是的,我使用了Tabbed应用程序。)

目前我在AppDelegate中使用一种全局变量来检测一个视图中的更改,并在另一个视图中进行检查。这很好,但代码不可读,因为它是如此紧密耦合。这样做有一种优雅的方法吗?我是否会错过这个编程框架中的某些内容?

如果有这么优雅的方式,我想UITableView的刷新过程应该在通知发生时立即发生。在这种情况下,我想知道在发生viewDidAppear之前是否可以延迟UITableView的刷新。

4 个答案:

答案 0 :(得分:2)

我会使用KVO(键值观察)来跟踪它何时发生变化:

 - (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];
      }
 }

答案 1 :(得分:2)

使用委托设计模式将数据从一个View Controller传递给另一个。

例如,假设一个选项卡显示UITableViewController中的汽车列表,并且您有另一个视图,让用户将新汽车添加到列表中。你可以让UITableViewController

  • 采用AddCarViewController的协议
  • 将自己设置为AddCarViewController协议的委托
  • 实施其协议方法
  • 获得通知时执行协议方法

然后你可以让AddCarViewController

  • 创建协议
  • 使用getter和setter方法声明对象引用Delegate
  • 在该协议下定义方法
  • 执行保存操作时通知代理

查看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 {
                 :
                 :
}

AddCarViewController的示例代码在这里

@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

答案 2 :(得分:1)

好吧,一种方法是让一些公共类(单例可能是哪种app委托类型)跟踪你的模型,当设置viewController检测到变化时它可以将模型标记为已更改,然后是视图有问题进来查看,即viewDidAppear被调用,它可以查询模型,看看是否已经设置了更改的标志,如果有,那么你知道重新加载表视图,否则你不...

另一种方法可能是使用通知中心,如果您的视图已加载,它可以注册模型更改的通知,在此点它设置一个标志,下次需要重新加载表视图屏幕上出现..

希望这会有所帮助

答案 3 :(得分:1)

您可以将配置存储在核心数据中,并使用NSFetchedResultsController并将从属视图控制器设置为委托。这样,只要数据发生变化,视图控制器就会收到回调。

Apple还有一些boilerplate code来处理更新