Контроллер доступа к контейнеру из родительской iOS

162

в iOS6 Я заметил новый Container View, но не совсем уверен, как получить доступ к нему с помощью содержащего представления.

Сценарий:

Изображение 66

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

Есть ли между ними переход, могу ли я использовать это?

  • 0
    полностью объяснено здесь, для современных представлений контейнера: stackoverflow.com/a/23403979/294884
Теги:
uiviewcontroller
containers

10 ответов

311
Лучший ответ

Да, вы можете использовать segue, чтобы получить доступ к контроллеру дочернего представления (и его представлению и представлениям). Дайте segue идентификатор (например, alertview_embed), используя инспектор атрибутов в Storyboard. Затем, если родительский контроллер представления (тот, в котором находится контейнер), реализует такой метод:

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
   NSString * segueName = segue.identifier;
   if ([segueName isEqualToString: @"alertview_embed"]) {
       AlertViewController * childViewController = (AlertViewController *) [segue destinationViewController];
       AlertView * alertView = childViewController.view;
       // do something with the AlertView subviews here...
   }
}
  • 1
    мы не спешим? я что-то здесь упускаю ...?
  • 24
    да, есть переход, который происходит, когда второй контроллер представления становится дочерним по отношению к первому контроллеру представления. prepareForSegue: вызывается как раз перед тем, как это произойдет. Вы можете использовать эту возможность, чтобы передать данные ребенку или сохранить ссылку на ребенка для последующего использования. см. также developer.apple.com/library/ios/#documentation/uikit/reference/…
Показать ещё 8 комментариев
45

Вы можете сделать это просто с помощью self.childViewControllers.lastObject (если у вас есть только один ребенок, в противном случае используйте objectAtIndex:).

  • 1
    @RaphaelOliveira, не обязательно. Если у вас есть несколько дочерних контроллеров в одном представлении, ЭТО будет предпочтительным подходом. Это позволяет координировать несколько контейнеров одновременно. prepareForSegue имеет ссылку только на один экземпляр дочернего контроллера, на который он действует.
  • 2
    @Fydo, а в чем проблема с обработкой всех нескольких контейнеров в режиме «prepare to segue»?
Показать ещё 2 комментария
19

для быстрого программирования

вы можете написать вот так

var containerViewController: ExampleViewController?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    // you can set this name in 'segue.embed' in storyboard
    if segue.identifier == "checkinPopupIdentifierInStoryBoard" {
        let connectContainerViewController = segue.destinationViewController as ExampleViewController
        containerViewController = connectContainerViewController
    }
}
  • 0
    Какая польза от знака вопроса после segueName в операторе if? "если segueName?"
10

Подход prepareForSegue работает, но он полагается на магическую строку идентификатора segue. Может быть, лучший способ.

Если вы знаете класс VC, который вам нужен, вы можете сделать это очень аккуратно с вычисленным свойством:

var camperVan: CamperVanViewController? {
  return childViewControllers.flatMap({ $0 as? CamperVanViewController }).first
  // This works because `flatMap` removes nils
}

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

  • 3
    return childViewControllers.filter { $0 is CamperVanViewController }.first в один return childViewControllers.filter { $0 is CamperVanViewController }.first
  • 1
    С тех пор я сделал childViewControllers.flatMap({ $0 as? CamperVanViewController }).first я думаю, что это немного лучше, так как он отбрасывает и избавляется от любых нулей.
Показать ещё 4 комментария
8

self.childViewControllers более уместен, когда вам нужен контроль над родителем. Например, если дочерний контроллер является табличным представлением, и вы хотите его принудительно перезагрузить или изменить свойство с помощью нажатия кнопки или любого другого события в Parent View Controller, вы можете сделать это, обратившись к экземпляру ChildViewController, а не через prepareForSegue. Оба имеют свои приложения по-разному.

7

Обновленный ответ для Swift 3, используя вычисленное свойство:

var jobSummaryViewController: JobSummaryViewController {
    get {
        let ctrl = childViewControllers.first(where: { $0 is JobSummaryViewController })
        return ctrl as! JobSummaryViewController
    }
}

Это только повторяет список дочерних элементов, пока не достигнет первого совпадения.

1

Существует другой способ использования оператора переключения Swift для типа контроллера вида:

override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
  switch segue.destination
  {
    case let aViewController as AViewController:
      self.aViewController = aViewController
    case let bViewController as BViewController:
      self.bViewController = bViewController
    default:
      return
  }
}
1

Если кто-то ищет Swift 3.0,

viewController1, viewController2 и т.д. тогда будет доступно.

let viewController1 : OneViewController!
let viewController2 : TwoViewController!

// Safety handling of optional String
if let identifier: String = segue.identifier {

    switch identifier {

    case "segueName1":
        viewController1 = segue.destination as! OneViewController
        break

    case "segueName2":
        viewController2 = segue.destination as! TwoViewController
        break

    // ... More cases can be inserted here ...

    default:
        // A new segue is added in the storyboard but not yet including in this switch
        print("A case missing for segue identifier: \(identifier)")
        break
    }

} else {
    // Either the segue or the identifier is inaccessible 
    print("WARNING: identifier in segue is not accessible")
}
1

Я использую Code like:

- (IBAction)showCartItems:(id)sender{ 
  ListOfCartItemsViewController *listOfItemsVC=[self.storyboard instantiateViewControllerWithIdentifier:@"ListOfCartItemsViewController"];
  [self addChildViewController:listOfItemsVC];
 }
0

вы можете написать вот так

- (IBAction)showDetail:(UIButton *)sender {  
            DetailViewController *detailVc = [self.childViewControllers firstObject];  
        detailVc.lable.text = sender.titleLabel.text;  
    }  
}

Ещё вопросы

Сообщество Overcoder
Наверх
Меню