Destination view in segue gives error in property - ios

I am trying to pass a custom object to a new view's property though it gives an error because it cannot find the "setter" for the property.
When I select a row in my table this method is called:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.actionIndexPath = indexPath;
[self performSegueWithIdentifier:SELECTED_PERSON sender:self];
}
Next:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:CREATE_EDIT_PERSON]) {
PersonDebtViewController *editPerson = [segue destinationViewController];
editPerson.editPerson = self.oweMePeople[self.actionIndexPath.row];
}
else if ([segue.identifier isEqualToString:SELECTED_PERSON]) {
EmailViewController *emailPerson = [segue destinationViewController];
emailPerson.selectedPerson = self.oweMePeople[self.actionIndexPath.row];
}
self.actionIndexPath = nil;
}
It is in the emailPerson.selectedPerson =... it goes wrong.
I have declared the property in the destinationview:
#import <UIKit/UIKit.h>
#import <MessageUI/MessageUI.h>
#import "Person.h"
#interface EmailViewController : UIViewController <MFMailComposeViewControllerDelegate>
#property (nonatomic) Person *selectedPerson;
#end
What am I missing?

You probably forgot to set your view controller to a EmailViewController in Storyboard. Your error is telling you:
[UIViewController setSelectedPerson:]
Trying to send the message setSelectedPerson: to an instance of UIViewController

Related

Unwinding from Storyboard prevents Delegate from being called

