如何从一个视图控制器呈现另一个视图控制器

3

如果满足特定条件,我想从一个视图控制器中打开另一个视图控制器。代码似乎没有错误,但视图从未显示。由于我刚接触xcode4/ios5,所以一定是忽略了某些东西。

以下是打开第二个视图控制器的代码:

CreateUserViewController *createUserController = [[CreateUserViewController alloc] initWithNibName:@"CreateUserView" bundle:[NSBundle mainBundle] keyWrapper:keyChainWrapper];

    [self presentViewController:createUserController animated:YES completion:nil];

在我的项目中,我有一个名为“CreateUserView”的xib文件。我已经向这个xib添加了一个视图控制器,并将其分配给“CreateUserViewController”。同时,我在苹果文档中注意到,它显示了设置要呈现的视图控制器的代理。但是,似乎没有名为“delegate”的属性在视图控制器对象上。这份文档过时了吗?这是我正在尝试使用的文档(第9-1节):View Controller Programming。有人能给我一个提示吗?谢谢...编辑 添加自定义构造函数。
    -(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil keyWrapper:(KeychainItemWrapper *)keyWrapper
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if(self){
        [self setKeyChainWrapper:keyWrapper];
    } 
             return self;
}

你能否在CreateUserView中发布你自定义的-initWithNibName:bundle:keyWrapper:方法的代码? - Jason Coco
2个回答

4
关于CreateUserView.xib:你不需要在nib文件中放置一个CreateUserViewController对象。你需要将File's Owner占位符的自定义类设置为CreateUserViewController。然后,您需要将File's Owner的view输出连接到nib中的顶级视图。
关于delegate属性:UIViewController类没有自己的delegate属性。想法是将delegate属性添加到UIViewController子类中。代理提供了一种让您呈现的视图控制器将自定义信息传递回呈现视图控制器的方法。
为什么要这样做?考虑您发布的代码。我假设您有一个UserListViewController,它显示用户对象列表,并具有“创建新用户”按钮。当用户点击“创建新用户”按钮时,您会创建一个CreateUserViewController并将其呈现。
用户与CreateUserViewController交互以设置新用户对象的属性-名称、等级、发型等。然后他点击“完成”按钮。您的CreateUserViewController创建新的User对象并将其放入数据库中。然后它需要解除自身,以便UserListViewController的用户对象列表再次出现。
但是,您希望用户列表包括新创建的用户对象,并且希望滚动列表,使新用户在屏幕上显示。因此,您需要一种方法让CreateUserViewController告诉UserListViewController有关新创建的用户对象。这就是代表的作用。
您可以像这样定义协议:
@protocol CreateUserViewControllerDelegate

- (void)didCreateUser:(User *)user;

@end

你需要给 CreateUserViewController 添加一个 delegate 属性:

@interface CreateUserViewController

@property (weak, nonatomic) id<CreateUserViewControllerDelegate> delegate;

// ...

当用户点击您的CreateUserViewController视图控制器中的“完成”按钮时,您会通知代理新用户的信息。
- (IBAction)doneButtonWasTouched:(id)sender {
    User *user = [self createUser];
    [self.delegate didCreateUser:user];
    [self dismissViewControllerAnimated:YES completion:nil];
}

在你的中,你需要采用并实现以下协议:
@interface UserListViewController <CreateUserViewControllerDelegate, UITableViewDelegate, UITableViewDataSource>

// ...

@end

@implementation UserListViewController

- (void)didCreateUser:(User *)user {
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[self.users count] inSection:0];
    [self.users addObject:user];
    [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
    [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition: UITableViewScrollPositionNone animated:YES];
}

当您需要呈现CreateUserViewController时,您将新控制器的委托设置为UserListViewController

- (IBAction)createUserButtonWasTouched:(id)sender {
    CreateUserViewController *createUserController = [[CreateUserViewController alloc] initWithNibName:@"CreateUserView" bundle:[NSBundle mainBundle] keyWrapper:keyChainWrapper];
    createUserController.delegate = self;
    [self presentViewController:createUserController animated:YES completion:nil];
}

我会尽快尝试一下。谢谢你! - Nick
这是一个非常好的答案。我很感激委托示例。然而... 我仍然无法从其他视图控制器打开我的视图。我按照您建议的方法从xib中删除了视图控制器。我将CreateUserViewController分配给File Owener占位符。然后,我将视图控制器上的视图分配给xib上的视图。 - Nick

1
在iOS5中,推送新的视图控制器的方法与iOS4和Xcode 3相比有了很大的变化。简而言之,现在使用故事板来创建应用程序视图控制器流程。即使您可以使用独立的.xib文件构建应用程序,在iOS5中这种情况也不太常见。
无论如何,将新的视图控制器推送到屏幕上的主要方法是使用转场。请查看此教程以获得介绍: http://www.raywenderlich.com/5138/beginning-storyboards-in-ios-5-part-1 它做了一个很好的工作,解释了如何创建故事板和使用转场。您仍然可以通过代码“老方法”来呈现视图控制器,但随着这些新技术的引入,这种情况现在变得越来越少见。在iTunes U上还有一些绝对棒的教程-搜索CS193P。这是斯坦福大学Objective-C和iOS编程介绍课程。这应该可以让你入门,并帮助你考虑一种更符合iOS5速度的推送< code >createUserController 的方法。 更新 我只是想补充一点。如果你将你的程序配置为使用故事板和转场,你可以使用方法performSegueWithIdentifier:sender:来执行转场到createUserController视图,如果满足适当的条件。请参阅UIViewController的Apple API,了解如何使用此方法。

谢谢提供的信息。我已经使用Storyboards和Seques做了一些工作。我试图解决的问题是当一个视图动态显示时。也就是说,只有在用户当前未登录时才显示此对话框。这似乎不是segues的用例(但我对它们非常陌生)。我会研究performSegueWithIdentifier:sender:的用法。谢谢! - Nick
Nick - 为了动态显示VC,您可以在Storyboard中定义segue,然后在代码的某个适当位置检查是否需要显示VC。如果需要,只需使用performSegueWithIdentifier:sender:方法。祝好运! - Joey J
@JakeV 如果我们在iOS5中不使用故事板,需要以编程方式呈现视图怎么办?[self presentModalViewController:x animated:YES]; 已过时吗? - DD_
1
根据UIViewController文档,如果不使用故事板,你需要使用“呈现另一个视图控制器的内容”下列出的方法之一来编程地呈现一个视图控制器。我建议首先尝试使用presentViewController:animated:completion:dismissViewControllerAnimated:completion:,除非你确实需要以模态方式呈现一个视图控制器。 - Joey J

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接