我是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
,我想用它来填充控制器上的那个标签。这就是我做的。
我的问题是:
我收到了错误消息。想知道我做错了什么?
[MainSwitchBoardViewController setTeststring:]: unrecognized selector
sent to instance 0x7572190
这是一种传递数据的推荐方法吗?或者我应该坚持使用通知中心?
思想?
修改 只是为了向您介绍应用程序的流程:
用户登录(如果用户名不存在,将弹出浮动视图控制器并强制用户登录。
一旦用户登录,弹出窗口就会消失,然后询问用户当前会话中将使用哪种角色(例如,工作人员或战斗机)。
如果用户选择战斗机,它会将用户推送到顶级VC如果用户选择人员,则会将用户推送到底部VC(集合控制器)
FOR Staff:目前我正在推动最后一个VC [self perfermSegueWithIdentifier:sender:self]
一旦用户看到最后一个VC(DetailsStaffView),我希望这是用户进行交易的主要详细信息视图。还有一些弹出窗口? (或者可能需要另外推送另一个VC以满足特定交易)。但最终我不希望用户访问第一个Viewcontroller(MasterSwitchBoard)
编辑2 这是主要的交换机板类,它在登录后控制第一个VC。
@interface MainSwitchBoardViewController : UIViewController{
}
@property (strong, nonatomic) IBOutlet UILabel *txtLabel;
- (IBAction)btnStaff:(id)sender;
- (IBAction)btnAdmin:(id)sender;
@end
这是收集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;
答案 0 :(得分:3)
我将以相反的顺序处理这些问题:
这是一种传递数据的推荐方法吗?或者我应该坚持使用通知中心?
理论上你可以使用通知中心,但在这种情况下我不会。就个人而言,我只使用NSNotificationCenter
if:
我正在进行异步处理,没有合理的方式知道视图控制器的状态(例如,我有一些后台任务正在花费一些时间从服务器更新数据,用户可能已经导航当我准备好通知视图控制器更新完成时,到app中的任何地方;和/或
我可能有多个对象要通知某些事件。
这些条件都不适用于此。当然你可以使用NSNotificationCenter
,但这应该是不必要的。通常优选明确设置属性。
我收到了一个错误。想知道我做错了什么?
不幸的是,根据您迄今为止提供的证据,很难说。但是有些事情我在你的代码和评论的基础上难以协调:
您已将detailViewController
声明为DetailStaffMainContentViewController
(这是您已合成teststring
个访问者的类;
但是您的错误消息表明detailViewController
显然是MainSwitchBoardViewController
对象(不理解setTeststring
存取方法);以及
您尚未向我们展示您如何设置detailViewController
,因此很难说您在这里出错了。
就个人而言,在这样的情况下,我总是沉默寡言来定义属性来维护指向视图控制器的指针。我一般倾向于问UISplitViewController
detail
分裂中的- (UIViewController *)detailViewController
{
return [[self.splitViewController.viewControllers lastObject] topViewController];
}
。所以,在我的主视图控制器中,我没有类属性/ ivar,而是有一个类似的方法:
viewControllers
这基本上是说“从我的分割视图控制器的topViewController
数组中获取最后一个对象(细节分割),因为我(个人)总是在细节分割中使用导航控制器,让我们使用{{1获取指向我的子类UIViewController
的指针,该指针位于该细节分割中(嵌入在导航控制器中)。
然后我进行了didSelectRowAtIndexPath
检查以查看该视图控制器是否符合我的预期。如果没有,我就转向它(并让prepareSegue
将我想要的数据传递给该控制器)。
因此,例如,考虑一下这个故事板:
这里,“A”是我的默认细节控制器。 “B”可能是一些随机的场景,我可能用“A”替换了“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
有错误类型的对象很难说,但这就是我可以解决的问题。
答案 1 :(得分:2)
也许你应该首先看看他们描述Storyboard Segues的一些不错的movies from the last WWDC。
在您提供的代码中,没有任何关于segues的文章。请务必通过IB或通过[self performSegueWithIdentifier:]
以编程方式使用segues。 See Apple Docs
然后,您可以在视图控制器中提供其他操作:
[view shouldPerformSegueWithIdentifier:sender:]
[view prepareForSegue:sender:]
第一个决定是否执行segue。第二个是在执行segue之前执行的。在secon操作中,您可以向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只有两个控制器:主控制器和详细控制器。