My app have core data and two views CoursesTableViewController and DetailViewController.
If the user tap on Detail Disclosure button segue to DetailViewController to show some details.
The app uses didSelectRowAtIndexPath and didDeselectRowAtIndexPath for other things.
CoursesTableViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
[[segue destinationViewController] setDetailItem:object];
}
}
DetailViewController.h
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UITextField *courseCodeLabel;
#property (weak, nonatomic) IBOutlet UITextField *courseNameLabel;
DetailViewController.m
#interface DetailViewController ()
- (void)configureView;
#end
#implementation DetailViewController
#synthesize detailItem = _detailItem;
#synthesize courseCodeLabel = _courseCodeLabel;
#synthesize courseNameLabel = _courseNameLabel;
#pragma mark - Managing the detail item
- (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.courseCodeLabel.text = [[self.detailItem valueForKey:#"courseCode"] description];
self.courseNameLabel.text = [[self.detailItem valueForKey:#"courseName"] description];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
self.courseCodeLabel = nil;
self.courseNameLabel = nil;
}
The problem is when I tap on Detail Disclosure the segue works good but in the DetailViewController there are no value in the courseCodeLabel and courseNameLabel.
Import & try casting the destination view controller.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
NSManagedObject *object = [[self fetchedResultsController] objectAtIndexPath:indexPath];
DetailViewController * detailVC = (DetailViewController *)[segue destinationViewController];
[detailVC setDetailItem:object];
}
}
Related
I want to pass a NSInteger from a tableViewController (HistoryTableViewController) to another viewController (InformationViewController) but apparently it is not responding to my selector.
HistoryTableViewController.h:
#class HistoryTableViewController;
#protocol HistoryTableViewControllerDelegate <NSObject>
- (void)addItemViewController:(HistoryTableViewController *)controller passItem:(NSInteger *)rowNum;
#end
#interface HistoryTableViewController : UITableViewController {
NSInteger row;
}
#property (nonatomic, weak) id <HistoryTableViewControllerDelegate> delegate;
#end
HistoryTableViewController.h
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
row = [self.tableView indexPathForSelectedRow].row;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"informationSegue"]) {
if([self.delegate respondsToSelector:#selector(addItemViewController:passItem:)]){
[self.delegate addItemViewController:self passItem:&(row)];
}
}
}
InformationViewController.h:
#interface InformationViewController : UIViewController <HistoryTableViewControllerDelegate>
#property (nonatomic, assign) NSInteger rowIn;
InformationViewController.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"informationSegue"]) {
HistoryTableViewController *historyvc = segue.destinationViewController;
historyvc.delegate = self;
}
}
- (void) addItemViewController:(HistoryTableViewController *)controller passItem:(NSInteger *)rowNum {
rowIn = *rowNum;
}
"informationSegue" is my segueIdentifier to go from HistoryTableViewController to InformationViewController.
I actually found out the answer myself. I was using the code for passing the delegate back to another view controller, but I was supposed to pass the delegate forward between view controllers
i'm trying to perform something pretty simple which is:
I have a home page view controller and a table view controller (separate controllers) which supports deleting cells.
In the home page I have a UILabel object which I want to populate with the first cell in the table view controller. So I figured what I need is to create an instance of my table view controller in my home page view controller and ask this information...but from some reason the object i'm getting from the table view controller called "currentTarget" is nil...(and it's not).
This is my HomeViewController: (just the relevant lines)
#import "StackTableViewController.h"
#interface HomeViewController ()
#property (strong, nonatomic) IBOutlet UILabel *homeLabel;
#end
#implementation HomeViewController
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
// Do something
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[self.navigationController setNavigationBarHidden:YES];
self.homeLabel.font = [UIFont fontWithName:#"Candara-Bold" size:40];
StackTableViewController *svc = [[StackTableViewController alloc] init];
self.homeLabel.text = svc.currentTarget;
}
This is my StackTableViewController.m: (just the relevant lines)
#import "StackTableViewController.h"
#import "Target.h"
#import "StackTableViewCell.h"
#import "HomeViewController.h"
#import "CoreDataStack.h"
#interface StackTableViewController () <NSFetchedResultsControllerDelegate>
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultController;
#end
#implementation StackTableViewController
- (id)init {
self = [super initWithNibName:#"StackTableViewController" bundle:nil];
if (self) {
// Do something
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
And also added this code in the prepare for segue method so the currentTarget will get updated coming back from segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
}
why my label won't show up :/?
tnx ahead
The problem is that your init method does not initialise either the fetched results controller or the currentTarget property. They are only initialised When you present that table view controller and the viewDidLoad method runs. If you move (or copy) these lines to your init method, it should work:
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body;
In your StackTableViewController.m:
- (id)init {
self = [super initWithNibName:#"HomeViewController" bundle:nil];
if (self) {
[self.fetchedResultController performFetch:nil];
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0];
Target *current = [self.fetchedResultController objectAtIndexPath:indexPath];
self.currentTarget = current.body; }
return self;
}
I have a simple notes app where I have just 2 view controllers:
table view controller - to list all the notes.
view controller - to create new notes.
In the table view controller I have a segue from a cell back to the creation page where a user can edit the note in this specific cell.
But my problem is that when I'm preforming editing to a certain cell(note) I'm creating a new note with the content of what I edited...
So instead of passing the note content in the prepareForSegue method I need to pass the note object...
How can I do that?
this are my classes:
NMNote: (correctly just containing a property of *content, will add more behaviour later)
#import <Foundation/Foundation.h>
#interface NMNote : NSObject
#property (strong, nonatomic) NSString *content;
#end
NMCreateNotesViewController.h:
#import <UIKit/UIKit.h>
#import "NMNote.h"
#interface NMCreateNotesViewController : UIViewController
#property (strong, nonatomic) NMNote *note;
#property (weak, nonatomic) IBOutlet UITextView *textField;
#property (strong, nonatomic) NSString *passedInString;
#end
NMCreateNotesViewController.m:
#import "NMCreateNotesViewController.h"
#import "NMNotesListViewController.h"
#interface NMCreateNotesViewController () <UITextViewDelegate>
#property (weak, nonatomic) IBOutlet UIBarButtonItem *saveButton;
#end
#implementation NMCreateNotesViewController
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// listen for keyboard hide/show notifications so we can properly adjust the table's height
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
#pragma mark - Notifications
- (void)adjustViewForKeyboardReveal:(BOOL)showKeyboard notificationInfo:(NSDictionary *)notificationInfo
{
// the keyboard is showing so ƒ the table's height
CGRect keyboardRect = [[notificationInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[notificationInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = self.textField.frame;
// the keyboard rect's width and height are reversed in landscape
NSInteger adjustDelta = UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? CGRectGetHeight(keyboardRect) : CGRectGetWidth(keyboardRect);
if (showKeyboard)
frame.size.height -= adjustDelta;
else
frame.size.height += adjustDelta;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
self.textField.frame = frame;
[UIView commitAnimations];
}
- (void)keyboardWillShow:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:YES notificationInfo:[aNotification userInfo]];
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
[self adjustViewForKeyboardReveal:NO notificationInfo:[aNotification userInfo]];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton) return;
if (self.textField.text.length > 0) {
self.note = [[NMNote alloc] init];
self.note.content = self.textField.text;
}
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.passedInString != nil) {
self.textField.text = self.passedInString;
}
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
NMNotesListViewController.h:
#import <UIKit/UIKit.h>
#interface NMNotesListViewController : UITableViewController
- (IBAction) unwindToList: (UIStoryboardSegue *) segue;
#end
NMNotesListViewController.m:
#import "NMNotesListViewController.h"
#import "NMCreateNotesViewController.h"
#interface NMNotesListViewController ()
#property (strong, nonatomic) NSMutableArray *notes;
#end
#implementation NMNotesListViewController
- (IBAction) unwindToList: (UIStoryboardSegue *) segue
{
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (note != nil) {
[self.notes addObject:note];
[self.tableView reloadData];
}
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.notes = [[NSMutableArray alloc] init];
// 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;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.notes count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"NotesPrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NMNote *note = [self.notes objectAtIndex:indexPath.row];
cell.textLabel.text = note.content;
return cell;
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(UITableViewCell *)sender
{
if ([[segue identifier] isEqualToString:#"noteSegue"]) {
NMCreateNotesViewController *destination = [segue destinationViewController];
NSInteger indx = [self.tableView indexPathForCell:sender].row;
NMNote *note = self.notes[indx];
destination.passedInString = note.content;
}
}
//#pragma mark - delegate
//
//- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
//{
//
//}
#end
This is the screens flow:
the initiate view is this table view:
Now there is the TextView where you write the note:
Now, after you save a note, you go back to the first screen. and then you can tap on a populated cell and you will segue back to this screen (the one with the TextView) so you can edit it. But instead of editing it, it will create a new one with the edited content. like this:
Please, would appreciate any help here to accomplish my task..
Thanks!
The thing you need to do when you pass the note to the NMCreateNotesViewController, is to differentiate between an edit and an add action so when you came back to the table view, you can either replace the old entry with the new edited one, or add a new entry.
The way I would approach this is to have two segues, one from the + button (I'll call it "addSegue") and one from the table view cell (call it "editSegue"). I would also create a property in the list controller to hold the value of the edited row, or set it to something like -1 to indicate it's a new note. Something like this,
#property (nonatomic) NSInteger editedRow;
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"editSegue"]) {
NMCreateNotesViewController *destination = [segue destinationViewController];
NSInteger indx = [self.tableView indexPathForCell:(UITableViewCell *)sender].row;
self.editedRow = index;
NMNote *note = self.notes[indx];
destination.note = note;
}else if ([segue.identifier isEqualToString:#"addSegue"]) {
self.editedRow = -1;
}
The prepareForSegue method in the NMCreateNotesViewController would be the same as you have in your question. You can get rid of the passedInString property since we're passing in the entire note object instead. In the unwind method in the list controller, you would do this,
- (IBAction) unwindToList: (UIStoryboardSegue *) segue {
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (note != nil && self.editedRow == -1) {
[self.notes addObject:note];
}else{
[self.notes replaceObjectAtIndex:self.editedRow withObject:note];
}
[self.tableView reloadData];
}
in NMCreateNotesViewController.h:
#property (strong, nonatomic) NMNote *note;
#property BOOL adding;
#property (strong,nonatomic) NSString *originalContent;
Then in your NMNotesListViewController.m prepareForSegue
destination.note=self.notes[indx];
destination.adding=NO; // set adding to yes if you are adding a new note
and in your unwind
- (IBAction) unwindToList: (UIStoryboardSegue *) segue
{
NMCreateNotesViewController *source = [segue sourceViewController];
NMNote *note = source.note;
if (source.adding && note != nil) {
[self.notes addObject:note];
[self.tableView reloadData];
}
}
in NMCreateNotesViewController.m
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// listen for keyboard hide/show notifications so we can properly adjust the table's height
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
if (self.note != nil)
{
self.originalContent=self.note.content;
self.textField.text=self.note.content;
}
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if (sender != self.saveButton)
{
if (self.note != nil)
{
self.note.content=self.originalContent;
}
}
else
{
if (self.note == nil)
{
if (self.textField.text.length > 0) {
self.note = [[NMNote alloc] init];
}
self.note.content = self.textField.text;
}
}
I have a table view controller segueing (with identifier feedToPollQuerySeg) to another view controller.
I am trying to print out the index number of the row selected in a label in the latter.
Feed View:
#interface FeedController3 : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) IBOutlet UITableView* feedTableView;
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(NSString*)stringNum{
if([segue.identifier isEqualToString:#"feedToPollQuerySeg"]){
PollQueryController *pqc = [[PollQueryController alloc] init];
pqc = [segue destinationViewController];
NSLog(#"This is row sending: %#", stringNum);
pqc.parentRowSelected.text = stringNum;
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger rowSelected = indexPath.row;
NSString *stringNum = [NSString stringWithFormat:#"%d", rowSelected];
NSLog(#"This is row selected: %#", stringNum);
[self performSegueWithIdentifier: #"feedToPollQuerySeg" sender: stringNum];
}
PollQuery View
#interface PollQueryController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (weak, nonatomic) IBOutlet UILabel *parentRowSelected;
#implementation PollQueryController
#synthesize parentRowSelected;
-(void)viewDidLoad{
[super viewDidLoad];
NSLog(#"Parent Row Selected: %#", parentRowString);
...
}
But the label isn't updating...?
This is row selected: 1
This is row sending: 1
Parent Row Selected:
Its because when you are in prepareForSegue of FeedController3, PollQueryController's view isn't initialized.
Add NSString in PollQueryController set NSString value in prepareForSegue.
In viewWillAppear of PollQueryController assign text to parentRowSelected label.
Like This -
In the viewController that will present the another viewController:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqual:#"feedToPollQuerySeg"])
{
PollQueryController *pvc = [segue destinationViewController];
pvc.myString = stringNum;
}
}
And inside the presented viewController:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.parentRowSelected.text = self.myString;
}
Here is a neater way to achieve what you want:
FeedController3.m:
#interface FeedController3
#property (nonatomic) int rowSelected;
#end
#implementation
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.rowSelected = indexPath.row;
NSLog(#"This is row selected: %#", [NSString stringWithFormat:#"%d", self.rowSelected]);
[self performSegueWithIdentifier:#"feedToPollQuerySeg" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"feedToPollQuerySeg"])
{
// Get reference to the destination view controller
PollQueryController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
vc.rowSelected = self.rowSelected;
}
}
#end
PollQueryController.h:
#interface PollQueryController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic) int rowSelected;
#property (weak, nonatomic) IBOutlet UILabel *parentRowSelected;
#end
PollQueryController.m:
#implementation
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.parentRowSelected.text = [NSString stringWithFormat:#"%d", self.rowSelected];
}
#end
I have programmatically created a custom cell of a dynamic table by integrating a segmentedcontrol of 8 segments.
It works well but once I tap on one of the segments, I would like that a popup menu with options appears near the cell and not at the lower end of the tableview.
I suppose that this occurrs because I have anchored the segue to the tableview. I would like to avoid to assign to each segment a segue to the popup menu.
Is there any possibility of re-positioning the popup menu automatically depending on the segment selected?
Here is the relevant code at the main view controller .m file
-(void)segmentSelectedAtRow: (UISegmentedControl *)sender{
if (self.flipsidePopoverController) {
[self.flipsidePopoverController dismissPopoverAnimated:YES];
self.flipsidePopoverController = nil;
} else {
[self performSegueWithIdentifier:#"segueToChangeValues" sender:sender];
}
UITableViewCell *theParentCell = [[sender superview]superview];
NSIndexPath *indexPathOfSegment = [self.spreadSheetView indexPathForCell:theParentCell];
...
}
...
- (void)flipsideViewControllerDidFinish:(POTFlipsideViewController *)controller {
[self.flipsidePopoverController dismissPopoverAnimated:YES];
self.flipsidePopoverController = nil;
}
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
self.flipsidePopoverController = nil;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"segueToChangeValues"]) {
[[segue destinationViewController] setDelegate:self];
UIPopoverController *popoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
self.flipsidePopoverController = popoverController;
popoverController.delegate = self;
}
}
#end
here is the flipside .h file
#class POTFlipsideViewController;
#protocol POTFlipsideViewControllerDelegate
- (void)flipsideViewControllerDidFinish:(POTFlipsideViewController *)controller;
#end
#interface POTFlipsideViewController : UIViewController
#property (weak, nonatomic) id <POTFlipsideViewControllerDelegate> delegate;
- (IBAction)done:(id)sender;
....
#end
here is the relevant code for the flipside .m file
#import "POTFlipsideViewController.h"
#interface POTFlipsideViewController ()
#end
#implementation POTFlipsideViewController
- (void)awakeFromNib
{
self.contentSizeForViewInPopover = CGSizeMake(320.0, 480.0);
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
return YES;
}
- (IBAction)done:(id)sender
{
[self.delegate flipsideViewControllerDidFinish:self];
}
#end