Delegation lost when back to ViewController - ios

In my program have two view controller.
first one has table view.
when i click one cell, relevant inflammations show in second view controller.
it work well.
when i go back to first view controller.click again cell now it not working.
delegation not working that time.
i navigate like this
-(void)gotoviewUnfinishedMinute
{
NSArray *vc=[self.navigationController viewControllers];
ViewControllerView *vcView=nil;
for (int i=0; i<[vc count]; i++)
{
UIViewController *tempVC=[vc objectAtIndex:i];
if([tempVC isKindOfClass:[ViewControllerView class]])
{
vcView=[vc objectAtIndex:i];
break;
}
}
if(vcView)
{
[vcView setMeetingMinute:[unfinishedMinutes objectAtIndex:selectedRow]];
[self.navigationController popToViewController:vcView animated:NO];
vcView = nil;
}
else
{
ViewControllerView *vc3New = [self.storyboard instantiateViewControllerWithIdentifier:#"vcview"];
[vc3New setMeetingMinute:[unfinishedMinutes objectAtIndex:selectedRow]];
[self.navigationController pushViewController:vc3New animated:NO];
vc3New = nil;
}
vc = nil;
}
table view delegation like this
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableViewLastMinutes.dataSource = self;
self.tableViewLastMinutes.delegate = self;
}
how can i solve this problem?

Assign delegates in -viewWillAppear.
ViewDidLoad calls only when the view is loaded.when popped it is not called
viewDidLoad is called exactly once, when the view controller is first loaded into memory. This is where you want to instantiate any instance variables and build any views that live for the entire lifecycle of this view controller.
viewWillAppear is called when the view is made visible, and can be called multiple times during the lifecycle of a View Controller
See the docs

Firstly you can check this method by placing breakpoint that they call this method or not if call for all other cells you clicked then check your indexpath where you clicked either they have value or not by placing NSLog.
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

Related

UICollectionView loading and UINavigationController reset of view controllers

