Хранение значений между контроллерами представления - PullRequest
1 голос
/ 08 августа 2010

У меня есть 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);
}

Категория устанавливается при создании CategorySelectionViewController. Когда категория выбрана на экране выбора категории, NSLog сообщает правильный объект. Когда он возвращается к ItemAddViewController, он снова становится нулевым. Эти два объекта должны быть одним и тем же, поэтому я не уверен, что делаю не так.

По сути, мне нужен хороший метод для передачи данных между двумя контроллерами представления.

Ответы [ 3 ]

1 голос
/ 29 августа 2012

Для продолжения того, что уже было сказано, один из подходов, обычно используемых в подобных проблемах, состоит в том, чтобы 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...
}

Что касается выполнения этого путем вызова [self parentViewController] в CategorySelectionViewController, уловка в том, что ItemAddViewController наследуется от UITableView, поэтому, когда вы отправляете сообщение [self parentViewController], компилятор думает, что вы говорите с UITableView, а не ItemAddViewController, если вы не разыгрываете его явно. Следовательно, он не знает, что self.parentViewController имеет свойство, называемое category. Вы можете исправить это, добавив приведение типа:

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

Надеюсь, это поможет.

0 голосов
/ 08 августа 2010

@ Дэвид - хороший ответ, но это сохранит данные в parentViewController.Если вы хотите, чтобы данные были локальными для ItemAddViewController (дочерний контроллер), вы можете создать локальный iVar во втором представлении и присвоить ему значение перед его отображением или помещением в контроллер навигации. См. Мой ответ на предыдущий вопрос SO здесь , чтобы увидеть, как это делается.

0 голосов
/ 08 августа 2010

Метод parentViewController класса UIViewController должен дать вам указатель на контроллер представления, который "управляет" текущим.Получив это, вы можете установить для него свойство 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:.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...