[iphone] UINavigationController에서 뷰를 팝하고 한 작업에서 다른 뷰로 대체하려면 어떻게해야합니까?

UINavigationController 스택에서 하나의 뷰를 제거하고 다른 뷰로 교체해야하는 응용 프로그램이 있습니다. 상황은 첫 번째보기가 편집 가능한 항목을 만든 다음 항목에 대한 편집기로 자신을 대체하는 것입니다. 첫 번째보기 내에서 명백한 해결책을 수행 할 때 :

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[self retain];
[self.navigationController popViewControllerAnimated: NO];
[self.navigationController pushViewController: mevc animated: YES];
[self release];

나는 매우 이상한 행동을한다. 일반적으로 편집기보기가 나타나지만 탐색 모음에서 뒤로 버튼을 사용하려고하면 추가 화면이 표시되고 일부는 비어 있으며 일부는 망가졌습니다. 제목도 무작위가됩니다. 내비 스택이 완전히 튀어 나온 것과 같습니다.

이 문제에 대한 더 나은 접근 방법은 무엇입니까?

고마워, 맷



답변

나는 당신이 viewControllers재산을 전혀 손으로 엉망으로 만들 필요가 없다는 것을 발견 했습니다. 기본적으로 이것에 대해 두 가지 까다로운 점이 있습니다.

  1. self.navigationController현재 탐색 컨트롤러의 스택에없는 nil경우 반환 됩니다 self. 따라서 액세스 권한을 잃기 전에 로컬 변수에 저장하십시오.
  2. 당신은 retain(그리고 적절하게 release) self당신이 속한 메소드를 소유 한 객체가 할당 해제되어 이상한 일을 일으킬 것입니다.

일단 준비를 마치면 평소대로 튀어 나와서 누르십시오. 이 코드는 상단 컨트롤러를 다른 컨트롤러로 즉시 대체합니다.

// locally store the navigation controller since
// self.navigationController will be nil once we are popped
UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

// Pop this controller and replace with another
[navController popViewControllerAnimated:NO];
[navController pushViewController:someViewController animated:NO];

그 마지막 줄에서 당신은 변경하는 경우 animatedYES다음 새 화면이 실제로 애니메이션에서 방금 튀어 컨트롤러가 밖으로 애니메이션 것입니다 것입니다. 꽤 좋아 보인다!


답변

다음 접근 방식은 나에게 더 좋게 보이며 ARC에서도 잘 작동합니다.

UIViewController *newVC = [[UIViewController alloc] init];
// Replace the current view controller
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
[viewControllers removeLastObject];
[viewControllers addObject:newVC];
[[self navigationController] setViewControllers:viewControllers animated:YES];


답변

경험상 UINavigationController의 viewControllers속성을 직접 조작해야 할 것입니다. 다음과 같이 작동합니다.

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[[self retain] autorelease];
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
self.navigationController.viewControllers = controllers;
[self.navigationController pushViewController:mevc animated: YES];

참고 : 일반적으로 더 강력하기 때문에 유지 / 릴리스를 유지 / 자동 릴리스로 변경했습니다. 유지 / 릴리스간에 예외가 발생하면 자체적으로 누출되지만 자동 릴리스가 처리합니다.


답변

많은 노력 (그리고 Kevin의 코드 수정) 끝에 마침내 스택에서 튀어 나오는 뷰 컨트롤러에서이를 수행하는 방법을 알아 냈습니다. 내가 가진 문제는 컨트롤러 배열에서 마지막 개체를 제거한 후 self.navigationController가 nil을 반환한다는 것입니다. 인스턴스 메서드 navigationController의 UIViewController에 대한 설명서에서이 줄이 원인이라고 생각합니다. “뷰 컨트롤러가 스택에있는 경우에만 탐색 컨트롤러를 반환합니다.”

현재 뷰 컨트롤러가 스택에서 제거되면 navigationController 메서드가 nil을 반환한다고 생각합니다.

작동하는 조정 된 코드는 다음과 같습니다.

UINavigationController *navController = self.navigationController;
MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
navController.viewControllers = controllers;
[navController pushViewController:mevc animated: YES];


답변

고마워요, 이것이 제가 필요했던 것입니다. 나는 또한 이것을 애니메이션에 넣어 페이지 컬을 얻습니다.

        MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

    UINavigationController *navController = self.navigationController;
    [[self retain] autorelease];

    [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration: 0.7];
    [UIView setAnimationTransition:<#UIViewAnimationTransitionCurlDown#> forView:navController.view cache:NO];

    [navController popViewControllerAnimated:NO];
    [navController pushViewController:mevc animated:NO];

    [UIView commitAnimations];

0.6 기간은 빠르며 3GS 이상에 적합하며 0.8은 여전히 ​​3G에 비해 너무 빠릅니다 ..

요한


답변

popToRootViewController로 다른 뷰 컨트롤러를 표시하려면 다음을 수행해야합니다.

         UIViewController *newVC = [[WelcomeScreenVC alloc] initWithNibName:@"WelcomeScreenVC" bundle:[NSBundle mainBundle]];
            NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
            [viewControllers removeAllObjects];
            [viewControllers addObject:newVC];
            [[self navigationController] setViewControllers:viewControllers animated:NO];

이제 모든 이전 스택이 제거되고 필요한 rootViewController로 새 스택이 생성됩니다.


답변

나는 최근에 비슷한 일을해야했고 Michaels 대답에 내 솔루션을 기반으로했습니다. 제 경우에는 탐색 스택에서 두 개의 뷰 컨트롤러를 제거한 다음 새 뷰 컨트롤러를 추가해야했습니다. 부름

[컨트롤러 removeLastObject];

두 번, 제 경우에는 잘 작동했습니다.

UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

searchViewController = [[SearchViewController alloc] init];
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];

[controllers removeLastObject];
// In my case I want to go up two, then push one..
[controllers removeLastObject];
navController.viewControllers = controllers;

NSLog(@"controllers: %@",controllers);
controllers = nil;

[navController pushViewController:searchViewController animated: NO];