无法协调视图控制器

时间:2013-02-04 16:48:18

标签: ios objective-c uiviewcontroller delegation

我在我的应用程序中构建了以下视图控制器。呈现控制器是“PatientSelectViewController”(让我们称之为控制器A),它允许在文本字段中手动输入患者ID或按下“扫描条形码”按钮,该按钮将执行到另一个视图控制器的segue - 即“BarcodeScanViewController” “(我们称之为控制器B)。

当B完成扫描条形码并返回结果(患者ID)时,我通知呈现视图控制器(A)有关它,A负责在数据库中查找ID。此时控制器B应该被解雇。如果找到了ID,那么我们转换到第三个视图控制器 - “PatientConfirmViewController”(让我们称之为C)。但是,如果找不到ID,那么我想要一条弹出消息,然后再次向控制器B再次扫描条形码。

同样,如果用户决定在文本字段中手动输入ID而不是扫描它,那么成功的ID会将我带到控制器C,而不成功的ID会给出弹出消息并保留在控制器A中再试一次。

我还希望将控制器嵌入到导航控制器中,这样我总是有tabbar按钮可以让我回到上一个视图控制器。例如,我将有一个标签栏按钮从B或C返回A.理想情况下,如果我在条形码扫描成功后到达C,我希望标签栏按钮将我带回B - 而不是A! - 如果用户决定她不想确认该ID,则该想法是用户可能想要重新扫描条形码。但这并不重要。

由于某种原因,我无法实现此功能。这是一个搞砸行为的例子:我正在调用A然后调用B(扫描条形码)并扫描我知道在数据库中的条形码。这正确地将我带到C并显示患者信息。但后来我决定使用标签栏按钮“输入患者ID”返回A然后我再次按下“扫描条形码”按钮,再次扫描相同的条形码,但这次没有成功转换到C,我得到了这个屏幕 - 注意搞砸的tabbar!它必须同时说“确认ID”和“输入患者ID”并且按钮返回登录(这是首先调用A的控制器)和“扫描条形码” - 即控制器B好像它以前从未弹出过! screwed up tabbar 这可以在2或3次或更多次成功扫描后随机发生。日志显示如下:

  

嵌套推送动画可能导致导航栏损坏

     

对开始/结束外观转换的不平衡调用   。

     

完成导航   转变为意外状态。导航栏子视图树可能   腐败了。

以下是我实施它的方式:

在视图控制器A中:

-(void)prepareForSegue: (UIStoryboardSegue *)segue sender: (id)sender
{
    if ([[segue identifier] isEqualToString:@"BarcodeScanView"])
    {
        self.p_usingBarcodeScan=YES;
        [[segue destinationViewController]setViewDelegate:self]; //sets itself as a delegate for receiving the result of a barcode scan from controller B 
    }
    if ([[segue identifier] isEqualToString:@"ConfirmID"])
    {
        [[segue destinationViewController] setP_userInfo:p_userInfo]  ; //passes the data to the controller C
    }
}

接收条形码扫描结果的委托方法(仍在控制器A中):

- (void) didScanBarcode:(NSString *)result
{

    self.p_userID = result;

    [self.navigationController popViewControllerAnimated:YES];//Pop B from the navigation stack to return to A - is this right????

    //Run the database query
    [self lookUpID];
}

在数据库中查找ID的方法(仍在A中):

