0

我是 iOS 编程的新手,所以我想从头开始制作这个东西,以便能够理解整个东西是如何工作的。因此,我没有使用主详细信息模板,而是从头开始这样做。

在主视图和详细视图之间传递数据方面,我遇到了巨大的障碍。目前,每当我点击主视图的项目时,它都会在细节视图控制器上查找第一个视图,我们称之为mainswitchviewcontroller. 它是第一个ViewController通过 segue 连接到UINavigationController详细控制器部分(请参见下图)。

这发生在登录后显示viewcontroller,我希望用户在访问整个应用程序之前选择一个选项。这将引导他们进入ViewController流程的最后一个(请参阅下图 - 红色圆圈)。

流程图

现在我想做的是:

@interface MasterListViewController : UITableViewController{
}

@property (nonatomic) int matNum;
@property (strong, nonatomic) DetailStaffMainContentViewController *detailViewController;
@end

:
:

@implementation MasterListViewController
@synthesize matNum;
:
:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{

    for(UIViewController *vc in self.splitViewController.viewControllers){
        NSLog(@"%@)", vc.title);
    }

    self.detailViewController.teststring = @"gronk";
}

这是我的 detailViewController(我想访问的那个)

@implementation DetailStaffMainContentViewController
@synthesize tableView;
@synthesize teststring;
@synthesize lblOutput;

现在在选择行时,我分配了teststring我想用来填充控制器上的标签的行。这就是我所做的。

我的问题是:

  1. 我收到一个错误。想知道我做错了什么?

    [MainSwitchBoardViewController setTeststring:]: unrecognized selector
    sent to instance 0x7572190
    
  2. 这是传递数据的推荐方式吗?还是我应该坚持使用通知中心?

想法?

编辑 只是为了让您了解应用程序的流程:

  1. 用户登录(如果用户名不存在,会弹出浮动视图控制器并强制用户登录。

  2. 一旦用户登录,弹出窗口就会消失,然后询问用户在当前会话中使用什么类型的角色(例如,职员或战士)。

  3. 如果用户选择斗士,则将用户推到顶部 VC 如果用户选择人员,则将用户推到底部 VC(集合控制器)

  4. 对于员工:目前我正在使用这个 [self perfermSegueWithIdentifier:sender:self] 推送到最后一个 VC

    一旦用户看到最后一个 VC (DetailsS​​taffView),我希望这是用户进行交易的主要详细信息视图。还有几个弹出窗口?(或者可能需要为特定交易添加另一个推送到另一个 VC)。但最终我不希望用户访问第一个 Viewcontroller (MasterSwitchBoard)

编辑 2 这是控制登录后第一个 VC 的主交换机板类。

@interface MainSwitchBoardViewController : UIViewController{

}

@property (strong, nonatomic) IBOutlet UILabel *txtLabel;
- (IBAction)btnStaff:(id)sender;
- (IBAction)btnAdmin:(id)sender;

@end

这是 atm 自动推送到最后一个 VC 的集合 VC。一开始我使用了一个通知,但似乎没有必要,所以我把它拿出来了。

@interface MatListCollectionViewController ()

@end

@implementation MatListCollectionViewController
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    [self performSegueWithIdentifier:@"SeguePushToStaffDetailFromMats" sender:self];
}

然后是细节工作人员

@interface DetailStaffMainContentViewController : UIViewController{

}

@property (strong, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, retain) IBOutlet UILabel *lblOutput;
@property (nonatomic, retain) NSString *teststring;

@end


    @implementation DetailStaffMainContentViewController
    @synthesize tableView;
    @synthesize teststring;
    @synthesize lblOutput;
4

2 回答 2

3

我将以相反的顺序处理这些问题:

这是传递数据的推荐方式吗?还是我应该坚持使用通知中心?

理论上你可以使用通知中心,但在这种情况下我不会。就个人而言,我只在以下情况下使用NSNotificationCenter

  • 我正在做异步过程,它没有合理的方式知道视图控制器的状态(例如,我有一些后台任务正在从服务器更新一些耗时的数据,并且用户可以导航到几乎任何地方在我准备好通知视图控制器更新完成时应用程序);和/或

  • 我可能有多个对象要通知某些事件。

这些条件都不适用于这里。当然你可以使用NSNotificationCenter,但这应该是不必要的。显式设置属性通常是可取的。

