Detail View Controller from Table View Controller WITHOUT Storyboard? - ios

I have a tableview in a controller that shows receipts and their image, date created, etc.
I made it so when the user taps a cell, it goes to DetailViewController. Using this code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ReceiptDetailViewController *controller = [[ReceiptDetailViewController alloc] initWithNibName:#"ReceiptDetailViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
}
I'd like to pass the image, date, category, etc, to my new view in a UIImageView, textView, etc.
This is the code for my Table in the first controller:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
cell.selectionStyle = UITableViewCellSelectionStyleGray;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
Receipt *receipt = [self.receiptsArray objectAtIndex:indexPath.row];
ReceiptCategory *category = receipt.relationshipToCategory;
ReceiptImage *image = receipt.relationshipToImage;
cell.textLabel.text = category.receiptCategory;
cell.detailTextLabel.text = receipt.date.description;
if(self.imageCache.count <= indexPath.row) {
[self.imageCache addObject:[UIImage imageWithData:image.data]];
}
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
imageView.image = [self.imageCache objectAtIndex:indexPath.row];
cell.imageView.image = imageView.image;
return cell;
}
How do I pass this data? I have searched around for two days now and all solutions include a storyboard, which I am not using.

You should get reference to your receipt in didSelectRowAtIndexPath: and pass it to ReceiptDetailViewController. I assume you have property to accept the data in ReceiptDetailViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get reference to receipt
Receipt *receipt = [self.receiptsArray objectAtIndex:indexPath.row];
ReceiptDetailViewController *controller = [[ReceiptDetailViewController alloc] initWithNibName:#"ReceiptDetailViewController" bundle:nil];
// Pass data to controller
controller.receipt = receipt;
[self.navigationController pushViewController:controller animated:YES];
}
It this example you should create property in ReceiptDetailViewController.h file:
#property(nonatomic, strong) Receipt *receipt;
Now you can use it in your ReceiptDetailViewController object.

You should just use Table View Delegate Method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
There you can retrieve the selected receipt and pass the data to the detail view like that:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ReceiptDetailViewController *controller = [[ReceiptDetailViewController alloc] initWithNibName:#"ReceiptDetailViewController" bundle:nil];
Receipt *selectedReceipt = [self.receiptsArray objectAtIndex:indexPath.row];
controller.receipt = selectedReceipt;
[self.navigationController pushViewController:controller animated:YES];
}

You can create a custom class for your detailed view controller and create an object of the same when the user clicks on any cell.
Something like this
DetailViewControllerClass *newObject = [[DetailViewControllerClass alloc] init];
newObject.data1 = dataToBeSent ; //assign data

You should make an object of Receipt in ReceiptDetailViewController and make the property nonatomic and strong Than in tour view controller Write this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
Receipt *receipt = [self.receiptsArray objectAtIndex:indexPath.row];
ReceiptDetailViewController *controller = [[ReceiptDetailViewController alloc] initWithNibName:#"ReceiptDetailViewController" bundle:nil];
controller.objReceipt= receipt;
[self.navigationController pushViewController:controller animated:YES];
}

Related

Passing data between viewcontroller through property