I have a UIViewController several segues deep that when the use is finished, should unwind and take them back to the DashboardViewController.
I created the unwindToDashboard method in the Dashboard and hooked a button up to the Exit in my FinishViewController. So that when its clicked will fire the unwind action.
That works fine.
But I need to pass back data to the Dashboard from the FinishViewController.
So I created a delegate ProcessDataDelegate for the FinishViewController and made the Dashboard conform to it.
However, the delegate method in the Dashboard is NOT called.
Can anyone tell me what I have done wrong?
DashboardViewController.m
#import "FinishViewController.h"
#interface DashboardViewController () <ProcessDataDelegate>{
FinishViewController *fm;
}
#end
#implementation DashboardViewController
- (void)viewDidLoad {
[super viewDidLoad];
if(!fm){
fm = [[FinishViewController alloc] init];
}
fm.delegate = self;
}
- (IBAction)unwindToDashboard:(UIStoryboardSegue *)unwindSegue {
//empty
}
#pragma mark PROTOCOL METHODS
-(void) didFinishWithResults:(NSDictionary*) dictionary{
NSLog(#"Dashboard method called didFinishWithResults");
}
#end
FinishViewController.h
#class FinishViewController;
#protocol ProcessDataDelegate <NSObject>
#required
- (void) didFinishWithResults: (NSDictionary*)dictionary;
#end
#interface FinishViewController : UIViewController
#property (nonatomic, weak) id <ProcessDataDelegate> delegate;
#end
FinishViewController.m
#interface FinishViewController ()
#end
#implementation FinishViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
[delegate didFinishWithResults:nil ];
}
#end
You need pass your delegate in prepareForSegue method of your DashboardViewController, there get the destinationViewController and cast to FinishViewController if the identifier is equal to your expected segue identifier
Something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSLog(#"fired via the button to the exit--- Segue: %#", [segue identifier]);
if([[segue identifier] isEqualToString:#"YourSegueIdentifier"])
{
((FinishViewController*)[segue destinationViewController]).delegate = self
}
}

IOS Obj-C ViewController not passing value

I know this question has been asked, but I have read the responses, adopted the fixes and still have an issue somewhere which I can't identify.
I have an IOS app which is similar in nature to email. It has an InboxVC which is a tableVC with a custom prototype cell which upon selection triggers a messageDetailVC.
The issue is that the messageDetailVC is triggered but the values are not being passed to it. I added log messages to evaluate the value in code before getting to Storyboard issues, and the variable being passed (messageID) has a NULL value.
Can someone tell me what I am missing or doing wrong? My code is:
InboxVC.m (snippet)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSLog(#"%#: Message touched...", LOG_TAG);
messageDetail *mdvc = [[messageDetail alloc] init];
mdvc.messageID = #"123456789-1";
[self.navigationController pushViewController:mdvc animated:YES];
NSLog(#"%#: messageID value is = %#",LOG_TAG,mdvc.messageID);
//messageID has valid value here
}
messageDetail.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface messageDetail : UIViewController
{
NSString *messageID;
}
#property (strong, nonatomic) NSString *messageID;
#property (strong, nonatomic) IBOutlet UITextView *body;
messageDetail.m
#import <Foundation/Foundation.h>
#import "messageDetail.h"
static NSString * LOG_TAG = #"messageDetailController";
#implementation messageDetail
#synthesize messageID;
#synthesize body;
- (void)viewDidLoad {
[super viewDidLoad];
body.text = messageID;
//debug messages
NSLog(#"%#:Added messageID as Body text", LOG_TAG);
NSLog(#"%#:Value of body.text is = %#", LOG_TAG, body.text);
NSLog(#"%#:Value of messageID is = %#", LOG_TAG, messageID);
//messageID has null value here
}
- (void) viewWillAppear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:NO];
}
MainStoryboard:
I have a messageDetail view tied to the messageDetail sub class of UIViewController. There is a segue with identifier "s_msgDetail" from the prototype cell's selection event to the messageDetailVC (show). As I said above the messageDetailVC appears, just not with the body.text being set to the value of "messageID".
You are setting the messageID on the wrong instance of your messageDetail view controller. Since you are using storyboards, the storyboard is already creating and presenting an instance of messageDetail for you. But, in tableView:didSelectRowAtIndexPath: you are creating a second one and presenting it. (I'm surprised you're not getting a bunch of runtime animation warnings when doing that.)
You should be setting messageID in prepareForSegue:sender: like this:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"s_msgDetail"]) {
messageDetail * vc = (messageDetail *) segue.destinationViewController;
NSIndexPath * indexPath = [self.tableView indexPathForSelectedRow];
vc.messageID = /* use indexPath to get data from messages collection */;
}
}
You have to use prepareForSegue to pass value to another view Controller

Delegate Method is not getting called

I am trying to pass selected cell text from CategoryViewController to DescribeViewController. But it does not call the method in the DescribeViewController method.
CategoryViewController.h
#import <UIKit/UIKit.h>
#protocol CategoryViewControllerDelegate <NSObject>
- (void)didSelectRow:(NSString *)cellDataString;
#end
#interface CategoryViewController : UIViewController<UITableViewDelegate, UITableViewDataSource>
#property (weak, nonatomic) id<CategoryViewControllerDelegate> delegate;
#end
CategoryViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [categoryTableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.textLabel.text;
[self.delegate didSelectRow:cellText];
[[self navigationController] popViewControllerAnimated:YES];
}
DescribeViewController.h
#import <UIKit/UIKit.h>
#import "CategoryViewController.h"
#interface DescribeViewController : ProductAwareBaseViewController<UITextFieldDelegate, CategoryViewControllerDelegate>
The following didSelectRow method is not getting called. I could not able to find out the root of the problem.
DescribeViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
CategoryViewController *popoverTableViewController = [[CategoryViewController alloc] init];
popoverTableViewController.delegate = self;
}
- (void)didSelectRow:(NSString *)cellDataString
{
self.cellDataString = cellDataString;
}
ProductAwareBaseViewController.h
#import UIKit;
#class Product;
#interface ProductAwareBaseViewController : UIViewController
#property (nonatomic, strong) Product *product;
#end
ProductAwareBaseViewController.m
#import "ProductAwareBaseViewController.h"
#import "Product.h"
#interface ProductAwareBaseViewController ()
#end
#implementation ProductAwareBaseViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.destinationViewController isKindOfClass:[ProductAwareBaseViewController class]]) {
ProductAwareBaseViewController *vc = (ProductAwareBaseViewController *)segue.destinationViewController;
vc.product = self.product;
}
}
#end
Try setting the delegate object in didSelectRow. And call that delegate method after that. Because delegate is weak, may be it is released from the memory.
CategoryViewController *popoverTableViewController = [[CategoryViewController alloc] init];
popoverTableViewController.delegate = self;
UITableViewCell *cell = [categoryTableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.textLabel.text;
[self.delegate didSelectRow:cellText];
[[self navigationController] popViewControllerAnimated:YES];
Most common reason for delegate method not being called is dealing with incorrect objects.
Ensure that CategoryViewController object created from
DescribeViewController is the same which you are presenting on
screen and that the delegate is being set on the same object. I truly believe you are creating a new CategoryViewController object and setting delegate on that.
In DescribeViewController, before calling delegate, check the
existence of delegate and that it implements the protocol method (if
its an optional method). This is a safety check, you can also put a NSLog statement to double check if your delegate exists or not. You are failing here.
->
if (delegate && [delegate respondsToSelector:(didSelectRow:)]) {
[self.delegate didSelectRow:cellText];
}
PS: If you are segueing from DescribeViewController to CategoryViewController then you set delegate in prepareForSegue:.
Follow these guidelines and I am sure you would be able to fix your issue!
try
#property (nonatomic, weak) id <CategoryViewControllerDelegate> delegate;
for declaring your delegate.
EDITED
try for checking the delegate is returning some value or not.
By this, whenever yo are setting the values.
if(self.delegate && [self.delegate respondsToSelector:#selector(didSelectRow:)])
{
[self.delegate didSelectRow:(NSString *) cellDataString];
}
and also if you are using the segue to transfer the data between two controllers then check there for the delegates.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
DescribeViewController *obj = (DescribeViewController *)segue.destinationViewController;
obj.delegate =self;
}
i think this will help you.

Trouble passing data between scenes when I segue

I've done tutorials where I pass data through scenes with the prepareForSegue:sender: method, but right now when I try to use the passed data, it's null. I'm using a navigation controller as well.
here's the .h -
#import <UIKit/UIKit.h>
#import "TalkChatTableViewController.h"
#interface CreateChatTableViewController : UIViewController
#end
here's the .m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"idSegueMyChatsToChat"]){
TalkChatTableViewController *tctvc = [segue destinationViewController];
tctvc.chatObjectId = #"test";
NSLog(#"%#", tctvc.chatObjectId);
//succesfully logs out test
}
}
When I log in the above method, it comes out fine. But then when I go to my TalkChatTableViewController class it doesn't log out in viewDidLoad; it's null.
The header to that looks like this:
#import <UIKit/UIKit.h>
#interface TalkChatTableViewController : UITableViewController
#property (nonatomic) NSString * chatObjectId;
#end
and then finally the .m -
#import "TalkChatTableViewController.h"
#implementation TalkChatTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#", self.chatObjectId);
// logs null
}
#end
TalkChatTableViewController * tctvc = (TalkChatTableViewController *)[segue destinationViewController];
This is what winded up working.

