iOS - pass int between view controllers - uitableview

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.

Related

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

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?

Programatically create segue from xib file to viewcontroller in storyboard

I use a library which has a xib file in objective-c
I have my storyboard that has swift classes
I need to create segue from that xib file to my storyboard and pass some data.
Tried this with no luck
XIB File
#import "IncomingMessageCell.h"
#implementation IncomingMessageCell
- (void)awakeFromNib {
UIImage * balloonImage = [UIImage imageNamed:#"bubble-left"];
balloonImage = [balloonImage resizableImageWithCapInsets:(UIEdgeInsets){36, 32, 18, 12}];
self.bubbleView.image = balloonImage;
self.avatarView.layer.cornerRadius = 25;
self.avatarView.clipsToBounds = YES;
self.avatarView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture1 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:)];
tapGesture1.numberOfTapsRequired = 1;
[tapGesture1 setDelegate:self];
[self.avatarView addGestureRecognizer:tapGesture1];
}
- (void) tapGesture: (id)sender
{
UIViewController *vc = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"yourVcIdentifier"];
[self.navigationController pushViewController:vc animated:YES];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
How is that possible ?
Do like this in ViewController that holds tableview with this cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
IncomingMessageCell *cell = ...;
cell.avatarView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired = 1;
[cell.avatarView addGestureRecognizer:tapGesture];
cell.avatarView.tag = 500 + indexPath.row; // To detect cell that image belongs to, because you use dequeue cell
return cell;
}
- (IBAction)handleTapGesture:(UITapGestureRecognizer *)tapGesture{
//Do you action
NSLog(#"Row tap : %ld",tapGesture.view.tag - 500);
UIViewController *vc = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"yourVcIdentifier"];
[self.navigationController pushViewController:vc animated:YES];
}

iOS - How to present different scenes from UITableViewCell

