Отправка данных из моего детального представления обратно в мой UITableView - PullRequest
2 голосов
/ 18 февраля 2011

Прежде всего, слава Богу за переполнение стека.Я новичок в разработке Objective-C / Cocoa / iPhone, и этот сайт очень полезен.

У меня есть окно с панелью вкладок, в котором есть контроллер навигации, который загружает UITableViewController.Нажатие кнопки «Добавить» на панели навигации (созданной программно) вызывает UITableViewController следующим образом:

InvoiceAddViewController *addController = [[InvoiceAddViewController alloc] initWithNibName:@"InvoiceAddViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:addController animated:YES];

Этот контроллер табличного представления выдвигает свой собственный подробный вид:

    UITableViewCell *targetCell = [self.tableView cellForRowAtIndexPath:indexPath];

    GenericTextFieldDetailViewController *dvController = [[GenericTextFieldDetailViewController alloc] initWithNibName:@"GenericTextFieldDetailViewController" bundle:[NSBundle mainBundle]];

    dvController.fieldName = targetCell.textLabel.text;
    dvController.fieldValue = targetCell.detailTextLabel.text;

    [self.navigationController pushViewController:dvController animated:YES];
    [dvController release];

В принципе, вы нажимаете на ячейку в контроллере табличного представления, например «Заметки».Это выдвигает «GenericTextFieldDetailViewController» с именем «поля», которое вы щелкнули, и значением (если оно уже существует).Это позволяет мне повторно использовать мой подробный вид, а не создавать один рекламный тошнот для каждого поля.

Чтобы отодвинуть данные назад, я создал метод на «Add» UITableViewController:

- (void) updateField:(NSString*) fieldName value:(NSString*) fieldValue
{
    UITableViewCell *targetCell;
    if([fieldName isEqualToString:@"Invoice ID"])
    {
        NSUInteger indexArr[] = {1,1};
        targetCell = [[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathWithIndexes:indexArr length:2]];
        targetCell.detailTextLabel.text = fieldValue;
    }
    else if([fieldName isEqualToString:@"P.O. Number"])
    {
        NSUInteger indexArr[] = {1,2};
        targetCell = [[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathWithIndexes:indexArr length:2]];
        targetCell.detailTextLabel.text = fieldValue;
    }
    else if([fieldName isEqualToString:@"Add Note"])
    {
        NSUInteger indexArr[] = {3,0};
        targetCell = [[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathWithIndexes:indexArr length:2]];
        targetCell.detailTextLabel.text = fieldValue;
    }
}

Этот метод предназначен для получения данных, которые я отправляю с помощью этого метода в «Универсальный»:

- (IBAction)saveField:(id)sender
{
    self.fieldValue = theTextField.text;
    InvoiceAddViewController *parentController = (InvoiceAddViewController*)self.view.superview;
    [parentController updateField:self.fieldName value:self.fieldValue];
}

Что приводит нас к проблеме: когда метод сохранения срабатывает, он выдает неверную ошибку селектора, потому что self.view.superview - это не UITableView, который выдвинул подробное представление «Generic».

Я пробовал следующие комбинации (из GDB):

(gdb) po [[self view] superview]
<UIViewControllerWrapperView: 0x4b6d4d0; frame = (0 64; 320 367); autoresize = W+H; layer = <CALayer: 0x4b6c090>>
(gdb) po [[self navigationController] parentViewController]
<UITabBarController: 0x4d2fa90>
(gdb) po [self parentViewController]
<UINavigationController: 0x4d2fdc0>

Я чувствую, что приземляюсьвсе вокруг UITableView я хочу вызвать, но не могу найти его.

Что я делаю не так?

воздерживается от того, чтобы вырывать больше волос

Ответы [ 4 ]

3 голосов
/ 18 февраля 2011

Проблема в том, что вы путаете иерархию представлений для стека навигации.Ваш контроллер подробного представления хочет отправить сообщение контроллеру, который поместил его в стек, который является вторым по последнему объекту в массиве viewControllers контроллера навигации.

Попробуйте изменить свой метод saveField: на:

- (IBAction)saveField:(id)sender
{
    self.fieldValue = theTextField.text;
    NSArray *navigationStack = self.navigationController.viewControllers;
    InvoiceAddViewController *parentController = (InvoiceAddViewController*)[navigationStack objectAtIndex:navigationSTack.count - 2];
    [parentController updateField:self.fieldName value:self.fieldValue];
}

Редактировать: я должен отметить, что этот дизайн очень хрупкий.Лучший способ - применить Model-View-Controller и создать объект, представляющий значение поля и заголовка.Затем ваш InvoiceAddViewController может передавать экземпляры этих объектов в ваш подробный контроллер, и когда ваш подробный контроллер изменяет их, эти изменения могут быть легко отражены в других ваших контроллерах.

Редактировать 2: Вот подсказка о том, как это будетРабота.

   UITableViewCell *targetCell = [self.tableView cellForRowAtIndexPath:indexPath];

    GenericTextFieldDetailViewController *dvController = [[GenericTextFieldDetailViewController alloc] initWithNibName:@"GenericTextFieldDetailViewController" bundle:[NSBundle mainBundle]];

    dvController.dataObject = [self dataObjectForIndexPath:indexPath];
    [self.navigationController pushViewController:dvController animated:YES];
    [dvController release];

Я предполагаю, что вы реализовали метод dataObjectForIndexPath:.Предположительно tableView: cellForRowAtIndexPath: также будет использовать этот метод для настройки своих ячеек.

Теперь вы можете исключить методы saveField: и updateField :.В вашем InvoiceAddViewController viewWillAppear: можно использовать для обновления вашего представления следующим образом:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self.tableView reloadData]
}

