Tuesday, September 7, 2010

Split view Controller, Calling Detail view controller from Navigation view controller.

You might find lots of Blogs and Books to use Split view controller in a normal way with one root view controller and a detail view controller like a really nice tutorial can be seen here. You might also find a tutorial that will tell you how to call different detail view controllers from root view controller here.

But when it comes to call detail view controller from a controller other then Root view controller help just diminish. As we can use navigation controller in root view controller that will navigate to a controller which is not defined in app delegate for split view controller then comes the real deal of calling it from last controller in navigation.

The solution that i proposed here is to use NSnotifications to broad cast a message with proper name and then use that message in detail view controller to call a function in detail view controller and for the detail item that is to be passed use the Object: parameter on NSnotification to send an object to it which can be utilized in detailview controller.

Lets check some code snippits for better elaboration.

Here is a root view controller didSelectRowatindexPath function from which mostly detail view controller is called but we need some navigation so i am calling a TestViewController by using navigation of root view controller.

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 int index = [indexPath row];
 
 Category *category = [categories objectAtIndex:index];
 
 
 TestViewController *shopList = [[TestViewController alloc] initWithNibName:@"TestViewController " bundle:[NSBundle mainBundle]];
 shopList.categoryId = category.categoryId;
 [[self navigationController]  pushViewController:shopList animated:YES];
 [shopList release];

}


Now to Reach to a test view controller from which a detail view controller needs to be called in the didSelectRowatindexPath function of this viewcontroller we will be broadcasting an NSTotification

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 int index = [indexPath row];
 
 [[NSNotificationCenter defaultCenter] postNotificationName:@"dealNotification" object:[article;

}

That all for a new controller in navigation controller. now we move to detail view controller where in ViewdidLoad an observer is added and the function that needs to be called is passed to selector.

- (void)viewDidLoad {

 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(iamcallingyou:) name:@"dealNotification" object: nil];
    [super viewDidLoad];
}

Now finally the function whose name is given in selector.

- (void) iamcallingyou:(NSNotification *)pNotification
{
 
 NSLog(@"hi");
// This is a Class Object that i have passed in to object parameter when broadcasting notifications.
 article = (Article *)[pNotification object];
  
 if (popoverController != nil) {
        [popoverController dismissPopoverAnimated:YES];
    } 
 

}


And we are done with it... do some memory management in final touches and we are good to go

Happy Coding.

11 comments:

stefano said...

Hi Usman,I'm trying to create an iPad application with a similar user interface to Apple's Mail application, i.e:

* RootView controller (table view) on the left hand side of the split view for navigation with a multiple view hierarchy. When a table cell is selected a new table view is pushed on the left hand side
* The new view on the left side can update the detail view.

When I select a row in the table,detail view won't be refreshed.
So I have a few questions to ask you about your solution(please be patient,I'm still a noob).
1) Why do you declare shoplist as a new controller (TestViewController) instead of just declare it a RootController?
2)I think you use NSNotification's trick to pass to detailViewController an object but how can I use this trick to solve my problem?

I post you a link to my source code:http://rapidshare.com/files/424550262/source-code.rar

Please help me,I'm really stuck on this.

Usman Shabbir said...

Hi stefano,

The Detail view wont be refreshed because we have left the root view controller and have navigated to a new table view controller which has nothing to do with Detail view controller so data on detail view controller wont get refreshed.

In the Example i have mentioned "TestViewController" which is the name of current tableview controller to which i have navigated from my Root view controller.

And then calling detail view controller from that testViewController by using NSNotification.

I have seen your code where you have not navigated to a new table view controller rather chnaged the table data with .plist file, and you want different detail view controllers to be called if i am not wrong. so i guess this link might help you

Click

stefano said...

Thanks for your response.

I downloaded the source code from the link you provide me,but in that example there's only a single table,what I'm trying to do is to push a new table when you select a row.


So I declared a RootController as a subclass of UITableViewController.
Inside the file data.plist there's a buch of elements.Each element has a field named "Children" which tells you how many children each item has.

So in RootController.m didselectRowAtIndexPath looks like:

- (void)tableView:(UITableView *)TableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

if([Children count] ==0{
// declare a new ViewController for every row of the table
//(I pasted the code from the tutorial you suggested me
}
else //if the element has at least a child
{
// declare a new rootController and push it onto the stack of navigation controller.I don't wanna declare a different new controller for every child an element has,so I use again a rootController type.


//I suppose I have to do something here to connect the new rootController to the detail view,but how??
}

Thanks for your time

Usman Shabbir said...

I am just confused here that you need to change content of one Detail view controller or you need to show different Deatil view controllers depending on the row selected by root view controller because your code have three detail view controller.

If you have just a single Detail view controller and only its content needs to be changed by Root view controler (with multiple table view) then just push a notification

by calling " [[NSNotificationCenter defaultCenter] postNotificationName:@"dealNotification" object:[article; "

and in the load of root view controller write this
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(iamcallingyou:) name:@"dealNotification" object: nil];


so when ever the row is selected tour detail view controler function will be Hitted by a breakpoint and there you can change the content.

Hope it clears the things ?

stefano said...

It works!Usman you're the man,I owe you one!Finally I understand as NSNotification works,that's very useful,I think I'll use it again in my code

Usman Shabbir said...

Thanks Stefano :) will always be there to help and seek good knowledge

Nitesh Meshram said...

Hi Usman Sir can you explain more on this...

[[NSNotificationCenter defaultCenter] postNotificationName:@"dealNotification" object:[article; "

I am unable to understand the code..

where we have to define the (Article ) class ??
if it is possible put some sample project.

Please help me out sir.

shannoga said...

Hi

you saved my day. tried many complex ways.
yours is simple clean and works great.

thanks

shani

Usman Shabbir said...

Any time, let me know if any other help is required :)

Nitesh Meshram said...

Hello Can you post the sample code for this problem. Thank you.

jess said...

Hi Usman Shabbir,

First of all Thanks for the help can you please explain in detail how to call detailviewcontroller from other controller ,Its hard to understand here or else please post the sample code it gives better understanding

Thanks,
Jess