如何在UIViewController中设置parentViewController?

14

UIViewController的parentViewController属性是只读的,但我正在嵌套自定义的视图控制器,想使用此属性。

然而,由于它是只读的,且我找不到其他设置该属性的方法,我的问题是:我该如何设置它?

显然,UINavigationController可以在-pushViewController中以某种方式设置该属性,-presentModalViewController也可以,因此一定有可能。

我知道我可以添加自己的UIViewController属性,但我确信parentViewController在原则上是正确的属性。


我认为在这个帖子中谁将每个答案都投了反对票的人应该给出一个理由 :) - willcodejavaforfood
不是我干的,但我怀疑他们不赞成使用私有API,并且在SO上反对使用私有API的建议似乎很普遍。也许他们是苹果的内鬼。 - Simon Woodside
6个回答

11

解决方案如下:

   - (void)setParentController:(UIViewController*)parent{
 [self setValue:parent forKey:@"_parentViewController"];
    }

它不会与链接器产生问题!

注:不要使用“setParentViewController”作为方法名称,因为此方法存在于私有API中,苹果公司说: “The non-public API that is included in your application is setParentViewController:。”

如果您在源代码中定义了一个与上述API同名的方法,我们建议更改您的方法名称,以使其不再与苹果的私有API发生冲突,以避免您的应用程序在未来提交时被标记。请在下一个更新中解决这个问题……"


3
这会不会导致应用商店拒绝?这解决了我的一些模态展示问题,但令人担忧。 - Sean Aitken

10

我知道这个问题是在iOS 5之前提出的,但是作为参考,当您想要嵌套UIViewControllers时,您应该使用addChildViewController。这也会自动设置parentViewController属性。

- (void)addChildViewController:(UIViewController *)childController NS_AVAILABLE_IOS(5_0);

您可以在Apple了解更多关于"创建自定义内容视图控制器"的内容。


1
这对我有效,为子视图控制器设置了parentViewController属性。不确定为什么它不是被接受的答案。 - KyleStew

2

我尝试了Alex的建议,为UIViewController创建了一个类别,在模拟器上可以运行,但在我的手机上不行。以下是该类别的代码:

@interface UIViewController (parentSetter) 
-(void)setParentUIViewController:(UIViewController*)parent;
@end

@implementation UIViewController (parentSetter)
-(void)setParentUIViewController:(UIViewController*)parent
{
 _parentViewController = parent;
}
@end

代码可以编译并正常运行,但需要注意下划线成员有点让人不舒服。这是在使用3.0 SDK进行编译时导致链接错误的原因。

我有一个容器视图,其中有2个子视图,其中一个是表格。表格需要一个父级,以便与导航栏等进行交互。

相反,我采用以下解决方案:

@interface AdoptedTableViewController : UITableViewController {
    UIViewController* surrogateParent;
}

-(UINavigationController*)navigationController;
@property (nonatomic, assign) IBOutlet UIViewController *surrogateParent;
@end

@implementation AdoptedTableViewController
@synthesize surrogateParent;

-(UINavigationController*)navigationController
{
    if( [super navigationController] )//self.navigationController ) 
    {
        return [super navigationController];
    }
    else
    {
        return surrogateParent.navigationController;
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

我的所有表视图控制器现在都是AdoptedTableViewController。它们需要父级来将视图控制器推到导航栈中,所以这由导航控制器获取器自动处理。
如果parentViewController不是只读的就好了,但我在尝试使用_parentViewController时发现ViewController层次结构并不仅限于该属性。我认为这种关系中可能存在很多耦合和责任,Apple没有为大众清理干净。例如,我注意到在向上移动导航层次结构时出现了奇怪的取消选择行为,我无法解决。也许UINavigation控制器反映了其顶部控制器的类并且表现不同?
总之,它确实是只读的,没有简单干净的解决方法,你只需要绕过它来设计架构。

0

看起来调用 setParentViewController: 方法是有效的。

[childViewController setParentViewController:self];

然而,这仍会生成编译器警告。在我看来,这意味着不要这样做(而是进行子类化)。

0

然而,由于它是只读的,我找不到其他设置此属性的方法,我的问题是:我该如何设置它?

如果它是readonly,你不能使用点符号表示法,否则会出现编译错误

但是,你可以使用分类UIViewController类添加自定义的modifyParentViewController方法。

即使这个属性是只读的,如果它不是@protected,那么变量本身可能是可修改的。如果它是@protected,那么子类化视图控制器可能允许你修改变量的选项。


这样做对我来说有点太粗糙了,但我想如果我坚持使用parentViewController,这几乎是唯一可能的方法。<br>不过我会使用自定义的UIViewController属性。 - mrueg
在父视图控制器上添加 addChildViewController 是正确的做法。 - Eric

0

parentViewController 属性用于导航控制器和模态视图控制器的使用,没有办法在不使用 pushViewController 或 presentModalViewController 方法的情况下设置该属性。parentViewController 是一个只读属性,只能由 UIViewController 类和 UINavigationController 类读取,这些类的子类将无法访问设置该属性的方法。


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