iPad - DetailViewController programmatically - ios

I'm working on an iPad app where I use UISplitViewController. I also use DetailViewController in which to display some information from XML, but the information is not displayed in DetailViewController but in MaterViewController. I really do not know how to fix it. Can you please help. Thank you
There is code:
-(void) showDetailsForIndexPath:(NSIndexPath*)indexPath
{
[self.searchBar resignFirstResponder];
DetailViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"DetailsViewController"];
Slova* slova;
if(isFiltered)
{
slova = [filteredTableData objectAtIndex:indexPath.row];
}
else
{
slova = [self.slovoArray objectAtIndex:indexPath.row];
}
vc.slovoItem = slova;
[self.navigationController pushViewController:vc animated:true];
}

The reason is that you're pushing the new UIViewController onto the stack for self, which is presumably the MasterViewController. Instead, create a new project using Apple's Master-Detail Application and you'll see how they do it.
Caveat: they use Storyboards, but it is very possible to do this all in code.
In Apple's example, both the MasterViewController and the DetailViewController are visible from the start (in landscape).
Look how Apple's example sets detailItem (slovoItem?) for DetailViewController:
#pragma mark - Segues
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSDate *object = self.objects[indexPath.row];
DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
[controller setDetailItem:object];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
}
}
So, you'll have DetailViewController already visible and you'll just update its detailItem property.
Therefore, the following code exists in DetailViewController:
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}

Related

How to pass data from one ViewController to another after using Segue?

