부모 iOS에서 컨테이너 뷰 컨트롤러에 액세스


203

iOS6에서 새로운 컨테이너보기를 발견했지만 포함보기에서 컨트롤러에 액세스하는 방법을 잘 모르겠습니다.

대본:

예

컨테이너보기가있는보기 컨트롤러에서 경고보기 컨트롤러의 레이블에 액세스하고 싶습니다.

그들 사이에 segue가 있는데, 그것을 사용할 수 있습니까?


현대적인 컨테이너 뷰를 위해 여기에 완전히 설명되어 있습니다 : stackoverflow.com/a/23403979/294884
Fattie

답변:


362

예. segue를 사용하여 하위 뷰 컨트롤러 (및 해당 뷰 및 하위 뷰)에 액세스 할 수 있습니다. alertview_embed스토리 보드의 속성 관리자를 사용하여 segue에 식별자 (예 :)를 제공하십시오 . 그런 다음 부모보기 컨트롤러 (컨테이너보기를 수용하는 컨트롤러)에게 다음과 같은 방법을 구현하십시오.

- (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's subviews here...
   }
}

1
우린 안해? 여기에 뭔가 빠졌습니까?
Adam Waite

25
예, 두 번째 뷰 컨트롤러가 첫 번째 뷰 컨트롤러의 자식이 될 때 발생하는 내장 segue가 있습니다. PreparingForSegue :이 작업이 발생하기 직전에 호출됩니다. 이 기회를 사용하여 데이터를 자식에게 전달하거나 나중에 사용할 수 있도록 자식에 대한 참조를 저장할 수 있습니다. developer.apple.com/library/ios/#documentation/uikit/reference/…
Peter E

1
아, 뷰가로드 될 때 '두 번째 뷰 컨트롤러가 첫 번째 뷰 컨트롤러의 자식이됩니까?' 감사합니다. 나는 지금 내 프로젝트에 있지 않지만 나중에 테스트 할 것입니다
Adam Waite

1
정확히 viewDidLoad 전에 호출됩니다. viewDidLoad에 도달하면 부모와 자식이 연결되고 부모의 [self childViewControllers]가 모든 자식 컨트롤러의 배열을 반환합니다 (아래 rdelmar의 답변 참조).
피터 E

2
제안 된 솔루션에 한 가지주의 사항을 추가합니다. (자식) 대상 뷰 컨트롤러의 뷰 속성에 액세스 할 때 매우주의하십시오. 어떤 상황에서는 viewDidLoad가 호출 된 다음 사전에 필요한 segue 데이터를 설정하는 것이 좋습니다. viewDidLoad를 안전하게 실행할 수 있습니다.
AlwaysLearning

56

당신은 단순히 다음과 같이 할 수 있습니다 self.childViewControllers.lastObject(자녀가 하나 있다고 가정하면 그렇지 않으면 사용하십시오 objectAtIndex:).


1
@RaphaelOliveira, 반드시 그런 것은 아닙니다. 단일 뷰에 여러 childController가있는 경우이 방법이 선호됩니다. 여러 컨테이너를 한 번에 조정할 수 있습니다. PreparingForSegue는 작동중인 단일 하위 컨트롤러 인스턴스에만 참조합니다.
Fydo

2
@Fydo, 그리고 'Segue 준비'에서 여러 컨테이너를 모두 처리하는 데 문제가 무엇입니까?
Lay González 2016 년

1
스토리 보드에서 전환하거나 속편 등을 사용하지 않기로 결정한 경우 어떻게해야합니까? 그런 다음 코드 변경 등을 파헤쳐 야합니다.
Tom Andersen

2
이것은 나의 일반적인 접근 방법이지만, childViewControllers"너무 빨리"에 액세스 한 이후로 충돌합니다.
Mazyod

24

스위프트 프로그래밍

이렇게 쓸 수 있습니다

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
    }
}

if 문에서 segueName 뒤에 물음표를 사용하는 것은 무엇입니까? "segueName이라면?"
목사

18

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라이너 하나
Adam Waite

1
나는 childViewControllers.flatMap({ $0 as? CamperVanViewController }).first그것이 조금 더 나은 것으로 생각합니다.
SimplGy

액세스하려는 경우에 정말 좋은 해결책이 뷰 컨트롤러를 두 번 이상
가브리엘 Goncalves은

이것은 희망이 없습니다. 특정 수업 중 하나만 가질 수있는 특별한 이유는 없습니다. 이것이 바로 식별자가 존재하는 이유입니다. 그냥 표준 공식을 따르십시오 ... stackoverflow.com/a/23403979/294884
Fattie

첫 번째 요소 만 취하기 위해 필터링하지 마십시오. 그냥 사용하십시오 first(where:). childViewControllers.first(where: { $0 is CamperVanViewController })
Alexander-복원 모니카

9

계산 된 속성을 사용하여 Swift 3에 대한 업데이트 된 답변 :

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

이는 첫 번째 일치 항목에 도달 할 때까지 하위 목록 만 반복합니다.


8

self.childViewControllers 부모의 통제가 필요할 때 더 관련이 있습니다. 예를 들어 자식 컨트롤러가 테이블보기이고이를 강제로 다시로드하거나 부모 탭 컨트롤러의 다른 이벤트 또는 버튼 탭을 통해 속성을 변경하려는 경우에는 PrepareForSegue가 아닌 ChildViewController의 인스턴스에 액세스하여이를 수행 할 수 있습니다. 둘 다 다른 방식으로 응용 프로그램을 가지고 있습니다.


2

뷰 컨트롤러의 유형에 Swift의 switch 문을 사용하는 다른 방법이 있습니다.

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

나는 다음과 같은 코드를 사용한다 :

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

1

경우에는 누군가가 찾고있는 스위프트 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

일반적으로 몇 가지 달콤한 일을 할 수 있습니다. 다음은 Array의 확장입니다.

extension Array {
    func firstMatchingType<Type>() -> Type? {
        return first(where: { $0 is Type }) as? Type
    }
}

그런 다음 viewController 에서이 작업을 수행 할 수 있습니다.

var viewControllerInContainer: YourViewControllerClass? {
    return childViewControllers.firstMatchingType()!
}

0

이렇게 쓸 수 있습니다

- (IBAction)showDetail:(UIButton *)sender {  
            DetailViewController *detailVc = [self.childViewControllers firstObject];  
        detailVc.lable.text = sender.titleLabel.text;  
    }  
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.