Passing an array with prepareforsegue - iphone

I trying to pass an array through prepareWithSegue but I get null when I launch the app
this is the code :
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController isEqual:#"table"]) {
PersonsViewController *person= [[PersonsViewController alloc]init];
[person setAnArray:anArray];
person = segue.destinationViewController;
}
}
and this is setAnArray method:
-(void)setAnArray:(NSMutableArray *)anArray
{
array = [[NSMutableArray alloc]initWithArray:anArray];
if (array != nil) {
NSLog(#"array is copied !!");
}
}
the data should pass from viewController(embedded with UINavigation Controller) to PersonViewController (which is tableview) and nothing shows on the table so I NSLogged the the array count and found it zero so I did some further checking with this code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
// Return the number of rows in the section.
if (array == nil) {
NSLog(#"array is null");
}
else
{
NSLog(#"array count is %lu",(unsigned long)[array count]);
return [array count];
}
and I get array is null message.
please help me to fix this

Why don't you just allocate the view controller from the storyboard and pass the array in as a property of that view controller before you add it to the stack? i.e. avoid using prepareForSegue
-(void) buttonPressed:(UIButton*) sender
{
UIStoryBoard *story = [UIStoryboard storyboardWithName:#"Storyboard name"];
YourViewController *vc = [story instantiateViewControllerWithIdentifier:#"identifier"];
vc.array = <you array>
[self.navigationController pushViewController:vc animated:YES];
}

when you assign segue.destinationViewController to person your over writing the person object you previously instantiated and assigned the array to.
you probably want to do something like this
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.destinationViewController isEqual:#"table"]) {
[(PersonsViewController *) segue.destinationViewController setAnArray:anArray];
}
}

Related

How to make SearchBar in tableview work?

So i am trying to make an application that displays names of people in a tableview and on tap moves to the next view controller that shows an image of the person.
However when i add the search bar on the table view; i dont seem to have it right.
What am i doing wrong here?
The code compiles and displays on the simulator but when i click on any of the buttons, it gives me the errors i hate the most (Thread 1 : signal SIGABRT)
Here is my code for the Table View Controller
#import "PhotoTableViewController.h"
#import "Photo.h"
#import "DisplayViewController.h"
#interface PhotoTableViewController ()
#end
#implementation PhotoTableViewController
#synthesize photoSearchBar, showPhotos, filteredPhotos;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
showPhotos = [NSArray arrayWithObjects:
[Photo photoofname:#"Main" filename:#"photo1.jpg" notes:#"Amazing Road Bike"],
[Photo photoofname:#"Back" filename:#"photo3.jpg" notes:#"this is the back"], nil];
[self.tableView reloadData];
self.filteredPhotos = [NSMutableArray arrayWithCapacity:[showPhotos count]];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (tableView == self.searchDisplayController.searchResultsTableView) {
return [filteredPhotos count];
} else {
return [showPhotos count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Photo *photo = nil;
if (tableView == self.searchDisplayController.searchResultsTableView)
{
photo = [filteredPhotos objectAtIndex:indexPath.row];
}else
{
photo = [showPhotos objectAtIndex:indexPath.row];
}
cell.textLabel.text = photo.name;
[cell setAccessoryType:UITableViewCellAccessoryDisclosureIndicator];
return cell;
}
#pragma mark Content Filtering
-(void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope {
// Update the filtered array based on the search text and scope.
// Remove all objects from the filtered search array
[self.filteredPhotos removeAllObjects];
// Filter the array using NSPredicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.name contains[c] %#",searchText];
filteredPhotos = [NSMutableArray arrayWithArray:[showPhotos filteredArrayUsingPredicate:predicate]];
}
#pragma mark - UISearchDisplayController Delegate Methods
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// Tells the table data source to reload when text changes
[self filterContentForSearchText:searchString scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
// Tells the table data source to reload when scope bar selection changes
[self filterContentForSearchText:self.searchDisplayController.searchBar.text scope:
[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];
// Return YES to cause the search result table view to be reloaded.
return YES;
}
#pragma mark - TableView Delegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Perform segue to candy detail
[self performSegueWithIdentifier:#"candyDetail" sender:tableView];
}
#pragma mark - Segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"photoDetail"]) {
UIViewController *candyDetailViewController = [segue destinationViewController];
// In order to manipulate the destination view controller, another check on which table (search or normal) is displayed is needed
if(sender == self.searchDisplayController.searchResultsTableView) {
NSIndexPath *indexPath = [self.searchDisplayController.searchResultsTableView indexPathForSelectedRow];
NSString *destinationTitle = [[filteredPhotos objectAtIndex:[indexPath row]] name];
[candyDetailViewController setTitle:destinationTitle];
}
else {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSString *destinationTitle = [[showPhotos objectAtIndex:[indexPath row]] name];
[candyDetailViewController setTitle:destinationTitle];
}
}
}
Also this is the code for my Objective C Class called Photo
#import "Photo.h"
#implementation Photo
#synthesize name,filename,notes;
+(id) photoofname: (NSString*)name filename:(NSString*)filename notes:(NSString*)notes{
Photo *newPhoto = [[Photo alloc]init];
newPhoto.name = name;
newPhoto.filename = filename;
newPhoto.notes = notes;
return newPhoto;
}
#end
Well, just by looking at the code what I can suggest you is, first remove that call to prepareForSegue method called in UITableView's delegate method, didSelectForRowAtIndexPath.
You are overriding prepareForSegue, so in your storyboard you should have a prototype cell from where you have to ctrl-drag to the destination controller and segue it accordingly. That's a basic concept. Still having problem? Let us see your console messages when it crashes.

Finding objectForKey in search results

I have a list of NSMutableArrays with NSMutableDictionaries in with objectsandkeys in this. like:
[silestoneArray addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"Zen: Unsui", #"name",
#"silestone-unsui1.jpg", #"image", nil]];
I have a working search but I am now trying to segue to a detail view. I need to find a way of calling up the objects and keys from the search results so that when I segue from the search results the correct data is passed on.
My didselectrowatindexpath and prepareforsegue look like this:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableView == self.mainTableView){
[self.detailViewController setDetailItem:[[contentsList objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]];}
else
[self.detailViewController setDetailItem:[[contentsList objectAtIndex:indexPath.section]
objectAtIndex: indexPath.row]];
}
#pragma mark - Segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"detailview"]) {
UIViewController *detailViewController = [segue destinationViewController];
// In order to manipulate the destination view controller, another check on which table (search or normal) is displayed is needed
if(sender == self.searchDisplayController.searchResultsTableView) {
detailViewController = self.detailViewController=segue.destinationViewController;
}
else {NSLog(#"Sender: %#", [sender class]);
self.detailViewController=segue.destinationViewController;
}
}
}
and this passes to a detailview which call forth the data like so:
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.navigationItem.title = [self.detailItem objectForKey:#"name"];
[self.detailImage setImage:[UIImage imageNamed:self.detailItem[#"image"]]];
}
}
The problem I have at the moment is when I segue from the results it will send the results from my original table so no matter what the cell of the results says the image and title will correspond with the order of the unfiltered results.
I know this is because I am calling on contentsList for both in didselectrow but when I try with search results it crashes.
the error report is: -[__NSCFConstantString objectForKey:]: unrecognized selector sent to instance 0x21ed8
and under exemption breakpoints it says it is being thrown at this point:
self.navigationItem.title = [self.detailItem objectForKey:#"name"];
in this section of the detail view:
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.navigationItem.title = [self.detailItem objectForKey:#"name"];
[self.detailImage setImage:[UIImage imageNamed:self.detailItem[#"image"]]];
}
}
Thanks for any help.

How to use pushViewController and popViewController

I want to A viewcontroller switch another B viewcontroller,First time,I push(press GuestBook Button)and TableView get information ok,and press back Button ok, push(press GuestBook Button) again,JSON data NSLog have message,but tableview data not appear!
what's happen?
PS:i use storyboard!Have a custom cell xib!
A.m
- (IBAction)toHostGuestBook:(id)sender {
hgbvc = [self.storyboard instantiateViewControllerWithIdentifier:#"ToHostGuestBookSegue"];
hgbvc.eventidStr = eventidStr;
NSLog(#"hgbvc.eventidStr:%#",hgbvc.eventidStr);
[self.navigationController pushViewController:hgbvc animated:YES];
}
B.m
- (IBAction)backToHostMainEventDetail:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
B.m
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *GuestBookCellIdentifier = #"GuestBookCellIdentifier";
static BOOL nibsRegistered = NO;
if (!nibsRegistered) {
UINib *nib = [UINib nibWithNibName:#"GuestBookCell" bundle:nil];
[tableView registerNib:nib forCellReuseIdentifier:GuestBookCellIdentifier];
nibsRegistered = YES;
}
gbcell = [tableView dequeueReusableCellWithIdentifier:GuestBookCellIdentifier];
if (gbcell == nil) {
gbcell = [[GuestBookCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:GuestBookCellIdentifier];
}
NSDictionary *dict = [messageRows objectAtIndex: indexPath.row];
gbcell.nicknameStr = [dict objectForKey:#"vusr"];
gbcell.dateStr = [dict objectForKey:#"date"];
gbcell.messageStr = [dict objectForKey:#"message"];
return gbcell;
}
Add this and Try
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.tableView reloadData]; //your table view name
}
try to reload the table view data on below the code of popViewController this is work what you want
hgbvc the B controller is retained by the A controller. so, it doesn't released when the B controller poped out. When the B controller pushed again, the viewDidLoad method not called.
solution: extract the tableview load data method. call this method when you push B.
in B controller:
- (void)showDataWithEventId:(NSString *)eventId
{
//retrive data
//table view reload
}

UITextView doesn't update text after segue

I'm trying to update a UITextView's text property, after a segue, which happens after a row of a table view is tapped.
here is my code
MasterViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"4 Choices"]) {
NSLog(#"prepareForSegue is called");
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
NSString *questionContent = [[selectedObject valueForKey:#"questionContent"]description];
self.questionContent = questionContent;
[segue.destinationViewController setTextViewWith:self.questionContent];
}
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath is called");
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
NSNumber *questionID = [selectedObject valueForKey:#"qID"];
int i = [questionID intValue];
if (i == 1) {
[self performSegueWithIdentifier:#"4 Choices" sender:self];
}
else
{
[self performSegueWithIdentifier:#"5 Choices" sender:self];
}
}
DetailViewController.m
-(void)setTextViewWith:(NSString *)aText
{
self.questionText = aText;
NSLog(#"setTextViewWith is called");
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.questionView setText:self.questionText];
NSLog(#"viewWillAppear is called");
}
EDIT 1 : change the code to set the text at 'viewWillAppear'
EDIT 2 : add 'didSelectRowAtIndexPath'
Note : the segue was pointed from MasterViewController to DetailViewController (not from the
tableViewCell)
Thanks for your help : )
The text view may not be loaded at the prepareForSegue point. I've only just started with storyboards and have found that I had to set string properties on the destination view controller instead, then update the UI components in viewDidLoad or viewWillAppear.

How to push view depending on the row selection?

/*****UPDATED** ***/r.com/YH3cm.png
I am trying to figure out in the above image, how will we know if the user has selected Date or Track.
/UPDATED/
The data I am receving is through a select query and I create an array to store the list. It is dynamic and not necessary limited to two fields, it can have 10 fields also. How will I know which row is selected and how will I push the data on to the next view.
Like in didSelectRowAtIndexPath, how should I push the date or track field on the next view?
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (dvController == nil)
dvController = [[DetailViewController alloc] initWithNibName:#"DetailView" bundle:nil];
Teat *obj = [appDelegate.coffeeArray objectAtIndex:indexPath.row];
dvController.obj = obj;
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:dvController animated:YES];
}
It's still not very clear what you're trying to do. If you want to push a certain view controller depending on what the content of the cell is, but there is no definite arrangement of the rows, I would use the row index to access the array that is the source of your data. Some very loose code:
WhateverObject* selectedObject= (WhateverObject*)[tableDataSourceArray objectAtIndex:indexPath.row];
if( [selectedObject hasAnAttributeYouCareAbout] )
{
MyViewController* theCorrectController= whicheverViewControllerYouWant;
theCorrectController.anAttribute= aValue;
[self.navigationController pushViewController:theCorrectController animated:YES];
}
And here's how you can define your UIViewController subclass MyViewController with specific attributes. In the .h file:
#interface MyViewController : UIViewController {
int anAttribute;
}
#property int anAttribute
#end
In the .m file:
#implementation MyViewController
#synthesize anAttribute;
#end
You can have as many attributes as you want of whatever type, and then you can set them with aViewController.anAttribute as above.
Create objects - dateInfoViewController and trackInfoViewController and then...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger row = [indexPath row];
if (row==0)
{
if (self.dateInfoViewController == nil)
{
DateInfoViewController *temp = [[DateInfoViewController alloc] init];
self.dateInfoViewController = temp;
[temp release];
}
else {
dateInfoViewController.title= [ NSString stringWithFormat:#"%#", [sessionInfoDetailsArray objectAtIndex:row]];
YourAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
[delegate.sessionNavigationController pushViewController:dateInfoViewController animated:YES];
}
}
if (row==1)
{
if (self.vetInfoViewController == nil)
{
TrackInfoViewController *temp = [[TrackInfoViewController alloc] init];
self.trackInfoViewController = temp;
[temp release];
}
else {
trackInfoViewController.title= [ NSString stringWithFormat:#"%#", [sessionInfoDetailsArray objectAtIndex:row]];
YourAppDelegate *delegate = [[UIApplication sharedApplication]delegate];
[delegate.sessionNavigationController pushViewController:trackInfoViewController animated:YES];
}
}
I fear it's not perfectly clear what do you want to do... if you need to push a different view depending on the selected row you may simply do something like
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0)
//push view 1
else
//push view 2
}
UPDATE: calling indexPath.row you get the index of the selected row. I guess is up to you to decide what to do depending on what row is selected. To pass this information to the next view you may simply think of a #property field to set, a method to call or a custom init method for the view controller you are pushing. What is the problem with the code you posted?