I went from one ViewController to another using Segue in my second viewController has an UITableView. now, I want to push from second ViewController's didSelected method to another viewController.
code use to Segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
self.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
SearchVC *svc = segue.destinationViewController;
self.providesPresentationContextTransitionStyle = YES;
self.definesPresentationContext = YES;
}
under button action:
-(void) searchButtonClicked:(id)sender {
[self performSegueWithIdentifier:#"search" sender:nil];
}
And the main problem arise here, can't navigate using below code:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
PackageListVC *pdvc = (PackageListVC *)[self.storyboard instantiateViewControllerWithIdentifier:#"PackageListVC"];
pdvc.strServiceProviderId = [[[arrSearch objectAtIndex:indexPath.row] objectForKey:#"ServiceProviderId"] stringValue];
pdvc.strCategoryId = [[[arrSearch objectAtIndex:indexPath.row] objectForKey:#"CategoryId"] stringValue];
pdvc.strSubCategoryId = [[[arrSearch objectAtIndex:indexPath.row] objectForKey:#"SubCategoryId"] stringValue];
pdvc.strTitle = [[arrSearch objectAtIndex:indexPath.row] objectForKey:#"CompanyName"];
[self.navigationController pushViewController:pdvc animated:YES];
}
You do it in the prepareForSegue method.
where you declare svc (SearchVC *svc = segue.destinationViewController;) you can say something like:
svc.variable = 1;

Persist view controller state in SWRevealViewConttoller in iOS?

I am using SWRevealViewController for navigation drawer in iOS.I have one main screen which is shown by default when app launches.I have also other screens like Settings,Help,About. So when user switch between screens then state of 1st view controller is reset.I want to persist it's state lie if was showing some data in screen then it should not get removed.
I am using below code to switch between screens.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
if(indexPath.row==0)
{
[self performSegueWithIdentifier:#"home" sender:cell];
[cell setSelected:YES];
}
else if(indexPath.row==1)
{
[self performSegueWithIdentifier:#"settings" sender:cell];
}
else if(indexPath.row==2)
{
[self performSegueWithIdentifier:#"help" sender:cell];
}
else if(indexPath.row==3)
{
[self performSegueWithIdentifier:#“about” sender:cell];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Segue");
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
destViewController.title = [[titles objectAtIndex:indexPath.row] capitalizedString];
if([segue.identifier isEqualToString:#"settings"])
{
self.revealViewController.navigationItem.title = #"Settings";
}
else if([segue.identifier isEqualToString:#"help"])
{
self.revealViewController.navigationItem.title = #"help";
}
else if([segue.identifier isEqualToString:#"about"])
{
self.revealViewController.navigationItem.title = #"about";
}
if([segue isKindOfClass:[SWRevealViewControllerSegue class]])
{
SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: #[dvc] animated: NO ];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
};
}
}
One solution I see that to keep the viewController in the navigation stack so that the viewController not get destroyed it remains in the stack when user go to "home" then it is relaunched from navigation stack instead of initializing the view controller again.
For example for HelpVC , you store a property of it in your side mennu view controller:
#property (nonatomic, strong) HelpViewContoller* helpVC;
Than in row selection instead of calling your segue, you instantiate the view controller, but before that you check if it is instantiated already you use it:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell=[self.tableView cellForRowAtIndexPath:indexPath];
if(indexPath.row==0) {
if (helpVC == nil) {
helpVC = [self.storyboard instantiateViewControllerWithIdentifier:#"helpVCidentifier"];
[self changeFrontVCto:helpVC];
}
}
}
-(void) changeFrontVCto:(UIViewController*)vc {
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: #[vc] animated: NO ];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
}

Touch cell and open a new view controller

The following code is in my menuViewController.m. Now I want to go to another view when touch on a specific cell. What should I do to go to contactViewController?(I am using storyboard)
storyboard image:
https://drive.google.com/file/d/0BwOYR2GMJ7l8U1lYYVFVTWVkOG8/edit?usp=sharing
code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
NSString *CellIdentifier = [menuItems objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if(indexPath.row==2)
{
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Set the title of navigation bar by using the menu items
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
UINavigationController *destViewController = (UINavigationController*)segue.destinationViewController;
destViewController.title = [[menuItems objectAtIndex:indexPath.row] capitalizedString];
if ( [segue isKindOfClass: [SWRevealViewControllerSegue class]] ) {
SWRevealViewControllerSegue *swSegue = (SWRevealViewControllerSegue*) segue;
swSegue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc) {
UINavigationController* navController = (UINavigationController*)self.revealViewController.frontViewController;
[navController setViewControllers: #[dvc] animated: NO ];
[self.revealViewController setFrontViewPosition: FrontViewPositionLeft animated: YES];
};
}
I want to go to another view when touch on a specific cell.
For this, I'd do it this way:
Step 1:
Drag from TableViewController to ContactViewController:
Step 2:
Select segue and specify the Segue Identifier (Show attributes Inspector tab in the right side bar)
I have named the Segue Identifier as SegueTestID
I chose Push as my style but it seems you might need Modal
And the corresponding code (in your MenuViewController.m) should be something like:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == 2) {
[self performSegueWithIdentifier:#"SegueTestID" sender:self];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//following lines needed only if you need to send some detail across to ContactViewController
if ([segue.identifier isEqualToString:#"SegueTestID"]) {
ContactViewController *destinationViewController = segue.destinationViewController;
destinationViewController.strTest = #"Check";
//where strTest is a variable in ContactViewController. i.e:
//"#property (nonatomic, strong) NSString *strTest;"
//declared in `ContactViewController.h`
}
//...
}
PS: It seems you have alot in your -prepareForSegue: already.
Obviously... you'll need to hook things up properly.
In Storyboard , Do this ( In your case its contactviewcontroller ) give the name identifier name to contactViewController whatever you want as shown in image for showRecipeDetail
and you can go to the contactviewcontroller
and then
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showRecipeDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
RecipeDetailViewController *destViewController = segue.destinationViewController;
destViewController.recipe = [recipes objectAtIndex:indexPath.row];
}
}
In above method it shows how to pass the data from current viewcontroller to destviewcontroller
where We simply set the property (i.e. recipeName) in the RecipeDetailViewController to pass the recipe name. Obviously, you can add other properties in the detail view controller to pass other recipe-related values. ( In your case it will be data you want to pass to contactviewcontroller)
When a segue is triggered, before the visual transition occurs, the storyboard runtime invokes prepareForSegue:sender: method of the current view controller. By implementing this method, we can pass any needed data to the view controller that is about to be displayed. Here, we’ll pass the selected recipe object to the detail view controller.

How to transition from UITableViewCell to another view controller

I am trying to go from a UITableView with prototype cells to a detailviewcontroller of the item I selected on.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"historyToDetail"])
{
BYFHistoryDetailViewController *controller = (BYFHistoryDetailViewController *)segue.destinationViewController;
controller.workOut = [[BYFWorkOut alloc] init];
controller.workOut=_selectRow;
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BYFHistoryTableViewController *detailViewController =[[BYFHistoryTableViewController alloc] init];
NSArray *items = [[BYFworkOutStore sharedStore] allItems];
BYFWorkOut *selectedItem = items[indexPath.row];
_selectRow = selectedItem;
}
What is not happening is the transition from the table to detail I have a push segue from the prototype cell to the details.
What am I missing?
You are doing quite a lot wrong here. When using segue's you don't create an instance of the class. You simply call:
[self performSegueWithIdentifier:#"MySegue" sender:self];
This will use the segue you have defined in the storyboard. Where MySegue is the segue ID you created.
When you want to pass in data you use the callback
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
BYFHistoryDetailViewController *vc = (BYFHistoryDetailViewController *)[segue destinationViewController];
vc.workOut = selectedItem;
}
But using this callback will mean you will need to store selectedItem somewhere after you click the row so you can access it here.
EDIT
Your code seems a bit odd here also.
You set workout to a new object.
detailViewController.workOut = [[BYFWorkOut alloc]init];
Create another object from data.
NSArray *items = [[BYFworkOutStore sharedStore] allItems];
BYFWorkOut *selectedItem = items[indexPath.row];
And then assign the new object, overwriting the previous one.
//give detail view controller a pointer to the item object in row
detailViewController.workOut = selectedItem;
There is no need to have the first line of code at all
EDIT 2
If you only going to be using the one selected item at a time. you can do this in your UITableViewController class.
#implementation MyTableViewControllerClass
{
BYFWorkOut *_selectedItem;
}
inside didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *items = [[BYFworkOutStore sharedStore] allItems];
_selectedItem = items[indexPath.row];
}
EDIT 3
I've modified the code you posted here. You didn't add the first line of code i posted. Please look at this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"historyToDetail"])
{
BYFHistoryDetailViewController *controller = (BYFHistoryDetailViewController *)segue.destinationViewController;
controller.workOut = _selectRow;
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *items = [[BYFworkOutStore sharedStore] allItems];
_selectRow = items[indexPath.row];
[self performSegueWithIdentifier:#"historyToDetail" sender:self];
}
You need to name your segue and call the method:
[self performSegueWithIdentifier:#"MySegue" sender:self];

setDetailItem:(id)newDetailItem not firing

I am updating my iPad app and I've got a list of options in the table of the split view controller, but it's not firing the setDetalItem is not firing. This will not be ported to the iPhone because of the form-factor (screen is too small).
From the appDelegate class:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
splitViewController.delegate = (id)navigationController.topViewController;
UINavigationController *masterNavigationController = splitViewController.viewControllers[0];
JSLMasterViewController *controller = (JSLMasterViewController *)masterNavigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
from the masterViewController:
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
JSLDetailViewController *detailView = self.detailViewController;
detailView.telegram = indexPath.row;
NSLog(#"Did Fire 1");
}
And from my detailViewController:
- (void)setDetailItem:(id)newDetailItem
{
NSLog(#"Did Fire 2");
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
//self.detailDescriptionLabel.text = [[self.detailItem valueForKey:#"timeStamp"] description];
NSArray *mainQuestion = [self mainQuestionArray];
NSArray *subQuestion = [self subQuestionArray];
questionTitle.text = mainQuestion[telegram];
subQuestionOne.text = subQuestion[telegram][0];
subQuestionTwo.text = subQuestion[telegram][1];
}
}
I understand that I may need to create an instance of the detailViewController in the appDelegate, but I am unsure as to how to do this. Most of the tutorials I have found build a split view from scratch or seem to be using an older version of the mechanism. Any tips you can give me would be greatly appreciated!
You need to set detailView.detailItem in order for the - (void)setDetailItem:(id)newDetailItem to fire.
In the MasterViewController.m detailViewController is usually something like:
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
and then in the didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSYourCoolObject *object = _YourObjectArray[indexPath.row];
self.detailViewController.detailItem = object;
}
Turns out that, in iOS6, one needs to call, "setDetailItem" directly. You can pass objects here, although it's not necessarily what you would think. I added the following code to didSelectItemAtIndexPath:
[detailView setDetailItem:indexPath];
This fired the update to the MasterViewController and life is good.

Resources