Iphone 在ViewController和TabBar子级之间传递数据

Iphone 在ViewController和TabBar子级之间传递数据,iphone,ios,objective-c,uitableview,uitabbarcontroller,Iphone,Ios,Objective C,Uitableview,Uitabbarcontroller,我正在开发一个具有TableView的应用程序。当我按下任何单元格时,应用程序将转到下一个ViewController。在这个viewController中,我通过代码创建了一个TabBarController,它有3个子viewController。因此,我想将一个变量从TableView传递给TabBar的子级。我可以将变量传递到TabBar,我已经用NSlog函数观察了它。对我来说,这真的很奇怪,在子视图控制器中,我也有一个NSlog类型,变量为null,但在输出中我首先看到了这一点 20

我正在开发一个具有TableView的应用程序。当我按下任何单元格时,应用程序将转到下一个ViewController。在这个viewController中,我通过代码创建了一个TabBarController,它有3个子viewController。因此,我想将一个变量从TableView传递给TabBar的子级。我可以将变量传递到TabBar,我已经用NSlog函数观察了它。对我来说,这真的很奇怪,在子视图控制器中,我也有一个NSlog类型,变量为null,但在输出中我首先看到了这一点

2013-10-01 03:01:40.687 Prototype[38131:c07] proId (null) // This is the children log from vc2 ViewController  "YPProjectViewController"
2013-10-01 03:01:40.697 Prototype[38131:c07] projectID 433 // This is the TabBar LOG YPTabBarViewController 
有人知道为什么我可以先把孩子们记录下来吗?也许有解决办法

#import "YPTabBarViewController.h"
#import "YPProjectViewController.h"
#import "YPCommentsViewController.h"
#import "YPProposalsViewController.h"

@interface YPTabBarViewController ()
@property (nonatomic,strong)UITabBarController *tabBar;
@end

@implementation YPTabBarViewController
@synthesize tabBar;
@synthesize projectId = _projectId;

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setUpTabBar];

}

// Set up tabBar
-(void)setUpTabBar
{

        YPCommentsViewController *vc1 = [[YPCommentsViewController alloc] init];
        vc1.title = @"Comments";
        vc1.view.backgroundColor = [UIColor clearColor];
        UINavigationController *contentNavigationController = [[UINavigationController alloc] initWithRootViewController:vc1];

        YPProjectViewController *vc2 = [[YPProjectViewController alloc] init];
        vc2.title = @"Project";
        vc2.view.backgroundColor = [UIColor clearColor];

        vc2.proId = _projectId;
        NSLog(@"PROJECT ID %@", vc2.proId);
       // UINavigationController *contentNavigationController2 = [[UINavigationController alloc] initWithRootViewController:vc2];


        YPProposalsViewController *vc3 = [[YPProposalsViewController alloc] init];
        vc3.title = @"Proposal";
        vc3.view.backgroundColor = [UIColor clearColor];
        UINavigationController *contentNavigationController3 = [[UINavigationController alloc] initWithRootViewController:vc3];
        tabBar = [[UITabBarController alloc] init];
        tabBar.viewControllers = @[contentNavigationController,vc2,contentNavigationController3];
        tabBar.selectedIndex   = 1;

        [tabBar.view setAutoresizingMask:UIViewAutoresizingFlexibleHeight];
        [tabBar willMoveToParentViewController:self];
        [self addChildViewController:tabBar];
        [tabBar didMoveToParentViewController:self];
        [self.view addSubview:tabBar.view];

}

为了理解问题,您在“选项卡栏控制器”中的
NSLog
语句在设置后立即记录
vc2.proID
的值。但是您的NSLog输出显示,第二个选项卡的视图控制器正在记录之前的结果。这就是为什么当第二个选项卡的视图控制器的
viewdiload
记录它时,它是
nil
,因为该日志发生在选项卡栏控制器有机会设置值并记录它自己之前

因此,有几种方法可以解决此问题:

  • 就在分配
    vc2.proId
    之前,您有一行无害的代码,上面写着:

    vc2.view.backgroundColor = [UIColor clearColor];
    
    该代码行触发要加载的第二个视图控制器的视图(将调用其
    viewDidLoad
    )。如果在开始访问任何
    vc2
    视图之前将
    vc2.proId
    的赋值移动到,则会更改
    NSLog
    语句的显示顺序(或者,更好的是,将背景色设置移动到子控制器的
    viewDidLoad

  • 您可以创建自己的
    init
    方法,该方法接受项目id作为参数。这也将确保它设置在
    viewDidLoad
    之前。因此,
    YPProjectViewController
    可以有如下方法:

    - (id)initWithProjectId:(NSString *)projectId
    {
        self = [self init];
    
        if (self)
        {
            _proId = projectId;
        }
    
        return self;
    }
    

  • 关于自定义容器调用的两个不相关的观察结果:

  • 当您调用
    addChildViewController
    时,它会为您调用
    willMoveToParentViewController
    。因此,您应该删除对
    willMoveToParentViewController
    的调用。看

  • 您甚至可能希望完全取消这些自定义容器调用,只需将
    yptabarviewcontroller
    本身作为
    uitabarcontroller
    的子类,而不是
    UIViewController
    。这样就完全不需要自定义容器调用。显然,如果您对定制容器有其他需求,那么请放心,但是在这个代码示例中它是多余的


  • 对不起,我已经编辑了这个问题。你说的是真的你是这个意思吗
    @implementation YPProjectViewController-(id)init{self=[super init];if(!self)return nil;NSLog(@“proId%@,_proId”);return self;}
    但是,我不是在init中查看它,我这样做是为了向您展示,我在ViewDidLoadI中显示proId log我想说的和Rob在这里说的差不多。我想补充一点,在我看来,您在这里设置的大多数控制器属性都应该由控制器自己处理。标题和背景色。didmoves和willmoves当然不属于这里。我将推荐Rob关于自定义启动器的想法,这些视图之间的任何其他通信都应通过委托/协议或NSNotification(视情况而定)进行处理。@DeanDavids同意。顺便说一句,这不仅仅是一个好的样式问题,还有性能/内存方面的原因,不让这个选项卡栏控制器不尝试更新子控制器的
    视图
    对象。如果选项卡栏控制器访问每个子视图,它将提前加载所有这些视图。没有理由遭受这种(适度的)打击。如果将这些视图更新延迟到相应子级的
    viewDidLoad
    ,则在您完全需要它们之前(例如,用户点击该选项卡)不会创建它们的视图。因此,启动速度更快,占用内存更少。