In iOS UINavigationController, in each of screen transition rapidly consuming memory - ios

I am developing iOS App.
In NavigationController, MainViewController has custom ContainerViewController(*YSLContainerViewController) which is composed of several UIViewController like the following code.
*YSLContainerViewController:https://github.com/y-hryk/YSLContainerViewController
MainViewController.m
#property (nonatomic) YSLContainerViewController *containerVC;
-(void)viewDidLoad
{
[super viewDidLoad];
CategoryViewController *categoryViewController[5];
categoryViewController[0] = [self.storyboard instantiateViewControllerWithIdentifier:#"EachCategoryView"];
categoryViewController[0].category = 0;
categoryViewController[0].title = #"apple";
categoryViewController[1] = [self.storyboard instantiateViewControllerWithIdentifier:#"EachCategoryView"];
categoryViewController[1].category = 1;
categoryViewController[1].title = #"orange";
categoryViewController[2] = [self.storyboard instantiateViewControllerWithIdentifier:#"EachCategoryView"];
categoryViewController[2].category = 2;
categoryViewController[2].title = #"strawberry";
categoryViewController[3] = [self.storyboard instantiateViewControllerWithIdentifier:#"EachCategoryView"];
categoryViewController[3].category = 3;
categoryViewController[3].title = #"cherry";
categoryViewController[4] = [self.storyboard instantiateViewControllerWithIdentifier:#"EachCategoryView"];
categoryViewController[4].category = 4;
categoryViewController[4].title = #"watermelon";
NSMutableArray *tabArray =
[NSMutableArray arrayWithObjects:categoryViewController[0], categoryViewController[1], categoryViewController[2], categoryViewController[3], categoryViewController[4], nil];
float navigationBarHeight = self.navigationController.navigationBar.frame.size.height;
_containerVC = [[YSLContainerViewController alloc]initWithControllers:tabArray
topBarHeight:navigationbarHeight
parentViewController:self];
_containerVC.delegate = self;
[self.view addSubview:_containerVC.view];
}
Each categoryViewController has TableView. When a cell in TableView is tapped, goes to detailViewController.
CategoryViewController.m
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
DetailViewController *vc = [storyBoard instantiateViewControllerWithIdentifier:#"DetailView"];
[self.navigationController pushViewController:vc animated:YES];
}
Each time I repeat the above transition like
"(tap tableViewCell in) categoryViewController in MainViewController → detailViewController → (go back to) MainViewController → (tap tableViewCell in) categoryViewController in MainViewController → detailViewController → (go back to) MainViewController..."
,my app are rapidly consuming the memory , it will not be reduced.
I guess in each of transition categoryViewControllers are not released from memory.
I tried the following method, but it does not work well.
DetailViewController.m
- (void)viewDidDisappear:(BOOL)animated
{
[self.navigationController popViewControllerAnimated:YES];
([self.navigationController popToRootViewControllerAnimated:YES];)
}
Could you tell me how to solve this problem?

Related

Why does data give me null?

I'm trying to pass a NSDictionaryfrom a TableViewControllerto a ViewController. In my TableViewController.m. I have this code to navigate to the ViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *objectDict = [dataArray objectAtIndex:indexPath.row];
NSLog(#"Info: %#", objectDict);
// Pass object to new page
//UIViewController * vc = [[UIViewController alloc] init];
//[self presentViewController:vc animated:YES completion:nil];
SeeInfoVC *controller = [[SeeInfoVC alloc] init];
controller.data = objectDict;
NSString * storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"SeeInfoVC"];
[self presentViewController:vc animated:YES completion:nil];
In my ViewController.h I have:
#interface SeeCardVC : UIViewController
{
NSDictionary *data;
}
#property (nonatomic, retain)NSDictionary *data;
#end
And then I'm trying to log data in ViewController.m:
#implementation SeeCardVC
#synthesize data;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"Info: %#", data);
}
But it only gives me null :(
What am I doing wrong?
Let's see what your code is doing here:
// Create new controller, assign objectDict to data property
SeeInfoVC *controller = [[SeeInfoVC alloc] init];
controller.data = objectDict;
//Get Storyboard name
NSString * storyboardName = #"Main";
//Get Storyboard (BTW, you can do this with self.storyboard)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
//Instantiate NEW controller
UIViewController * vc = [storyboard instantiateViewControllerWithIdentifier:#"SeeInfoVC"];
//Present NEW controller
[self presentViewController:vc animated:YES completion:nil];
You created a controller and assigned data to it, and then didn't use it anymore, instead you created a new one from the storyboard, you didn't add the data and presented it.
Basically, you created two, set data to one and presented the other one.
See the problem?

iOS - pass int between view controllers

I have an int pageNumber setup like so #property (nonatomic, assign) int pageNumber; which I am trying to pass between two view controllers.
It works the first time I tap a cell in the tableview, however if I tap a cell again the int does not get updated.
Any ideas? My code is below.
LeftMenuViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone"
bundle: nil];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
SoftwareCheckViewController *sc = [[SoftwareCheckViewController alloc] init];
if ([cell.textLabel.text isEqual: #"S:1 R:0"]) {
sc = [mainStoryboard instantiateViewControllerWithIdentifier: #"SoftwareCheckViewController"];
sc.pageNumber = 1;
}
else if ([cell.textLabel.text isEqual: #"S:1 R:1"]) {
sc = [mainStoryboard instantiateViewControllerWithIdentifier: #"SoftwareCheckViewController"];
sc.pageNumber = 2;
}
else if ([cell.textLabel.text isEqual: #"S:1 R:2"]) {
sc = [mainStoryboard instantiateViewControllerWithIdentifier: #"SoftwareCheckViewController"];
sc.pageNumber = 3;
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"pageNumberNotification" object:self];
}
SoftwareCheckViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pageNumberMethod) name:#"pageNumberNotification" object:nil];
}
- (void)pageNumberMethod{
NSLog(#"pageNumber: %i", pageNumber);
}
You are creating new view controllers every time you tap a cell but you aren't doing anything with them. Setting sc.pageNumber is never going to have an effect if sc isn't the controller that's listening for a notification.
Also, even if you wanted a new controller, [[SoftwareCheckViewController alloc] init] is basically a waste because you then assign something different to sc right after.

Pushing new UIViewController from custom UIPopOver issue

Hello I'm using this library to show my PopOver which contain tableView with searchBar.
The problem is that one user try to select row from the tableView instead dismissing the popOver and displaying the slected row in hole screen I got this :
.
I've tried to use [self.parentViewController.navigationController ...] to push my view but didn't worked.
This is my popOver code (in MainVC.h):
-(IBAction)showPopoverSearch:(id)sender{
UIBarButtonItem *btn = (UIBarButtonItem *) sender;
NSInteger width = 600;
NSInteger height = 400;
SearchViewController *searchVC = [self.storyboard instantiateViewControllerWithIdentifier:#"searchView"];
searchVC.modalInPopover = NO;
UINavigationController* contentViewController = [[UINavigationController alloc] initWithRootViewController:searchVC];
popoverController = [[WYPopoverController alloc] initWithContentViewController:contentViewController];
popoverController.delegate = self;
//popoverController.passthroughViews = #[btn];
popoverController.popoverContentSize = CGSizeMake(width, height);
popoverController.popoverLayoutMargins = UIEdgeInsetsMake(10, 10, 10, 10);
popoverController.wantsDefaultContentAppearance = YES;
[popoverController presentPopoverFromBarButtonItem:btn permittedArrowDirections:WYPopoverArrowDirectionAny animated:YES];
}
And this is the didSelctRow method (SearchViewController.m) :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main"bundle:nil];
PostReaderViewController *postReaderView =
(PostReaderViewController *)
[storyboard instantiateViewControllerWithIdentifier:#"postReader"];
postReaderView.thePost = [_postsArray objectAtIndex:indexPath.row];
// if ([self.parentViewController.po .popoverController isPopoverVisible])
// [popoverController dismissPopoverAnimated:YES];
[self.navigationController pushViewController:postReaderView animated:YES];
}
To solve this issue I've passed the Navigation controller and popoverController from The parent View MainVC.h to child controller SearchViewController.h and then use those vars to dismiss my PopOvercontroller and push the new VC. Code snippet :
SearchView
#interface SearchViewController : UIViewController
#property (strong, nonatomic) WYPopoverController *parentPopoverVC;
#property (strong, nonatomic) UINavigationController *parentNavigationController;
#end
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
...
[self.parentPopoverVC dismissPopoverAnimated:YES];
[self.parentNavigationController pushViewController:postReaderView animated:YES];
}
MainVC.h
-(IBAction)showPopoverSearch:(id)sender{
SearchViewController *searchVC = [self.storyboard instantiateViewControllerWithIdentifier:#"searchView"];
[searchVC setParentPopoverVC:popoverController];
[searchVC setParentNavigationController:self.navigationController];
[popoverController presentPopoverFromBarButtonItem:btn permittedArrowDirections:WYPopoverArrowDirectionAny animated:YES];
}

How to pass data using didSelectRow in UISplitViewController - from master to detail

I want to pass some core data from master to detail.
First the user selects a name which has a gender assigned. If gender Girl "pige" it goes to the girls UITableiew. From there each selection shows on detail view.
I want to pass some data from the girl UITableiew. Like if its a girl color it pink. set a title etc.
So far i know how to pass around the UITableiew "master" but not how to get it to the detail view
Here's some code on how i manage the selection of UITableView etc.
DetailViewContainerController
UIStoryboard* initial = [UIStoryboard storyboardWithName:#"Main-iPad" bundle:nil];
self.initital = [initial instantiateViewControllerWithIdentifier:#"initialSite"];
[self addChildViewController:self.initital];
self.startSide = [initial instantiateViewControllerWithIdentifier:#"startSide"];
[self addChildViewController:self.startSide];
-(void)initialSite:(int)viewId
{
UIViewController *viewController;
switch (viewId)
{
case 0:
viewController = self.initital;
[self.navigationController setNavigationBarHidden:NO animated:NO];
break;
case 1:
viewController = self.startSide;
[self.navigationController setNavigationBarHidden:NO animated:NO];
break;
}
[self showChildViewController:viewController];
}
-(void)showChildViewController:(UIViewController*)content
{
if(topController != content)
{
content.view.frame = [self.view frame]; // 2
[self.view addSubview:content.view];
[content didMoveToParentViewController:self];
topController = content;
}
}
startTableViewController
-(void)viewDidLoad
{
arrayA = [[[NSMutableArray alloc] initWithArray:[Start findAllSortedBy:#"navn" ascending:YES]] mutableCopy];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[[self.fetchedResultsController objectAtIndexPath:indexPath] valueForKey:#"gender"]isEqualToString:#"Pige"])
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main-iPad" bundle:nil];
DetailViewContainerController *controller = [storyboard instantiateViewControllerWithIdentifier:#"MenuPige"];
controller.forNavn = [arrayA objectAtIndex:indexPath.row];
[self.navigationController pushViewController:controller animated:YES];
}
if ([[[self.fetchedResultsController objectAtIndexPath:indexPath] valueForKey:#"gender"]isEqualToString:#"Dreng"])
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main-iPad" bundle:nil];
DetailViewContainerController *controller = [storyboard instantiateViewControllerWithIdentifier:#"MenuDreng"];
controller.forNavn = [arrayA objectAtIndex:indexPath.row];
[self.navigationController pushViewController:controller animated:YES];
}
}
MenuPige
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.detailViewContainerController initialSite:[indexPath row]];
if ([[[self.fetchedResultsController objectAtIndexPath:indexPath] valueForKey:#"menuPunkt"]isEqualToString:#"Barnedåb / Navngiving"]) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"BarneDaab" bundle:nil];
DetailViewContainerController *controller = [storyboard instantiateViewControllerWithIdentifier:#"barneDaab"];
[self.navigationController pushViewController:controller animated:YES];
}
in the girl menu.h i have the NSStrings of the data that i want to pass. So that is working. but how to get it to detailviewcontroller ?
UPDATE:
I tried this Accessing array from a detail view controller into master view controller in Objective-C
but can't get it work
UPDATE 2:
self.navigationController.parentViewController.navigationItem.title = [self.detailViewContainerController.forNavn valueForKey:#"navn"];
doesn't work in the velkommen.m, it returns nil
UPDATE 3:
Leftmenucontroller.m - this works. but only to another uitableview. can't get it over to the detail view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewContainerController *start = [[DetailViewContainerController alloc]init];
start.forNavn = forNavn;
NSLog(#"leftview = %#", forNavn);
[self.detailViewContainerController initialSite:[indexPath row]];
}
UPDATE 4:
startTableViewController.h
{
NSMutableArray *arrayA;
NSMutableArray *tableData;
NSString *forNavn;
NSString *mellemNavn;
NSString *efterNavn;
NSString *gender;
}
#property (nonatomic, retain) NSString *forNavn;
#property (nonatomic, retain) NSString *mellemNavn;
#property (nonatomic, retain) NSString *efterNavn;
#property (nonatomic, retain) NSString *gender;
#property (nonatomic, strong) NSMutableArray *arrayA;
UPDATE 6:
I figured out that i can pass the data to DetailviewContainerController with this
DetailViewContainerController *test = (DetailViewContainerController *) [[self.splitViewController.viewControllers lastObject] topViewController];
test.leftViewController = self;
test.forNavn = forNavn;
NSLog(#"test = %#",test.forNavn);
but now i can't get it further from DetailViewContainerController. i tried this :
VelkommenViewController *test2 = (VelkommenViewController *) [[self.splitViewController.viewControllers lastObject] topViewController];
test2.detailViewContainerController = self;
test2.forNavn = self.forNavn;
NSLog(#"test2 = %#",test.forNavn);
Update 7:
Update 8:
VelkommenViewController *test2 = [[[self.splitViewController.viewControllers.lastObject topViewController] childViewControllers] objectAtIndex:0];
test2.forNavn = forNavn;
NSLog(#"test3 = %#",test2.forNavn);
Throws a error : -[UINavigationController setForNavn:]: unrecognized selector sent to instance 0x175b56c0
Update 9:
It's a little unclear what you're doing, especially with the child view controller stuff. But, in general, when working with a split view controller, the detail controller can be accessed by using self.splitViewController.viewControllers[1] (if the detail controller is embedded in a navigation controller, then that gets you a reference to the navigation controller, and you have to use its topViewController property to get to the detail controller). You shouldn't be using instantiateViewControllerWithIdentifier:, or alloc init to access the detail controller, since either of those methods will give you a new instance instead of referencing the one you have on screen.
on the receiving end this works:
NSString *name = ((DetailViewContainerController *)self.parentViewController).forNavn;

navigationController = null in TableViewController's pushViewController method (popover)

First of all, sorry for my English.
I'm trying to do an app for iPad with a navigation controller which pushes view controllers when a button "Next" is selected. But I also want to have a popover, called from a button in the nav bar, that allows the user to "jump" from one view controller to another, pushing it with the tableView:didSelectRowAtIndexPath: and the pushViewController:animated: methods, but it's not working.
Summary:
Tab bar -> switches between FirstViewController and SecondViewController (works just fine)
Nav bar (button Next) -> switches between SecondViewController, FirstSlideController and SecondSlideController (it's also good)
Popover -> user selects SecondViewController, FirstSlideController or SecondSlideController (here's the problem!)
Codes:
AppDelegate
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UINavigationController *navigationController1 = [[UINavigationController alloc] initWithRootViewController:viewController1];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
UINavigationController *navigationController2 = [[UINavigationController alloc] initWithRootViewController:viewController2];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = #[navigationController1, navigationController2];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
TableViewController(popover)'s didSelectRowAtIndexPath method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row == 0){
FirstSlideController *detailViewController = [[FirstSlideController alloc] initWithNibName:#"FirstSlideController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
}
else if(indexPath.row == 1){
SecondSlideController *detailViewController = [[SecondSlideController alloc] initWithNibName:#"SecondSlideController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
}
else{
SecondViewController *detailViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
}
}
SecondViewController (with delegate suggested by maros)
-(void) showPopover:(id) sender
{
TableViewController *PopoverView = [[TableViewController alloc] initWithNibName:#"TableViewController" bundle:nil];
self.popOver = [[UIPopoverController alloc] initWithContentViewController:PopoverView];
self.popOver.delegate = self;
[self.popOver presentPopoverFromBarButtonItem:self.navigationItem.leftBarButtonItem permittedArrowDirections: UIPopoverArrowDirectionUp animated: YES];
}
I tried to print self.navigationController and it says it's null. I'd appreciate any help.
Thank you.
Presnented UIPopoverController is not pushed on the navigation stack in the view controller from which it was presented. It is a separate view controller.
Therefore the navigationController inside the popover is nil.
What I would recommend you is to create a delegate MyNavigationPopoverDelegate (the class that creates a popover (PopoverController). Pass it's instance as an delegate to the TableViewController.
After users clicks on some button inside popover, call delegate's method to processes button clicks (myNavigationPopover:(UIPopoverController*)popover clickedButtonAtIndex:(NSInteger)buttonIndex).
Then maybe dismiss delegate?
and finally change navigation however you want! :)
#protocol MyNavigationPopoverDelegate
- (void) myNavigationPopover:(UIPopoverController*)popover clickedButtonAtIndex:(NSInteger)buttonIndex;
#end
#interface TableViewController : UITableVieController // your viewController in popover
... // your code
#property (nonatomic, weak) NSObject <MyNavigationPopoverDelegate> * delegate;
... // your code
#end
#implementation TableViewController
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate myNavigationPopover:self clickedButtonAtIndex:indexPath.row];
}
...
#end
// defines that SecondViewController implements the delegate's method
#interface SecondViewController <MyNavigationPopoverDelegate> : UIViewController
// your code
#end
// code where you presenting popover
#implementation SecondViewController
// This is the method that is executed after your button press and it is responsible for presenting a popover
- (void) presentPopover{
...
myPopover.delegate = self; // setting the delegate
[myPopover presentPopoverFromXXX ...]; // however you present it
...
}
- (void) myNavigationPopover:(UIPopoverController*)popover clickedButtonAtIndex:(NSInteger)buttonIndex
{
UINavigationController *currentNavigationController = ; // get the navigation controller from the tab bar
if(buttonIndex == 0){
FirstSlideController *detailViewController = [[FirstSlideController alloc] initWithNibName:#"FirstSlideController" bundle:nil];
[currentNavigationController pushViewController:detailViewController animated:YES];
}
else if(buttonIndex == 1){
SecondSlideController *detailViewController = [[SecondSlideController alloc] initWithNibName:#"SecondSlideController" bundle:nil];
[currentNavigationController pushViewController:detailViewController animated:YES];
}
else{
SecondViewController *detailViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[currentNavigationController pushViewController:detailViewController animated:YES];
}
}
#end;

Resources