I have a UIViewController (which is my apps root view controller) that contains a UINavigationController that I reload using
- (void)presentSelectedViewController
{
[[self navController] popToRootViewControllerAnimated:NO];
[[self navController] setViewControllers:#[[self selectedViewController]] animated:NO];
}
self.selectedViewController is set through this:
- (void)setSelectedViewController:(UIViewController *)selectedViewController
{
if (_selectedViewController != selectedViewController)
{
if ([selectedViewController isKindOfClass:[SNPStandInViewController class]])
{
Class newClass = [(SNPStandInViewController *)selectedViewController actualClass];
if ([newClass class] == [SVWebViewController class])
selectedViewController = [[[(SNPStandInViewController *)selectedViewController actualClass] alloc] initWithAddress:[PREFERENCES urlForDefaultSearchProvider]];
else
selectedViewController = [[[(SNPStandInViewController *)selectedViewController actualClass] alloc] init];
if ([selectedViewController isKindOfClass:[SNPSettingsViewController class]])
[(SNPSettingsViewController *)selectedViewController setDelegate:[self rootController]];
}
Class oldClass = [self.selectedViewController class];
NSInteger oldControllerIndex = [self.viewControllers indexOfObject:self.selectedViewController];
[self.selectedViewController willMoveToParentViewController:nil];
[self.selectedViewController removeFromParentViewController];
[(SNPStandardViewController *) self.selectedViewController releaseResources];
[self willChangeValueForKey:#"selectedViewController"];
_selectedViewController = selectedViewController;
[self didChangeValueForKey:#"selectedViewController"];
[self.viewControllers replaceObjectAtIndex:_selectedIndex withObject:selectedViewController];
if (nil != oldClass && oldControllerIndex != NSNotFound)
{
[self.viewControllers replaceObjectAtIndex:oldControllerIndex withObject:[[SNPStandInViewController alloc] initWithClass:oldClass]];
}
[[self indexTableView] reloadData];
}
[self presentSelectedViewController];
}
(The standin view controller class is an NSObject subclass that basically holds the class of the view controller that should be there and creates it if selected -- though it is visually not a tab interface, think a tab interface where I don't want to have the actual view controllers that are not selected be created and in memory and running)
I have one view controller that has a UICollectionView in it and this is the default view controller that is set using the above code when the app first runs. It runs fine and the UICollectionView loads its data before the -(void)viewWillAppear: of that view controller runs (a -(void)loadView implementation creates the UICollectionView and does a [uiCollectionViewInstance reloadData]).
If I select another view controller above, and then reselect the initial one (which is a new instance -- old instances when moved off of are destroyed), the UICollectionView does not load its data (even though the loadView routine creates it and calls reloadData) until after both viewWillAppear: and viewDidAppear actually run. This is bad because I call a selection routine in viewWillAppear: to set a highlight in the collection view on the item that is the default selection [think a button bar type interface].
The same code path seems to run each time I create this view controller that contains the collection view (with extensive NSLog outputting to show the path). So I assume that maybe something is happening in the actual routine that creates the new view controller and sets it as the active one in the UINavigationController
I am at a loss to know what to explore to see why this collection view has no visible cells after being created and reload data being called on it when it is created after being selected in my pseudo tab controller described above (but it works fine when set initially upon creation of the pseudo tab controller).
I don't know what else people want to see but I'd be happy to try and post more info, code, etc as necessary.
in the -presentSelectedViewController I added this after doing the setViewControllers and now it all works fine.
[[[self selectedViewController] view] setNeedsLayout];
[[[self selectedViewController] view] layoutIfNeeded];

DetailViewController Not Updating For Animation

I have a UISplitview controller (with a master and detail view). So, when the detailview loads the viewDidLoad calls a function named [self animateToPosition]; with the following code:
-(void*)animateToPosition
{
NSLog(#"Called Function");
[worldV animateToPosition:MaplyCoordinateMakeWithDegrees(-122.4192, 37.7793) time:1.0];
[self.view setNeedsDisplay];
return 0;
}
Now, when this is first run, my globeViewC correctly animates to the position passed in (worldV is initialized and created an all in viewDidLoad of detailviewController also "Called Function" is printed in the log.
However, I have a view controller and in the didSelectRowAtIndexPath I have the following code (in the file masterViewController.m)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[testArray objectAtIndex:indexPath.row]isEqualToString:#"Menu1"]) {
DetailViewController *test=[[DetailViewController alloc]init];
[self addChildViewController:test];
[self.view addSubview:test.view];
[test didMoveToParentViewController:self];
[test animateToPosition];
}
}
When I select the cell called menu1, "Called function" DOES display in the NSLog, but the animation that occurred when the view was first loaded doesn't anymore. I'm wondering if I must somehow reload the detailviewcontroller or initialize it again (but I tried initializing it again and that didn't work)
Would like if someone could see this and help me get this working.
It would be helpful if you could show more, especially how you alloc and init your worldV and what you have in your viewDidLoad.
Normally you don't create a new DetailViewController for SplitView setup.
Instead of creating a new DetailViewController, try to grab a hold of the existing detail view controller by creating a property:
#property(strong, nonatomic) DetailViewController *detailViewController;
and:
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
First thing to test here is whether your worldV is nil. A simple NSLog in animateToPosition would reveal the answer.
And whenever you need to call that method, do:
[self.detailViewController animateToPosition];
To animate from one coordinate to another with time, you may need to change your animateToPosition method to:
-(void)animateToPosition:(MaplyCoordinate)coordinates time:(CGFloat)time
Consult whether or not your MaplyCoordinate is an object, which I doubt.
So, to sum up, in your tableview's viewDidLoad, get a hold of the detail view controller.
When didSelectRow gets called, use the new method suggested and pass the coordinate and time this way:
[self.detailViewController animateToPosition:coordinates time:1.0];
Hope this helps.
In didSelectRowAtIndexPath function you create an DetailViewController but you don't add it to the view hierarchy. You should add it to the parent view controller like this
[self addChildViewController:viewController];
[self.view addSubview:viewController.view];
[viewController didMoveToParentViewController:self];
or just add it to navigation or present it as a modalViewController

How do I manually set the "Back" destination in iOS apps

I have a UIViewController called 'detailViewController'.
This view controller is accessed through multiple different segues using the push segue.
The problem I am facing is that the back button on the detailViewController takes the user back to the previous view controller (as it should), however I would like the back button to take the user to the masterViewController (the default UIViewController in the app).
How do I do this?
I have tried changing the segue types however that didn't really do anything at all.
Peter
The method you're looking for is UINavigationController's popToRootViewControllerAnimated:
From the documentation: "Pops all the view controllers on the stack except the root view controller and updates the display."
You'll need to create a custom back button. You can't afaik override the back button's functionality.
So something like:
UIButton *myBackButton = [UIButton buttonWithType:UIButtonTypeCustom];
[myBackButton addTarget:self action:#selector(popToRoot:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *myCustomBackButtonItem = [[UIBarButtonItem alloc] initWithCustomView:myBackButton];
[self.navigationItem setLeftBarButtonItem:myCustomBackButtonItem];
and then the implementation of popToRoot: would look like:
- (void)popToRoot:(id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
If the masterViewController you're talking about is the root you can call:
[self.navigationController popToRootViewControllerAnimated:YES];
You can create the back button yourself and call [self.navigationController popToRootViewControllerAnimated:YES]. However, that does require you to create the back button yourself. An alternative option could be to take the current view controller, and remove all of them except the first and current ones:
NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableCopy];
[viewControllers removeObjectsInRange:NSRangeMake(1, [viewControllers count] - 2)];
self.navigationController.viewControllers = viewControllers;
Use the following code in order to go back to main view controller:
[self.navigationController popViewControllerAnimated:YES];
Edit:
Based on the comments, I realize that my code takes you only one step back and may not answer what is asked in this question. Thanks.
I came up with a workaround that looks up in a navigation controller's collection and find the offset between the existing and destination controller using name of destination controller and remove the in-between controller. Not sure if it is close to your need but give it a try:
- (NSArray *)navigateToViewController:(NSString *)destinationControllerName withControllers:(NSArray *)sourceControllers
{
NSMutableArray *controllers = [[NSMutableArray alloc] initWithArray:sourceControllers];
NSInteger sourceControllerIndex = [controllers count] - 1; // Value should be index oriented instead of position oriented.
NSInteger destControllerIndex = 0;
// Find position of destination controller (index oriented)
for (UIViewController *controller in controllers)
{
NSString *controllerName = NSStringFromClass([controller class]);
NSLog(#"class name: %#", controllerName);
if([[controllerName lowercaseString] isEqualToString:[destinationControllerName lowercaseString]])
break;
destControllerIndex +=1;
}
// If desired controller does not exists in the stack, do not proceed.
if (destControllerIndex == sourceControllerIndex)
{
return controllers;
}
// If destination is the same as source do not enter in this block
// If destination and source controllers have zero or no controllers in between do not enter in this block
// If destination and source controllers has few controllers (at least one) in between, go inside this block.
// Here "destControllerIndex + 1" shows, there is at least one controller in between source and destination.
else if(destControllerIndex + 1 < sourceControllerIndex)
{
NSLog(#"controllers in stack: %#", controllers);
// Start from the controller following the source controller in stack and remove it
// till the destination controller arrives
for (NSInteger iterator = sourceControllerIndex - 1; iterator > destControllerIndex; iterator--)
{
UIViewController *cont = [controllers objectAtIndex:iterator];
if(cont) {
[cont release]; cont = nil; }
[controllers removeObjectAtIndex:iterator];
NSLog(#"controllers in stack: %#", controllers);
}
}
return controllers;
}
and define it in some base controller:
-(void) popToViewController:(NSString *)controllerName withNavController:(UINavigationController *)navController
{
// STStatistics refers a singleton class of common functions.
NSArray *mArr = [STStatistics navigateToViewController:controllerName withControllers:navController.viewControllers];
navController.viewControllers = mArr;
// There should be more than one controller in stack to pop.
if([mArr count] > 1)
{
[navController popViewControllerAnimated:YES];
}
}
and here is how called:
[self popToViewController:#"NameOfDestinationControllerInNavStack" withControllers:self.navigationController];

Passing Array from RightChildViewController to MainVIewController

I am having problem working with a SlidingViewController. My sliding view controller has a left view controller, a main view controller and a right view controller. My left view controller is a menu style view controller and switches the main view controller to a view controller selected. The right view controller is a table view controller that has recent searches using NSUserDefault keys. This key is an array that contains 4 strings. The problem I am having is sending this string back to the main view controller because the main view controller's viewWillAppear does not get called because technically it is never off the screen (ie it never disappears).
I've tried to make the view controller call the viewDidAppear manually but it seems as initializing the main view controller creates a whole new viewController all together and doesn't create the tableView inside the main view controller, therefore doesn't load reload a table view. Also, the tableView comes out as (null) when I log it.
Here is the didSelectRowAtIndexPath of LeftViewController
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UIStoryboard *iPhoneStoryBoard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
ViewController *viewController = (ViewController *)[iPhoneStoryBoard instantiateViewControllerWithIdentifier:#"HomePage"];
viewController.reloadArray = self.recentSearchesArray[indexPath.row];
NSLog(#"Recent ReloadArray: %#", viewController.reloadArray); //This prints out the correct information
/*
MenuViewController *menuViewController = [[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:nil];
SlidingViewController *slidingViewController = [[SlidingViewController alloc] initWithNibName:#"SlidingViewController" bundle:[NSBundle mainBundle] mainViewController:viewController leftViewController:menuViewController andRightViewController:self];*/ //Tried doing this too, doesn't work
[viewController viewWillAppear:YES];
[self.tableView deselectRowAtIndexPath:indexPath animated:YES];
[self performSelector#selector(toggleView)];
}
viewWillAppear's of ViewController
-(void)viewWillAppear:(BOOL)animated
{
if(self.reloadArray.count !=0)
{
NSLog(#"Reload Array Not Empty!");
NSLog(#"ReloadArray: %#",self.reloadArray); // Logs out the correct information
[self.homePageTableView reloadData];
NSLog(#"Table: %#", self.homePageTableView); // Logs out as (null) :(
}
else
{
NSLog(#"Reload Array Is Empty");
}
}
Anyone have any suggestions/ideas or has anyone worked with something like this or come across this problem? If so, any information and guidance would be greatly appreciated. Thanks in advance!
You can use Notification center method. In your main view controller's viewdidload method write following code..
[[NSNotificationCenter defaultCenter] addObserver: self
selector: #selector(anymethod:)
name: anyname
object: nil];
- (void)anymethod:(NSNotification *)notification {
NSLog(#"%#", notification.userInfo);
}
and in your right view controller pass data like,
[[NSNotificationCenter defaultCenter] postNotificationName:#"anyname" object:self userInfo:anydata];

Pushing self.view to navigation controller by allocing, but when coming back same data is shown

I am pushing self view to self.navigationcontroller by allocating. I have a tableView on that view so I am changing the content of tableview. But when I am pressing back button (that is automatically created), I am not able to show previous content. Its showing updated content.
Please suggest.
You set code in viewWillAppear method
- (void)viewWillAppear:(BOOL)animated
{
//code set here
}
If you fill the tableView's data in viewWillAppear: or viewDidAppear:, it will reload even if you only press the back button of your top viewController. If you do not want to have your content changed, you are supposed to use initWithNibName: or viewDidLoad: methoads. They are called only at creation time of the view.
Based on the comments on #Kirti's post, You can check if your viewcontroller is being popped by following method, and take some necessary actions for you controller holding table.
-(void) viewWillDisappear:(BOOL)animated
{
if(![self.navigationController.viewControllers containsObject:self])
{
YourControllerWithTable *instance = [self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count - 1];
instance.loadOldContent = YES;
}
}
In viewWillAppear: of YourControllerWithTable, you can check:
-(void) viewWillAppear:(BOOL)animated
{
if(loadOldContent)
{
//Do your work here
}
}
You don't push UIView instances onto a UINavigationController instance, only instances of UIViewController.

Resources