【问题标题】:Keeping values between view controllers在视图控制器之间保持值
【发布时间】:2010-08-08 01:18:55
【问题描述】:

我有一个 ItemAddViewController,它以模态视图的形式呈现自己。其中一个字段推送了一个新的视图控制器 CategorySelectionViewController,它允许用户选择单个类别。

ItemAddViewController.h

@property (nonatomic, retain) Category *category;

CategorySelectionViewController.h

@property (nonatomic, retain) Category *category;

CategorySelectionViewController.m

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *currentCategory = category;

if (currentCategory != nil) {
    NSInteger   index = [categories indexOfObject:currentCategory];
    NSIndexPath *selectionIndexPath = [NSIndexPath indexPathForRow:index inSection:0];
    UITableViewCell *checkedCell = [tableView cellForRowAtIndexPath:selectionIndexPath];
    checkedCell.accessoryType = UITableViewCellAccessoryNone;
}

//set the checkmark accessory
[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];

//update the category
category =[categories objectAtIndex:indexPath.row];
NSLog(@"%@", category);
// Deselect row
[tableView deselectRowAtIndexPath:indexPath animated:YES];

}

ItemAddViewController.m

- (void)viewWillAppear:(BOOL)animated {
  NSLog(@"%@", category);
}

Category 在 CategorySelectionViewController 创建时设置。在类别选择屏幕上选择类别时,NSLog 会报告正确的对象。当它返回到 ItemAddViewController 时,它再次为空。这两个应该是同一个对象,所以我不确定我做错了什么。

基本上,我需要一种在两个视图控制器之间传递数据的好方法。

【问题讨论】:

    标签: iphone uiviewcontroller


    【解决方案1】:

    为了跟进已经说过的内容,在类似问题中通常采用的一种方法是使ItemViewController(父级)成为CategorySelectionViewController(子级)的代表,并且当tableView:didSelectRowAtIndexPath:CategorySelectionViewController 中触发时, 向ItemAddViewController 中的委托回调发送消息 - 将所选类别作为参数传入。

    这个概念可以通过以下方式实现:

    @protocol CategorySelectionViewControllerDelegate;
    
    // in CategorySelectionViewController.h
    @interface CategorySelectionViewController : UITableViewController {
        id<CategorySelectionViewControllerDelegate> delegate;
    }
    @property (nonatomic, assign) id<CategorySelectionViewControllerDelegate> delegate;
    @end
    
    @protocol CategorySelectionViewControllerDelegate
    // delegate callback skeleton
    -(void)userDidSelectCategory:(Category *)categorySelected;
    @end
    
    // in CategorySelectionViewController.m
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
       NSManagedObject *currentCategory = category;
    
        if (currentCategory != nil) {
            NSInteger   index = [categories indexOfObject:currentCategory];
            NSIndexPath *selectionIndexPath = [NSIndexPath indexPathForRow:index inSection:0];
            UITableViewCell *checkedCell = [tableView cellForRowAtIndexPath:selectionIndexPath];
            checkedCell.accessoryType = UITableViewCellAccessoryNone;
        }
    
        //set the checkmark accessory
        [[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
    
        // here's where you message the delegate callback
        [self.delegate userDidSelectCategory:[categories objectAtIndex:indexPath.row]];
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
    }
    

    ItemAddViewController 的骨架随后将被修改以符合CategorySelectionViewControllerDelegate 协议:

    // in ItemAddViewController.h
    @protocol CategorySelectionViewControllerDelegate;
    @interface ItemAddViewController :  UITableViewController <CategorySelectionViewControllerDelegate> 
    { /* etc.... */ }
    @property (nonatomic, retain) Category *category;
    // delegate callback
    -(void)userDidSelectCategory:(Category *)categorySelected
    
    // in ItemAddViewController.m
    // set the CategorySelectionViewController delegate as this ItemViewController when you instantiate it
    -(void)showCategorySelectionViewController {
        CategorySelectionViewController *myChild = [[CategorySelectionViewController alloc] init];
        myChild.delegate = self;
        [self presentModalViewController:myChild animated:YES];
    }
    // implement the delegate callback
    -(void)userDidSelectCateogry:(Category *)categorySelected {
        self.category = categorySelected;
        // other handling code as needed...
    }
    

    关于通过在CategorySelectionViewController 中调用[self parentViewController] 来执行此操作,问题是ItemAddViewController 继承自UITableView,因此当您发送消息[self parentViewController] 时,编译器认为您正在与一个UITableView,不是ItemAddViewController,除非你明确地转换它。因此,它不知道self.parentViewController 有一个名为category 的属性。您可以通过添加类型转换来解决此问题:

    ItemAddViewController *itemAddViewControllerParent = (ItemAddViewController *)[self parentViewController];
    itemAddViewControllerParent.category = [categories objectAtIndex:indexPath.row]; 
    

    希望这会有所帮助。

    【讨论】:

      【解决方案2】:

      UIViewController 类的parentViewController 方法应该给你一个指向“管理”当前视图控制器的指针。完成后,您可以在其上设置 category 属性。

      也就是说,我自己还没有在 iOS 上使用视图控制器做太多事情,所以我不确定“parentViewController 应该为给定视图指向什么”的语义是什么......但我冒险您的 ItemAddViewController 实例应该是您的 CategorySelectionViewController 的父实例。

      这里有一个例子说明你可以如何做:

      - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
          NSManagedObject *currentCategory = category;
      
          if (currentCategory != nil) {
              NSInteger   index = [categories indexOfObject:currentCategory];
              NSIndexPath *selectionIndexPath = [NSIndexPath indexPathForRow:index inSection:0];
              UITableViewCell *checkedCell = [tableView cellForRowAtIndexPath:selectionIndexPath];
              checkedCell.accessoryType = UITableViewCellAccessoryNone;
          }
      
          //set the checkmark accessory
          [[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
      
          //update the category
          [self parentViewController].category = [categories objectAtIndex:indexPath.row];
          NSLog(@"%@", category);
          // Deselect row
          [tableView deselectRowAtIndexPath:indexPath animated:YES];
      }
      

      编辑:文档说明parentViewController 方法:

      父视图控制器与导航、标签栏和模态视图控制器层次结构相关。在每个层次结构中,父对象是负责显示当前视图控制器的对象。

      我认为这意味着您的模态视图控制器的 parentViewController 指向收到消息 presentModalViewController:animated: 的任何视图控制器。

      【讨论】:

      • 有趣。但是,似乎父视图控制器是导航控制器,而不是 ItemAddViewController(并且导航控制器的父级是标签栏控制器)
      【解决方案3】:

      @David's 是一个很好的答案,但这会将数据保留在parentViewController 中。如果您希望数据位于 ItemAddViewController(子控制器)的本地,那么您可以在第二个视图中创建一个本地 iVar,并在将其显示或将其推送到导航控制器之前为其分配一个值。 See my answer to a previous SO question here 看看它是如何完成的。

      【讨论】:

        猜你喜欢
        • 2020-04-24
        • 1970-01-01
        • 2012-12-31
        • 1970-01-01
        • 2016-01-20
        • 2017-01-28
        • 1970-01-01
        • 1970-01-01
        • 2014-11-07
        相关资源
        最近更新 更多