The value get by delegate method is been clear?

In tableViewControllerA.h I declare a delegate ,and in tableViewControllerA.m I implement the method when click a cell of the tableView, A will pass the value to B, and execute the perfromSegueWithIdentifier to jump to tableViewControllB,in tableViewControllB.m the getting method is called, and I get the value, but after the viewDidLoad() method call, the value become nil. Please help me to solve the problem.By the way , the property of the value is strong,nonatomic.
DTZHomeTableViewController.h
#import <UIKit/UIKit.h>
#import "PassData.h"
#protocol PassDataDelegate
-(void)passData:(PassData*) dataToProgram;
#end
#interface DTZHomeTableViewController :
UITableViewController<UITableViewDelegate,UITableViewDataSource>
#property(assign,nonatomic) id<PassDataDelegate> dataDelegate;
#end
PassData is an user-defined class
DTZHomeTableViewController.m
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ProgramTableViewController *programViewController=
[[ProgramTableViewController alloc]init];
self.dataDelegate=programViewController;;
PassData *jump=[[PassData alloc]init];
jump.livingStatus=YES;
jump.role=0;
jump.index=indexPath.row;
jump.curOnlineNum=305605;
[self.dataDelegate passData:jump];
[self performSegueWithIdentifier:#"showSelectedProgram" sender:self];
}
ProgramTableViewController.h
#import <UIKit/UIKit.h>
#import "DTZHomeTableViewController.h"
#interface ProgramTableViewController :
UITableViewController<PassDataDelegate,UITableViewDataSource,UITableViewDelegate>
#property(strong,nonatomic) PassData * dataFromHome;
#end
ProgramTableViewController.m
#implementation ProgramTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"view did load%#",self.dataFromHome); // log :null
}
- (void) passData:(PassData *)dataToProgram
{
self.dataFromHome=dataToProgram;
}
#end
Delegation isn't the proper way to pass data to a segued view controller. Instead, you want to pass the data in prepareForSegue:sender:
Remove the protocol and delegate.
Add properties to your ProgramTableViewController for the data you want to pass.
#property (nonatomic, assign) BOOL livingStatus;
#property (nonatomic, assign) NSInteger role;
#property (nonatomic, assign) NSInteger row;
#property (nonatomic, assign) NSInteger curOnlineNum;
In prepareForSegue:sender:, set the ProgramTableViewController's passed properties to the values associated with the selected row:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)__unused sender
{
if ([[segue identifier] isEqualToString:#"showDetail"])
{
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
ProgramTableViewController *controller = (ProgramTableViewController *)[segue destinationViewController];
controller.livingStatus = YES;
controller.role = 0;
controller.row = indexPath.row;
controller.curOnlineNum = 305605;
}
}
You shouldn't allocate and init ProgramTableViewController in tableView:didSelectRowAtIndexPath:. Your segue will instantiate the destination view controller for you.
You don't even need to have a tableView:didSelectRowAtIndexPath: method. You can create a push segue from the tableViewCell to ProgramTableViewController, right within Storyboard. Give the segue an identifier (such as "showDetail"). Then in prepareForSegue, you assign the values, as I explained.
When you tap on that row, the segue will create a ProgramTableViewController, set the parameters, and present it for you.

Resources