I have a dictionary on Viewcontroller A .I am passing it on viewcontroller B.On ViewController A it shows data on the dictionary of viewcontroller B.But ,In Viewcontroller it doesnt show any data in it?
ViewController A:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
if (cell== nil) {
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
if(_List.count>0) {
[cell setupCell:[_List objectAtIndex:indexPath.row]];
ViewControllerB *vc=[[ViewController alloc]init];
vc.userIdInfo=[_List objectAtIndex:indexPath.row];
}
return cell;
}
ViewController B:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"_userIdInfo %#",userIdInfo);
if([userIdInfo valueForKey:#"UserID"]) {
[self fetchDataFromServer:getdetail];
}
}
This NSLog(#"_userIdInfo %#",userIdInfo) prints null. while vc.userIdInfo prints dictionary
{
Count = 3;
UserID = "6gdab241-j176-1121-lde2-as8d21f62231";
UserName = "abc#gmail.com";
}
In objective C, cellForRowAtIndexPath methods is used for showing the data.
As per code, you are intiallising the ViewController B in cellForRowAtIndexPath.
it will allocate ViewController B multiple time which lead to memory consumptions.
I would suggest you to initialise in ViewDidLoad of ViewController A.
For Passing the data from A to B, you need to Use didSelectRowAtIndexPath method of UITableViewDelegate.
Example:
ViewController A:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
if (cell== nil) {
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
if(_List.count>0) {
//Use to show data
cell.textLabel.text = [NSString stringWithFormate:#"%#",[_List objectAtIndex:indexPath.row]]];
// [cell setupCell:[_List objectAtIndex:indexPath.row]];
// ViewControllerB *vc=[[ViewController alloc]init];
// vc.userIdInfo=[_List objectAtIndex:indexPath.row];
}
return cell;
}
ViweController B
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// 1st Type
ViewControllerB *vc=[[ViewController alloc]init];
vc.userIdInfo=[_List objectAtIndex:indexPath.row];
[self.navigartionController pushViewController:aVC animated:YES];
}
You need to do ViewController B initialization in DID select method like below.
Don't initialize it in cellForRowAtIndexPath.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// 1st Type
ViewControllerB *vc=[[ViewController alloc]init];
vc.userIdInfo=[_List objectAtIndex:indexPath.row];
[self.navigartionController pushViewController:aVC animated:YES];
//2nd Type
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewControllerB *aVC = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
aVC.userInfo = <set your data>;
[self.navigartionController pushViewController:aVC animated:YES];
}
Hope this will helps.
The code
ViewControllerB *vc=[[ViewController alloc]init];
vc.userIdInfo=[_List objectAtIndex:indexPath.row];
only creates ViewController; it doesn't present it anywhere. moreover, the instance vc will be deallocated right after you leave the scope of
if(_List.count>0){}
your method
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"_userIdInfo %#",userIdInfo);
if([userIdInfo valueForKey:#"UserID"])
{
[self fetchDataFromServer:getdetail];
}
}
will never be called, because your view will never load.
I assume, that what you really want is to present your vc instance with navigationController instance, or from current viewController
[self.navigationController presentViewController: vc animated: YES completion: nil];

Pass data to new view from tableView

I have a table view which pushes a detailed view on cell click. The new view pushes however I'm trying to pass a web address to the detailed view which loads a webView but I'm unsure on how to do this. Here is my code:
-(void)setupArray {
webAddress = [[NSMutableDictionary alloc]init];
[webAdress setObject:#"http://www.google.com.au" forKey:#"first item"];
[webAdress setObject:#"http://www.yahoo.com.au" forKey:#"second item"];
menuItems = [webAdress allKeys];
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [webAdress count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *simpleTableIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
cell.textLabel.text = [menuItems objectAtIndex:indexPath.row];
return cell;
}
- (void) tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath {
DetailViewController *detailView = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
[self.navigationController pushViewController:detailView animated:YES];
}
Any help would be greatly appreciated.
You need to use a property for that in your detail view and pass the URL in the didSelectRowAtIndexPath method like this :
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailView = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
detailView.webAddress = [menuItems objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailView animated:YES];
}
and in your DetailView :
#property (nonatomic, strong) NSString *webAddress;
You should add an instance variable to the DetailViewController which will hold the address & set it to the desired value. Then (with the proper accessor) set it before/after pushing the view.
e.g. if you defined the variable as webAddress:
DetailViewController *detailView = [self.storyboard instantiateViewControllerWithIdentifier:#"detail"];
[detailView setWebAddress:[webAddress objectForKey:[menuItems objectAtIndex:[indexPath row]]]]; // or some other way to get the correct address
[self.navigationController pushViewController:detailView animated:YES];
The only thing that remains to be done is to set the web view's address to this value on viewWillAppear: or something.
Edit:
A sample viewWillAppear: method would look like this:
- (void)viewWillAppear:(BOOL)animated
{
// construct request
NSURL *url = [NSURL URLWithString:webAddress];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
[webView loadRequest:req];
[super viewWillAppear:animated];
}

My table view is loading the detail view in a dark screen

So i have a table view hooked up to a plist with urls. When I click on the table view cells i want it to take me to the detail view, but the only problem right now is when i click on the cell to take me to the detail view it just loads a dark screen with nothing on it. I don't receive any errors on the compiler so i have no idea what is wrong. I have reset the stimulator and tried restarting my computer but now I'm starting to think there is something wrong with the code. Can someone help?
TableViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSString *myListPath = [[NSBundle mainBundle] pathForResource:#"myList" ofType:#"plist"];
tableData = [[NSArray alloc]initWithContentsOfFile:myListPath];
NSLog(#"%#",tableData); }
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [tableData count]; }
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [tableData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if( cell == nil )
{
NSLog(#"Cell Creation");
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"cell"];
}
//Set Data For each Cell
cell.textLabel.text = [[tableData objectAtIndex:indexPath.row]objectForKey:#"cellName"];
cell.detailTextLabel.text = [[tableData objectAtIndex:indexPath.row]objectForKey:#"cellSubtitle"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Index Selected,%d",indexPath.row);
WebViewController *View = [[WebViewController alloc] init];
NSString *urltoPass = [NSString stringWithString:[[tableData objectAtIndex:indexPath.row]objectForKey:#"cellSubtitle"]];
View.urlString = [[NSString alloc] initWithFormat:#"http://%#",urltoPass];
View.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:View animated:YES completion:nil];
}
When you make a controller in a storyboard, you need to get an instance of that view controller by using instantiateViewControllerWithIdentifier:, not by using alloc init.
WebViewController *View = [self.storyboard instantiateViewControllerWithIdentifier:#"WebView"];
In the storyboard, you need to give the controller the identifier "WebView".

Tableview with details

I have created a tableview with the data from an array. Now i want the details for all the rows of the tableview. If i select any recipe from the tableview it should show me all the ingredients and procedure to prepare that recipe with a pic of that particular recipe on top. I am new to this field so kindly help.
Here's "ViewController.m"
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
RecipeList = [[NSMutableArray alloc]init];
[RecipeList addObject:#"Chicken Kabab"];
[RecipeList addObject:#"Chicken Tikka"];
[RecipeList addObject:#"Chicken 65"];
[RecipeList addObject:#"Chicken Do Pyaza"];
CGRect frame = self.view.frame;
RecipeTable = [[UITableView alloc]initWithFrame:frame style:UITableViewStylePlain];
RecipeTable.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
RecipeTable.backgroundColor = [UIColor cyanColor];
RecipeTable.delegate = self;
RecipeTable.dataSource = self;
[self.view addSubview:RecipeTable];
[RecipeTable setScrollEnabled:YES];
[RecipeTable setUserInteractionEnabled:YES];
[RecipeTable setRowHeight:35];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return #"RECIPES";
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return RecipeList.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
cell.textLabel.text = [RecipeList objectAtIndex:indexPath.row];
return cell;
}
#end
Just pass recipe name to the detailViewController. Then depending on the name of the recipe you can load the suitable image in UIImageView.
In the code recipename is an NSString in detailViewController. Declare it as a property..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
NSString *name=[recipe objectAtIndex:indexPath.row];
detailViewController.recipename=name;
[self.navigationController pushViewController:detailViewController animated:YES];
}
Then in the detaiViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
if([recipename isEqualToString:#"Pizza"])
{
UIImage *image = [UIImage imageNamed: #"pizza.png"];
[img setImage:image];
}
else if([recipename isEqualToString:#"Chicken 65"])
{
UIImage *image = [UIImage imageNamed: #"chicken.png"];
[img setImage:image];
}
}
you must use the DidSelectRow Delegate of UITableView . Then if you select a recipe it calls the DidSelectRow delegate .Inside this delegate you do the coding for pushing to a new ViewController . Create an UIImageView on top of your new ViewController , then pass the image from your TableViewCell to the UIImageView of your new viewController
If you want the details of a particular Dish populated in another ViewController that is pushed, the easiest way is by creating an NSObject with all the details required for that particular dish and maintaining it as an array. When you select a row in tableView, the didSelectRowAtIndexPath: get the object at that indexPath and pass it to the next VC which is being pushed. In the detail VC you can populate the details with that from the object.
Instead of doing like this
RecipeList = [[NSMutableArray alloc]init];
[RecipeList addObject:#"Chicken Kabab"];
do something like
RecipeList = [[NSMutableArray alloc]init];
[RecipeList addObject:dishObj];
where dishObj is an NSObject, of Class Dish which contains Dish name, image and recipe.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
Dish *dishObject = [RecipeList objectAtIndex:indexPath.row];
cell.textLabel.text = dishObject.dishName;
return cell;
Try this ,
you must use the DidSelectRow Delegate of UITableView
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
NSString *strDishName = [RecipeList objectAtIndex:indexPath.row];
detailViewController.strDishDetail =strDishName;
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
}
I hope the following tutorial will useful for u..Segue

how to make pushViewController: work in the following case?

I have a Navigation Controller embedded in a RootViewController. The elements present inside the RootViewController are a segmented control and a UIView. As the different segments are selected, the UIView displays a corresponding ViewController.
Now each of the ViewController being displayed in the UIView is a UITableViewController.
I need to display the table values as per the segment selections. And also if any of the row of the table is selected, it has to move to a newer ViewController with the detailed view.
I am able to display the UITableViewControllers as per the segment change. However, when i click on the row of the table, the newer ViewController that comes up is blank (Black Screen) even though I have created the particular ViewController in the Storyboard and set up an identifier as well.
Code for the Segmented Control change in ViewController.m
- (void)segmentedControlChangedValue:(UISegmentedControl*)segmentedControl {
int selIndex = segmentedControl.selectedIndex;
if (selIndex == 0)
{
aTable = [[aTableViewController alloc] init];
aTable.view.frame = self.myView.bounds;
[self.myView addSubview:aTable.view];
[self addChildViewController:aTable];
}
if (selIndex == 1)
{
bTable = [[bTableViewController alloc] init];
bTable.view.frame = self.myView.bounds;
[self.myView addSubview:bTable.view];
[self addChildViewController:bTable];
}
if (selIndex == 2)
{
//NSLog (#"Well you selected a 3rd option");
}}
Code for the didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
newDetailController* newController = [self.storyboard instantiateViewControllerWithIdentifier:#"Detail"];
newController = [[newDetailController alloc] init];
[[self navigationController] pushViewController:newController animated:YES];}
The pushViewController pushes an empty view for me even though I have specified the ViewController to use in the Storyboard design and also using an identifier.
Please help me in understanding what I must do to rectify this error.
UPDATE - The above problem has been resolved.
The problem I face now is being unable to access the data in the newViewController.
I pass the data to the newViewController as follows:
Create a class named newClass which contains all the elements I want to pass across.
Create a NSMutableArray "newObjects" in the firstViewController.
Create each newClass object at this method.
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object
{
static NSString *CellIdentifier = #"Cell";
customBigTableCell *cell = (customBigTableCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[customBigTableCell alloc] init];
}
cell.name.text = [object objectForKey:#"objName"];
newClass* newObj = [[newClass alloc] init];
newObj.objName = cell.name.text;
[newObjects addObject:newObj];
return cell;
}
Pls pardon me .. for the indenting with the code block is messed up...
Also the PFObject is cos i use Parse for database.
Add the created object to the newObjects array.
In the - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method, this is the code
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
newDetailController* newController = [storyboard instantiateViewControllerWithIdentifier:#"UpcomingDetail"];
obj = [[newClass alloc] init];
NSIndexPath* path = [self.tableView indexPathForSelectedRow];
obj = [newObjects objectAtIndex:path.row];
NSLog(#"Row selected is %ld", (long)path.row); //this returns the correct row selected
NSLog(#"Movie selected is %#", [[newObjects objectAtIndex:path.row] objName]);//however this is not the right one as per the cellForRowAtIndexPath method.
[newController setNewObj:obj];
[[self navigationController] pushViewController:newController animated:YES];
}
When I run this code, the row is selected correctly. However I dont get the corresponding row in the database. The array gets stored with redundant data.
You need to get rid of that middle line:
newController = [[newDetailController alloc] init];
That just redefines newController (as an empty controller with no view set up), which you defined in the first line.

Resources