我收到一个错误。想知道我做错了什么?

不幸的是,根据您迄今为止提供的证据,很难说。但是根据您的代码和注释,我无法协调一些事情:

  • 您已声明detailViewController为一个DetailStaffMainContentViewController(这就是您为其合成teststring访问器的类);

  • 但是您的错误消息表明这detailViewController显然是一个MainSwitchBoardViewController对象(它不理解setTeststring访问器方法);和

  • 你还没有向我们展示你是如何设置detailViewController的,所以很难说你在哪里出错了。

就个人而言,在这种情况下,我总是不愿定义属性来维护指向视图控制器的指针。我通常倾向于问分裂UISplitViewController中有什么。detail因此,在我的主视图控制器中,我没有一个类属性/ivar,而是有一个类似的方法:

- (UIViewController *)detailViewController
{
    return [[self.splitViewController.viewControllers lastObject] topViewController];
}

这基本上是说“从我的拆分视图控制器的viewControllers(详细拆分)数组中获取最后一个对象,并且因为我(个人)总是在该详细拆分中使用导航控制器,所以让我们使用topViewController来获取指向我的子类的指针UIViewController,即详细信息拆分(嵌入在导航控制器中)。

然后我didSelectRowAtIndexPath检查该视图控制器是否是我所期望的。如果没有,我继续使用它(并将prepareSegue我想要的数据传递给该控制器)。

因此,例如,考虑这个故事板:

示例故事板

在这里,“A”是我的默认细节控制器。“B”可能是我可能用“A”替换的一些随机场景。“C”是我真正的细节视图控制器,我可以在其中看到我从主视图控制器的表视图中选择的项目的详细信息。因此,我didSelectRowAtIndexPath的主视图控制器可能看起来像:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIViewController *controller = [self detailViewController];

    if (![controller isKindOfClass:[DetailCViewController class]])
    {
        // if I'm not already showing "C" in my detail split, then let's segue to it

        [self performSegueWithIdentifier:@"GoToC" sender:self];
    }
    else
    {
        // if I'm already showing "C" in my detail split, let's just set the item of data I want to pass to it

        DetailCViewController *cController = (DetailCViewController *)controller;

        cController.detailItem = self.objects[indexPath.row];
    }

    // I have a method I call to make sure that the popover menu for the master view
    // controller disappears (in case it popped up since I was in portrait mode) and
    // adds the master view controller button to the navigation bar if I need it.

    [self removePopoverAndAddNavigationButton];
}

如果我需要转到“C”,我还让我的`prepareSegue 根据需要传递detailItem:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"GoToC"])
    {
        DetailCViewController *cController = (DetailCViewController *)[segue.destinationViewController topViewController];

        cController.detailItem = self.objects[[[self.tableView indexPathForSelectedRow] row]];
    }
}

正如我所说,试图弄清楚为什么你detailViewController的对象类型错误很难说,但这就是我可能解决这样的事情的方法。

于 2013-02-19T05:24:59.050 回答
2

也许你应该先看看上届 WWDC上一些描述 Storyboard Segues 的好电影。

在您提供的代码中,没有任何关于 segue 的内容。请务必通过 IB 或以编程方式通过[self performSegueWithIdentifier:]. 请参阅 Apple 文档

然后你可以在你的视图控制器中提供额外的操作:

  • [view shouldPerformSegueWithIdentifier:sender:]
  • [view prepareForSegue:sender:]

第一个决定是否执行segue。第二个是在 segue 执行之前执行的。在第二个操作中,您可以向destinationViewController 提供信息。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if([segue.identifier isEqualToString:@"showIssuesByProject"]){
        if (_searchActive) {
            ((IssueListViewController *)segue.destinationViewController).project = [_filteredProjects projectAtIndex:[self.tableView indexPathForSelectedRow].row];
        } else {
            ((IssueListViewController *)segue.destinationViewController).project = [_projects projectAtIndex:[self.tableView indexPathForSelectedRow].row];
        }
    }
    if ([segue.identifier isEqualToString:@"showIssuesByFilter"]) {
        ((IssueListViewController *)segue.destinationViewController).filter = [_filters filterAtIndex:[self.tableView indexPathForSelectedRow].row];
    }
}

注意: UISplitViewControll.viewControllers 只有两个控制器:主控制器和细节控制器。

于 2013-02-18T15:52:49.107 回答