button click to remember value when a table view is pushed - iphone

I have a view controller with 6 buttons on it. Each of these buttons push a single table view controller which will be propagated with items depending on what value the button had. Lets say the buttons were 'car', 'van' etc. is it possible to remember the value of the button when the table view is pushed so that the twitter search can be based on the value handed over by the button i.e #car? I can do this with 6 different table views as I can just assign a viewDidLoad method to each based on the search but I would rather only do it once and allow the table view to 'fill in' the value on the button automatically. Here is my code:
- (void)fetchTweets
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: #"https://api.twitter.com/1/statuses/public_timeline.json"]];
NSError* error;
tweets = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
});
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return tweets.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *text = [tweet objectForKey:#"text"];
NSString *name = [[tweet objectForKey:#"user"] objectForKey:#"name"];
cell.textLabel.text = text;
cell.detailTextLabel.text = [NSString stringWithFormat:#"by %#", name];
return cell;
}

Easy man. Set a public property on that TableViewController to hold that value:
In the TVC .h file:
#property(nonatomic,strong) NSString *selectedButtonText;
And synthesize it in the TVC .m file
#synthesize selectedButtonText;
If you are using Storyboard, just make sure you have the segue wired up to the ViewController itself and NOT to the buttons and then in each of the buttons IBActions do something like:
[self performSegueWithIdentifier#"mySegueID" sender:sender];
In the prepareForSegueMethod (implement if you haven't already:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"mySegueID"]) {
// Cast the sender as a UIButton to get the text
UIButton *tappedButton = (UIButton *)sender
MyTableViewController *mtvc = segue.destinationViewController;
mtvc.selectedButtonText = tappedButton.titleLabel.text;
}
}
Then do whatever you want to with that value in your TableViewController
* EDIT *
For a custom attribute on an object (like a UIButton). Add a new file to your project (I put them in a group called Custom Subclasses). This file should be of UIButton class. Name it TweetButton.
Then replace what you have in TweetButton.h with this:
import
#interface TweetButton : UIButton
#property(nonatomic, strong) NSString *buttonName;
#end
TweetButton.m should look like:
import "TweetButton.h"
#implementation TweetButton
#synthesize buttonName;
#end
Then just change the parent class of each of those buttons to TweetButton instead of UIButton (this will be done in Interface Builder).
Then in each of the IBActions, cast that button to type of TweetButton and access/set the name property.
After going through all this, another idea would be to just add in a property (NSString) in the ViewController that is calling the segue (the one with the buttons) and set that to whatever you want and then use that to send to the destination VC.

Related

How do I utilize CoreData when moving from collection view to detail view

I have an IOS app that is using RestKit to pull json formatted data from a server into a CoreData Entity. Some of the attributes of the entity help populate a collection view with an image and title for each cell.
I am attempting to move from the collection view to a detail view when a cell is selected. There is a "summary" attribute of the CoreData Entity that I would like to display in the detail view along with the image.
I know I can pass data thru the prepareForSegue method. But I am not sure how to specify the image and summary data I want to pass.
Maybe passing the image and summary is not the proper way? Should I be passing the managedObjectContext to the detail view controller and fetching the results from there?
Here is how my CollectionView is populated.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
MyNewsCollectionViewCell *cell = (MyNewsCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath];
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSURL *photoURL = [NSURL URLWithString:(NSString *) [object valueForKey:#"imageUrl"]];
NSData *photoData = [NSData dataWithContentsOfURL:photoURL];
[cell.cellimg setImage:[[UIImage alloc] initWithData:photoData]];
[cell.title setText:[object valueForKey:#"title"]];
return cell;
Here is the prepareForSegue method
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"newsDetail"]) {
NewsDetailViewController *vc =[segue destinationViewController];
vc.newsDetailImageView = //How do I designate the image from the cell I selected???
vc.newsDetailText = //How do I designate the text from the cell I selected???
}
}
This is obviously a beginners question.... any help would be much appreciated. Given that I'm a beginner basic example code really helps!
If the cell selection triggers the segue instantly, you can make use of the indexPathForSelectedItems method of UICollectionView to get the indexPath that you need to get your NSManagedObject.
Try this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"newsDetail"]) {
NewsDetailViewController *vc =[segue destinationViewController];
// In the following line, replace self.collectionView with your UICollectionView
NSIndexPath *indexPath = [[self.collectionView indexPathsForSelectedItems] objectAtIndex:0];
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSURL *photoURL = [NSURL URLWithString:(NSString *)[object valueForKey:#"imageUrl"]];
NSData *photoData = [NSData dataWithContentsOfURL:photoURL];
UIImage *img = [[UIImage alloc] initWithData:photoData];
vc.newsDetailImageView = [[UIImageView alloc] initWithImage:img];
vc.newsDetailText = howeverYouGetYourObjectSummary;
}
}
You could add a property to you MyNewsCollectionViewCell, like so:
#property (weak,nonatomic) NSManagedObject* myObject;
Then you could assign this property the NSManagedObject for this cell in cellForItemAtIndexPath.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
/* Add this line to All that u r already doing*/
[cell setMyObject:object];
return cell;
}
Now in didSelectCellMethod you can call [self performSegueWithIdentifier: #"MySegue" sender: cell];
and then in prepareForSegue: get the object from the sender.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(MyNewsCollectionViewCell)sender
{
if ([[segue identifier] isEqualToString:#"newsDetail"]) {
NewsDetailViewController *vc =[segue destinationViewController];
NSManagedObject* object = sender.myObject;
//use this object to set values of
vc.newsDetailImageView = /*set value*/
vc.newsDetailText = /*set value*/
}
}

How to get UITableview cell.textlabel.text value from button click?

i am a newbie to iphone development.
I am working on a project where i am having a UItableview , i placed a button in each row .
Now my UItableView have a cell.textlabel, detailLabel, and a button placed programatically.
In cell.textlabel i have some values from json(each label have different values) and just at the right corner of each row , i placed a button.
Now i want the cell.textlable.text value of that row only whose button is pressed.
I am getting the same value for each button.
So , my question is , how to get labeltext value of the specific row whose button is pressed ?
attach a tag with your button during its creation e.g. button1.tag = 9999;
in your button click action grab the button as sender
-(void)buttonaction:(UIButton*)sender
{
UITableViewCell * selectedCell = nil;
for(UITableViewCell *cell in [tableView visibleCells])
{
if([cell viewWithTag:9999] == sender)
{
selectedCell = cell;
break;
}
}
//do whatever you like with selected cell now.
}
I hope it helps!!!
Solved like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
UIButton *tableCellButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect]retain];
tableCellButton.frame = CGRectMake(200, 1, 80, 20);
[tableCellButton setTitle:#"showing" forState:UIControlStateNormal];
[tableCellButton addTarget:self action:#selector(shortcutBottonClicked:) forControlEvents:UIControlEventTouchUpInside];
[cell addSubview:tableCellButton];
} NSDictionary *listing = [ self.temp objectAtIndex:indexPath.row];
cell.textLabel.text = [listing objectForKey:#"0"];
return cell;
}
-(IBAction) shortcutBottonClicked:(id)sender{
//this code solved the problem
indexPath = [self.tableView indexPathForCell:(UITableViewCell*)[sender superview]];
mlsid2 = [self.tableView cellForRowAtIndexPath:indexPath].textLabel.text;
}
I think you mean that each row in the table has a button, and any number of them can be pressed. After the user is done pressing buttons for rows, you need to get which rows of data have been pressed.
If I read you correclty then unless your table is static, it will work something like the following:
You need to have a datastructure like the one I'm assuming you have for your UITableview datasource. For example, an NSArray full of NSNumber objects, one corresponding to each row of data. When the button in a row is pressed, the corresponding NSNumber is set 1. When you need it, just iterate through the NSArray of NSNumbers to know the corresponding rows in your table's datasource that had it's button pressed.
One thing to be aware of is that UItableview cells that you see in the UI are normally reused as the user scrolls - at least this is the case if you have a variable amount of data and rows for your table (as opposed to static), so you can't rely on the UI elements, like the button, for remembering the state
in first view .h file
#
class viewController;
#import <UIKit/UIKit.h>
#interface firstViewController : UITableViewController<UITableViewDelegate, UITableViewDataSource> {
NSString *_cellTitle;
}
#end
first view .m file in didSelectRowAtIndex method add this code like
viewController *detailViewController = [[viewController alloc] initWithNibName:#"viewController" bundle:nil];
NSInteger row = [indexPath row];
_rowTitle = [_detailList objectAtIndex:row];
detailViewController._barTitle = _rowTitle ;
or you can do this in buttonPressed method
then in the second view .h section -
#interface viewController : UIViewController {
NSString *_barTitle;
}
#property (nonatomic, retain) NSString *_barTitle;
#end
synthesize this property in implementation section
in .m and under viewDidLoad method
self.navigationItem.title = _barTitle;
don't forget to import second view .h file
hope this helps

Fetching Values from textField in a custom cell iPhone

I have a custom cell in a table View, see below.
I have two textFields txt1 and txt2 in my custom cell, as seen below
How can i access the values i enter in each of the text fields so that i can add the values in to seperate Arrays...
the "Addset" button will increment the no of sections of the grouped table View there by incrementing the one more set.
my table view code is as follows.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellID= #"catogoryCell";
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:cellID];
if(cell==nil)
{
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomCell" owner:nil options:nil];
for(id currentObject in nibObjects)
{
if([currentObject isKindOfClass: [CustomCell class]])
{
cell = (CustomCell *)currentObject;
}
}
}
//cell.txt1.text = #"0";
return cell;
}
Thanks all..
Cells are reusable, so they need a more persistent way to keep their info.
Method 1:
You could hold some UITextField objects into an array in case you don't want to reuse the textfields as well, and at cellForRowAtIndexPath you'd only need to set the textfields to their cells such as:
cell.txt1 = [textFieldsArray objectAtindex:indexPath.section*2];
cell.txt2 = [textFieldsArray objectAtindex:indexPath.section*2+1]; //txt1 and txt2 properties should have assign
Method 2:
If you want to reuse the textfields as well I suggest using an array with mutable dictionaries, each dictionary holding the 'settings' for a cell. The textfields will be fully managed by the custom cell (e.g: at the UIControlEventValueChanged event update #"txt1" or #"txt2" values from the dictionary attached to the cell).
///somewhere in the initialization (in the class holding the tableview)
contentArray = [[NSMutableArray alloc] init];
///when adding a new cell (e.g: inside the 'Add set' action)
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:#"", #"txt1", #"", #"txt2", nil]];
//add a new cell to the table (the same way you do now when tapping 'Add set')
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
...
[cell attachDictionary:[contentArray objectAtIndex:indexPath.section]];
return cell;
}
///anywhere where you'd like to access the values inserted inside a cell
NSMutableDictionary *cell3Content = [contentArray objectAtIndex:3];
NSString *text1 = [cell3Content valueForKey:#"txt1"];
NSString *text2 = [cell3Content valueForKey:#"txt2"];
///CustomCell.m
-(id)initWithCoder:(NSCoder *)decoder{
self = [super initWithCoder:decoder];
if(!self) return nil;
[txt1 addTarget:self action:#selector(txt1Changed:) forControlEvents:UIControlEventValueChanged];
[txt2 addTarget:self action:#selector(txt2Changed:) forControlEvents:UIControlEventValueChanged];
return self;
}
-(void)attachDictionary:(NSMutableDictionary *)dic{
contentDictionary = dic;
txt1.text = [contentDictionary valueForKey:#"txt1"];
txt2.text = [contentDictionary valueForKey:#"txt2"];
}
-(void)txt1Changed:(UITextField *)sender{
[contentDictionary setValue:txt1.text forKey:#"txt1"];
}
When you make the IBOutlet connections in your UITableViewCell subclass, connect them to properties in the File Owner (the viewController), instead of the view itself. That way you'll be able to access them from your viewController (the UItableViewDataSource)

UITableView with JSON help

I am trying to feed in some JSON data to my iPhone app, the data is coming in fine as I have NSLog's telling me so.
The problem I am having is trying to get the results to show in a UITableView. I have a navigation controller underneath a tab bar controller, the navigation controller contains a table view controller which loads another NIB file with a table view connected to a class which is the delegate and data source delegate.
I also need to categorize the results into sections - these being
England
Scotland
Wales
N.Ireland
To get an idea of what JSON string I am using see this one.
As you can see the JSON does not cater for the sections but I am yet to implement this, so i would need to know beforehand so I do not have to amend much code later on.
OK - I am using Stig JSON parser.
Here is my ListVenuesView.h (connected to table view)
#import <UIKit/UIKit.h>
#import "SBJson.h"
#interface ListVenuesView : UITableViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *venueList;
NSMutableDictionary *jsonArray;
}
#property (nonatomic, retain) IBOutlet UITableView *venueList;
#property (nonatomic, retain) NSMutableDictionary *jsonArray;
#end
jsonArray is used to store the JSON data and eventually the proper array.
And here is my ListVenuesView.m (key areas in question)
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Table View Loaded");
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
// This is where we load the JSON data
NSURL *jsonURL = [NSURL URLWithString:#"http://www.thebigfishexperience.org.uk/sources/ajax/venue-json.php?location=peterborough"];
NSString *jsonData = [[NSString alloc] initWithContentsOfURL:jsonURL];
NSLog(#"%#", jsonData);
// Convert jsonData to array
self.jsonArray = [jsonData JSONValue];
NSLog(#"%#", jsonArray);
NSLog(#"count is: %i", [self.jsonArray count]);
// Release NSString and NSURL
[jsonURL release];
[jsonData release];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.jsonArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSMutableDictionary *dict = [self.jsonArray objectAtIndex: indexPath.row];
cell.textLabel.font = [UIFont fontWithName:#"Arial" size:15.0];
cell.textLabel.text = [dict objectForKey:#"venueName"];
cell.detailTextLabel.text = [dict objectForKey:#"venueCordDist"];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Configure the cell...
return cell;
Also how can I use the data in the cells to go to another subview of the nav controller which gives me a back button and displays the info from the JSON string just for that particular cell that has been tapped.
I think this has something to do with it? Not sure though as this is my first app i am building! So probably expect more pleas of assistance - ha ! ;)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"Nib name" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
On selecting a row, as mentioned by u, we are navigating to another view. Let us assume that the view controller is DetailViewController which is a sub-class of UIViewController.
In the DetailViewController.h , declare a NSDictionary object.
In DetailViewController.m, add
-(void)setVenueDict:(NSDictionary*)venueDict
{
if( _venueDict )
{
[_venueDict release];
}
_venueDict = [venueDict retain];
}
In ParentViewController, ur didSelectRow.. method should be like this.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"Nib name" bundle:nil];
// ...
// Pass the selected object to the new view controller.
NSDictionary *dict = [self.jsonArray objectAtIndex: indexPath.row];
[detailViewController setVenueDict:dict];
detailViewController.title = [dict objectForKey:#"venueName"];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
In the second view controller, u can do whatever u want with the _venueDict.
Nathan,
since you want to reuse the data parsed from the JSON feed over more than one ViewController the best way to approach this is to build an object Model so that you can pass the object for the selected row in the list to the detail ViewController.
I would also separate the JSON parsing code into a separate class and not keep it in the ViewController.
You can find classes to fetch JSON on this link.
The result from the custom code to parse the JSON feed would give back a NSDictionary with as keys the section names you mention. And the value in the NSDictionary for those keys would be an array of your custom objects that contain all the relevant data for one row (and detail screen).
Hope this helps you on your way.
jsonArray is NSMutableDictionary.
have to use
[jsonArray objectForKey:key];
//check this line
NSMutableDictionary *dict = [self.jsonArray objectAtIndex: indexPath.row];
this may help.

iOS: Custom UITableViewCell touch receiver confusion

have seen similar questions but couldn't find a definitive answer.
Having mastered regular tables of most types, I am doing some conceptual experiments with custom table cells to get familiar with how this works. I want to have a custom subclass of UITableViewCell which loads a nib to the contentView. I may want to implement different editing styles at some later point but want to reuse the custom view in different parts of my application, however, i'm having problem receiving the didSelectRowAtIndexPath message in my calling UITableViewController.
Here's the hierarchy which is built from a basic view template.
CustomCellViewController: A stock XCode objective-c class sublcassed from UITableViewCell
#interface CustomCellViewController : UITableViewCell {
IBOutlet UILabel *lbl;
}
#property (nonatomic, retain) IBOutlet UILabel *lbl;
#end
#implementation CustomCellViewController
#synthesize lbl;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
NSArray *a = [[NSBundle mainBundle] loadNibNamed:#"customCellView" owner:self options:nil];
UITableViewCell *tc = [a objectAtIndex:0];
NSLog(#"Cell loaded from nib");
[self.contentView addSubview:tc];
}
return self;
}
.. the other stock methods are unchanged ..
#end
I realise that the init method could be simplified but this is my first attempt.
The XIB file's owner is my custom class (CustomCellViewController), has a UITableViewCell and a label (linked to the outlet 'lbl' on it) positioned half way accross, leaving plenty of the underlying UITableViewCell clickable.
RootViewController is a standard, stock XCode subclass of UITableViewController
RootViewController sets up an instance variable "CustomTableCellController *myCustomCell"
The cellForRowAtIndexPath: is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"myCustomCell";
CustomCellViewController *cell = (CustomCellViewController *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[CustomCellViewController alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
NSLog(#"Creating New cell for position %d", indexPath.row);
} else {
NSLog(#"Reusing cell for position %d", indexPath.row);
}
// Configure the cell.
cell.lbl.text = [NSString stringWithFormat: #"Hi There %d", indexPath.row];
return cell;
}
And in the same RootViewController.m, my didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Cell tapped at row %d", indexPath.row);
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
Designed at present, to purely output a log message when tapped.
numberOfSectionsInTableView returns 1
numberOfRowsInSection returns 50
This all compiles and runs fine, iPhone simulator starts, I see a table on the display, my output log confirms it has created 9 versions of CustomCellViewController and I can see the reuse stack via the NSLog() comments.
I just can't select a row, doesn't matter where I click in the custom cell, nothing gets to my didSelectRowAtIndexPath: in my RootViewController which is where I expect it.
Is it that I have I not set a delegate somewhere and if so, how? Do I need to do this via a first responder? (ie, create a method in my CustomCellViewController class, link the UITableViewCell from the XIB to that method and then call [super didSelectRowAtIndexPath] - but how do I pass the indexPath?
Am I not responding to a message from my XIB in it's owner and then passing it on (is this how I do it?)
I read through all the apple docs to get to this stage but couldn't quite decipher how touch messaging happened.
Slightly confused!
May be you have forget to set data source and delegate if the tableview object set it as like below
tbl.delegate = self;
tbl.dataSource = self;