I have a UIViewController with a TableView. The TableView is populated with an image and a text for each cell. Now I need to present others Scenes when the user taps a cell. For example:
- tap on first row --> present ViewController1 - tap on second row --> present ViewController2
ViewController1 and ViewController2 are scenes in my Storyboard.
I've tried various solutions, but none of these works. Moreover it seems that the method didSelectRowAtIndexPath: is not called when I tap a cell (for example I tried to show up an alert).
Here the code of my ViewController:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
{
NSArray *recipes;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
recipes = [NSArray arrayWithObjects:#"News", #"Calendar",#"Take a photo",#"Draw",#"Mail us",#"Follow us on Facebook", nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [recipes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [recipes objectAtIndex:indexPath.row];
if ([cell.textLabel.text isEqualToString:recipes[0]]) {
cell.imageView.image = [UIImage imageNamed:#"newsicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[1]]) {
cell.imageView.image = [UIImage imageNamed:#"mensaicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[2]]) {
cell.imageView.image = [UIImage imageNamed:#"fotoicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[3]]) {
cell.imageView.image = [UIImage imageNamed:#"drawicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[4]]) {
cell.imageView.image = [UIImage imageNamed:#"mailicon"];
}
else if ([cell.textLabel.text isEqualToString:recipes[5]]) {
cell.imageView.image = [UIImage imageNamed:#"fbicon"];
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// here we get the cell from the selected row.
UITableViewCell *selectedCell=[tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell.textLabel.text isEqualToString:recipes[0]]) {
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:#"You've selected a row" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display Alert Message
[messageAlert show];
NSString *storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"news"];
[self presentViewController:vc animated:YES completion:nil];
}
// use the image in the next window using view controller instance of that view.
}
#end
I'm new to iOS developing, so I don't know if my code is right or if there are other solutions more elegant of these. Anyway, let's focus on the problem, can anyone help me?
If your view is only a table view I'd suggest using a UITableViewController instead of a UIViewController. If you have a UITableView in an existing UIViewController you need to set up the delegate and data source methods yourself.
You can do this in the storyboard. Click on your tableView and then select the connections inspector. Then click the circle next to dataSource and drag it to your view controller. Do the same for delegate. This is probably why your table view methods aren't being called.
If it's a static table, you can create independent segues from each cell in the storyboard.
Moreover it seems that the method didSelectRowAtIndexPath: is not called when I tap a cell (for example I tried to show up an alert).
Your based class is UIViewController, therefore, your UITableViewDelegate and UITableViewDataSource won't get set automatically. You need to do it yourself. For example, you can set them in the init function:
- (instancetype)init {
self = [super init];
if( self ) {
self.delegate = self;
self.datasource = self;
}
return self;
}
An alternative is to use UITableViewController as your base call, then you don't need to worry about setting the delegates.
according to your code alert will only be shown when you click on 1st cell only..
but according to your needs let me write a code for that will help you..
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// here we get the cell from the selected row.
NSString *selectedcelltext=[recipes objectAtIndex:indexPath.row];
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:[NSString stringWithFormat:#"You've selected a %# row ",selectedcelltext] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// Display Alert Message
[messageAlert show];
if ([selectedcelltext isEqualToString:recipes[0]]) {
NSString *storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"news"];
[self presentViewController:vc animated:YES completion:nil];
}
else if ([selectedcelltext isEqualToString:recipes[1]]) {
NSString *storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"calendar"];
[self presentViewController:vc animated:YES completion:nil];
}
// use the image in the next window using view controller instance of that view.
}

iPhone open multiple view controllers on table view item click

Is it possible to open different view controllers depending on witch table view cell user clicks? I tried to do that with:
[self presentViewController:obj animated:YES completion:nil];
but when next view is presented, there is no navigation bar and I can't go back to table view.
EDIT:
Here is MasterViewController class that I am using
#import "MasterViewController.h"
#interface MasterViewController () {
NSArray *viewArray;
}
#end
#implementation MasterViewController
#synthesize items,itemImges;
- (void)awakeFromNib
{
if ([[[UIDevice currentDevice] systemVersion] compare:#"7" options:NSNumericSearch] != NSOrderedAscending) {
self.preferredContentSize = CGSizeMake(320.0, 480.0);
}
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
self.clearsSelectionOnViewWillAppear = NO;
}
self.title = NSLocalizedString(#"MasterTitle",#"Options:");
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
items = [NSArray arrayWithObjects:#"Media Explorer",#"Live TV",#"Settings",nil];
itemImges = [NSArray arrayWithObjects:
[UIImage imageNamed:#"listicon_guide.png"],
[UIImage imageNamed:#"listicon_livetv.png"],
[UIImage imageNamed:#"listicon_settings.png"],
nil];
// Do any additional setup after loading the view, typically from a nib.
self.detailViewController = (DetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController];
MediaExpDetailViewController *DVCA = [self.storyboard instantiateViewControllerWithIdentifier:#"MediaExpDetailViewController"];
LiveTVDetailViewController *DVCB = [self.storyboard instantiateViewControllerWithIdentifier:#"LiveTVDetailViewController"];
SettingsDetailViewController *DVCC = [self.storyboard instantiateViewControllerWithIdentifier:#"SettingsDetailViewController"];
//Create Array of views
viewArray = [NSArray arrayWithObjects:DVCA, DVCB, DVCC, nil];
}
#pragma mark - Table View
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return items.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSString *object = items[indexPath.row];
UIImage *image = itemImges[indexPath.row];
cell.textLabel.text = [object description];
cell.imageView.image = image;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//for iPad
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
//something goes here
}
else { //for iPhone
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
MediaExpDetailViewController *objSynergy = (MediaExpDetailViewController *)[mainStoryboard instantiateViewControllerWithIdentifier:#"MediaExpDetailViewController"];
[self.navigationController pushViewController:objSynergy animated:YES];
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
}
#end
First set Storyboard IDs for your Next View controllers in Interface Builder and then.
-(void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Check Row and Select Next View controller
if (indexPath.row == 1)
{
// Push Selected View
UIViewController *view1 = [self.storyboard instantiateViewControllerWithIdentifier:#"StoryboardID"];
[self.navigationController pushViewController:view1 animated:YES];
}
}
That's because
[self presentViewController:obj animated:YES completion:nil];
Presents the new view controller modally (over top of the existing visible controller). If you want to push to a new view controller using your navigation controller, you'll want to use this. Of course you'll want to make sure that the view controller you're pushing from is embedded within a UINavigationController.
[self.navigationController pushViewController:obj animated:YES];
And to answer your first question, yes it absolutely is possible. Just add some condition logic to your didSelectRowAtIndexPath: UITableViewDelegate method.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (someCondition) {
[self.navigationController pushViewController:obj animated:YES];
}else{
[self.navigationController pushViewController:otherObj animated:YES];
}
}
Modally presented view controllers don't have navigation bars by default. You have to embed them in a UINavigationController, in order to have one. You should also implement how to dismiss the presented view controller by yourself, calling dismissViewControllerAnimated at the appropriate times.
However, I'd recommend to push your view controllers (with pushViewControllerAnimated), instead of presenting them modally, if you don't specifically need the modal functionality.

Updating DetailViewController from RootController

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.
I can accomplish both tasks, but not together.
I mean I can make a multi-level table view in the RootController.
Or I can make a single-level table view in the RootController which can update the detailViewController.
Can anyone tell me how to make a multi-level table in the RootController which can update a detailViewController?
There is more source code at the link but below is the method in which I presume I have to declare a new detailViewController (which has to be put in the UISplitViewController):
- (void)tableView:(UITableView *)TableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *dictionary = [self.tableDataSource objectAtIndex:indexPath.row];
//Get the children of the present item.
NSArray *Children = [dictionary objectForKey:#"Children"];
//
if([Children count] == 0) {
/*
Create and configure a new detail view controller appropriate for the selection.
*/
NSUInteger row = indexPath.row;
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
if (row == 0) {
FirstDetailViewController *newDetailViewController = [[FirstDetailViewController alloc]initWithNibName:#"FirstDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
if (row == 1) {
SecondDetailViewController *newDetailViewController = [[SecondDetailViewController alloc]initWithNibName:#"SecondDetailView" bundle:nil];
detailViewController = newDetailViewController;
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers//nothing happens.....
[viewControllers release];//
}
else {
//Prepare to tableview.
RootViewController *rvController = [[RootViewController alloc]initWithNibName:#"RootViewController" bundle:[NSBundle mainBundle]];
//Increment the Current View
rvController.current_level += 1;
//Set the title;
rvController.current_title = [dictionary objectForKey:#"Title"];
//Push the new table view on the stack
[self.navigationController pushViewController:rvController animated:YES];
rvController.tableDataSource = Children;
[rvController.tableView reloadData]; //without this instrucion,items won't be loaded inside the second level of the table
[rvController release];
}
}
Sorry, but I cannot post my source code as it contains sensitive information. When I have more time available I will create a separate project and upload the code somewhere.
Here are extracts of how I have done it so far (I welcome any feedback).
The RootViewController - Note I have 4 sections in my root table.
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
// Detail view logic
NSUInteger section = indexPath.section;
UIViewController <SubstitutableDetailViewController> *detailViewController = nil;
if (section == 2) {
ProductSearchDetailView *viewController = [[ProductSearchDetailView alloc] initWithNibName:#"ProductSearchDetailView" bundle:nil];
detailViewController = viewController;
//[viewController release];
}
else {
DetailViewController *defaultDetailViewController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
detailViewController = defaultDetailViewController;
//[defaultDetailViewController release];
}
// Navigation logic
switch (section) {
case 0:
{
break;
}
case 1:
{
break;
}
case 2:
{
// new Navigation view
ProductSearchViewController *viewController = [[ProductSearchViewController alloc] initWithNibName:#"ProductSearchViewController" bundle:nil];
viewController.navigationItem.backBarButtonItem.title = #"Back";
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
break;
}
case 3:
{
StoreLocatorNavController *viewController = [[StoreLocatorNavController alloc] initWithNibName:#"StoreLocatorNavController" bundle:nil];
viewController.navigationItem.backBarButtonItem.title = #"Back";
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
break;
}
}
// Update the split view controller's view controllers array.
NSArray *viewControllers = [[NSArray alloc] initWithObjects:self.navigationController, detailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
// Dismiss the popover if it's present.
if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
// Configure the new view controller's popover button (after the view has been displayed and its toolbar/navigation bar has been created).
if (rootPopoverButtonItem != nil) {
[detailViewController showRootPopoverButtonItem:self.rootPopoverButtonItem];
}
[detailViewController release];
}
NSNotificationCenter part
Add this to ProductSearchViewController:
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *itemAtIndex = (NSDictionary *)[self.productResults objectAtIndex:indexPath.row];
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateProduct" object:itemAtIndex];
}
And finally, add this to ProductSearchDetailViewController:
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateTheProductDetails:) name:#"updateProduct" object:nil];
}
- (void)updateTheProductDetails:(NSNotification *)notification {
NSDictionary *productDictionary = [NSDictionary dictionaryWithDictionary:[notification object]];
// product name
_productName.text = [productDictionary objectForKey:#"ProductDescription"];
}
Hope it helps!

Resources