- (void) lookUpID{


    /*.....
    Does something here and gets a result of the lookup...
    */

    // Do something with the result
    if ([[result  p_userName] length] > 0 ){ //Found the user!
        p_userInfo = result;
        [self performSegueWithIdentifier: @"ConfirmID" sender: self];

    }
    else {
        UIAlertView * messageDlg = [[UIAlertView alloc] initWithTitle:nil message:@"User was not found. Please try again"
                                                             delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
        [messageDlg show];

        //Here I'd like to perform this seque to B only if I got here after a barcode scan... 
        //Otherwise I am just staying in A...
        if (self.p_usingBarcodeScan == YES ){
            [self performSegueWithIdentifier: @"BarcodeScanView" sender: self];
        }  
    }
    return;
}

为了完整起见,在B设法扫描条形码后,我称之为:

- (void)decodeResultNotification: (NSNotification *)notification {

    if ([notification.object isKindOfClass:[DecoderResult class]])
    {
        DecoderResult *obj = (DecoderResult*)notification.object;
        if (obj.succeeded)
        {
            decodeResult = [[NSString alloc] initWithString:obj.result];

            [[self viewDelegate] didScanBarcode:decodeResult];
        }
    }
}

我正在使用从A到B以及从A到C并使用故事板的推送序列。 这是故事板的快照,其中可以看到从A到B(“BarcodeScan”)和A到C(“ConfirmID”)的段。两者都是push segues:

storyboard snapshot

提前多多感谢!

2 个答案:

答案 0 :(得分:0)

您没有说明您当前是使用导航控制器还是推送segues,还是使用模态segues进行演示。

下面:

    [self.navigationController popViewControllerAnimated:YES];//Pop B from the navigation stack to return to A - is this right????
    [self dismissViewControllerAnimated:YES completion:nil];**//is this right???**

第一个对于从推送segue返回是正确的,第二个适用于模态/呈现segue。推送返回方法实际上是在导航控制器中使用后退按钮时发生的情况。

<强>更新 我想你需要稍微解开你的导航方法。我的建议

  • 在B中,有一个委托方法

    • 检查患者ID
    • 如果好的话,在A
    • 中设置self.p_userID
    • 将BOOL成功/失败返回到B.
      _
  • 基于该结果:

    • 让自己离开(你可以直接在B)中使用[self.navigationController popViewController]

    • 在B 中显示提示。鉴于您在B中有一个后退按钮,并且(可能)有一个重新扫描按钮,您的警报可能不需要提供任何选择。

A

- (void) viewWillAppear:(BOOL)animated
{
    NSLog (@"viewControllers %@",self.navigationController.viewControllers);

    [super viewWillAppear:animated];
    if (self.p_userID) {
        [self performSegueWithIdentifier: @"ConfirmID" sender: self];
        self.p_userID = nil;
    }
}

(只有在你还在B的时候设置了self.p_userID才会发生这个performSegue)

键入的userID逻辑更简单。再次检查患者ID。如果它不存在,则在A中抛出警报(同样,您不应该提供选择,因为所有导航选项都可用而没有警报)。如果存在,请将self.p_userID设置为ID并启动segue。

prepareForSegue中,您应该进行查找以从self.p_userID获取userInfo字典以传递给C,然后将self.p_userID设置为nil。或者(更好)只需将self.p_userID传递给C并在C中进行查找(假设您有一个单独的模型源对象)。无论你做什么,每当你离开A时,一定要将self.p_userID设置为nil,这样你就不会自动触发你不想要的segue!也许在'viewWillDisappear'中也可以为零。

答案 1 :(得分:0)

好的,我正试图部分回答我自己的问题。 即使在实施了上述建议之后,我的麻烦仍然存在甚至成倍增加(关于这些的一些细节在我在讨论主题http://chat.stackoverflow.com/rooms/23918/discussion-between-peterd-and-he-was的评论中)

然而,通过一些更改我搜索了我得到的日志消息:“嵌套推送动画可能导致导航栏损坏”并且最后阅读了这个答案:https://stackoverflow.com/a/5616935/1959008,这表明我的问题是使用

   [self.navigationController popViewControllerAnimated:YES]; 

将动画设置为YES。一旦我将它设置为NO,tabbar的问题就消失了(一些小怪怪仍然存在,我希望很快就能解决它们)。这真的很奇怪 - 看起来更像是一个错误,而不是一个功能,但我当然可能是错的......