ObjectiveC - [self.view viewWithTag]返回null

时间:2015-11-24 08:35:21

标签: ios objective-c uiview hidden

我完全难过,并且已经研究了好几天。可能是我遗失的非常简单的东西。

我有一个ViewController,其中包含一个名为GameView的自定义UIView,以及一个名为buttonBox的UIView,其中包含一个"下一个级别"按钮。我想要实现的是当在GameView中完成关卡时,它会在我的ViewController中触发一个显示buttonBox的函数,这样用户就可以点击"下一级"按钮。它根本行不通。

我尝试了3种方式,但都没有效果:

  • IBOutlet中创建ViewController,将其连接到隐藏的UIView(并且肯定已连接)并致电setHidden:NO
  • 致电[self.view viewWithTag:xxx],然后致电setHidden:NO
  • 使用hidden=NO代替setHidden:NO

ViewController的相关代码如下:

@interface PlayViewController : UIViewController
@property GameView *gv;
@property (strong, nonatomic) IBOutlet UIView *buttonBox;
-(void) showButtonBox;
@end

@implementation PlayViewController
@synthesize buttonBox;
...
- (IBAction)showButtonBox {
    UIView *uiv = (UIView*) [self.view viewWithTag:999];
    dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"Showing box function");
        NSLog(@"%@", uiv);
        uiv.hidden = NO;
    });
}
@end

我的自定义视图:

@implementation GameView
...
   dispatch_async(bgQueue, ^{
        _loopRunning = true;
        //NSLog(@"Calling main loop...");
        while ([self loopRunning])
        {
             ...
             PlayViewController * pvc = [[PlayViewController alloc]init];
             [pvc showButtonBox];
             ...
         }
@end

问题是,变量uiv在NSLog中返回null,这显然是隐藏不起作用的原因,但我不明白为什么。当我使用IBOutlet时,它也没有用。

此外,NSLog的当前输出如下:

2015-11-24 00:18:38.612 ib[12579:1264539] Showing box function
2015-11-24 00:18:38.612 ib[12579:1264539] (null)

提前致谢。

正确答案:

问题在于我使用StoryBuilder来构建我的UI,但是使用alloc init方法创建了一个新的视图控制器(从未显示过),而不是正确引用正在显示的视图控制器。这是通过将显示的视图控制器传递给viewDidLoad函数中的视图来实现的,请参见下文:

@implementation PlayViewController
@synthesize buttonBox;
@synthesize gv;

- (void)viewDidLoad
{
    [super viewDidLoad];
    gv = [self.view viewWithTag:777];
    [gv setPlayViewController:self];
}
...

2 个答案:

答案 0 :(得分:1)

男人,这很简单。我们来看看:

@implementation GameView
...
   dispatch_async(bgQueue, ^{
        _loopRunning = true;
        //NSLog(@"Calling main loop...");
        while ([self loopRunning])
        {
             ...
             PlayViewController * pvc = [[PlayViewController alloc]init];
             [pvc showButtonBox];
             ...
         }
@end

我们遇到了这个问题:

  

dispatch_async(bgQueue,^ {

我认为,bgQueue代表“后台队列”,这意味着主线程(UI线程)不提供此服务。 话虽如此,期待

非常天真
  

[pvc showButtonBox];

正常工作。只需将此代码移动到主线程中即可。例如,您可以将上述代码行包装到主队列中的dispatch_async。如果您的插座和/或标签没问题,这应该可以解决您的问题。欢呼声。

答案 1 :(得分:0)

[[PlayViewController alloc]init];

这将创建PlayViewController的新实例。你在哪里定义了你的网点和观点?

  • 在故事板中?您无法使用此初始化工具 - 故事板中的任何内容都不会被选中,您必须使用segue或initializeViewControllerWithIdentifier:
  • 在xib文件中?它叫PlayViewController.xib吗?如果没有,它将不会被初始化者接收。视图控制器的普通alloc/init只会找到documentation of the nibName property中所述的nib文件。
  • 你真的想要alloc / init吗?你真的想制作一个新的视图控制器,还是已经出现在屏幕上?

从您的评论看来,选项3似乎是正确的答案。 PlayViewController已经在屏幕上,alloc/init正在创建一个新的实例,它永远不会被放在屏幕上,无论故事板还是笔尖都不会加载任何视图。

您需要获得对PlayViewController现有实例的引用。如果不知道应用程序的结构,那么说它是如何完成的 - 它是不是很容易呈现游戏视图?游戏视图是视图控制器视图的子视图吗?您可能需要在创建游戏视图时将参考(弱)传递到viewDidLoad,或在故事板中设置插座。