Здесь целый мир возможностей.reloadData является очень тяжелым.Поэкспериментируйте с такими вещами, как KVO, чтобы сделать это более автоматическим.

В контроллере деталей, конечно же, не забудьте обновить объект, скажем, видимость исчезнет, ​​чтобы сделать что-то вроде

self.dataObject.fieldValue = theTextField.text;

Это только начало.Есть много возможностей и деталей для рассмотрения.Вы действительно должны смотреть на множество примеров кода, этот шаблон часто используется.Пример CoreDataBooks на портале для разработчиков использует похожий шаблон, и почти наверняка есть и другие.

0 голосов
/ 08 марта 2012

У меня была такая же проблема, но не с табличным представлением. Я хотел изменить значение из последнего контроллера представления. Я использую Xcode 5:

 {

    NSArray *navigationStack = self.navigationController.viewControllers;
    ViewController *control = [navigationStack objectAtIndex:([navigationStack count] -2)];
    control.pagecont.currentPage = self.currIndex;
    CGRect frame;
    frame.origin.x = control.scroll.frame.size.width * control.pagecont.currentPage;
    frame.origin.y = 50;
    frame.size = control.scroll.frame.size;

    [control.scroll scrollRectToVisible:frame animated:YES];

    [self.navigationController popViewControllerAnimated:YES];

}
0 голосов
/ 19 февраля 2011

Этот подход просто требует делегирования. Создайте протокол на вашем контроллере подробного представления, объявите метод как

- (void)genericTextFieldDetailViewController:(GenericTextFieldDetailViewController *)controller didUpdateValue:(NSString *)value forField:(NSString *)field

Теперь, когда вы будете готовы отправить данные обратно, вы просто отправите это сообщение своему делегату (контроллеру push-представления).

[self.delegate genericTextFieldDetailViewController:self didUpdateValue:newValue forField:passedInField]

Убедитесь, что при создании и отправке контроллера подробного представления вы назначаете себя в качестве его делегата и реализуете этот метод для обработки входящих значений. Я думаю, вы найдете такой подход более гибким.

0 голосов
/ 18 февраля 2011

Вы должны использовать уведомление, KVO или делегирование.Используйте шаблоны проектирования, которые подходят для передачи данных на этой платформе.Даже если вы можете сделать вызов напрямую, используя один из этих шаблонов, наверняка окажется лучшим способом достижения этого в инкапсулированном виде.

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