Delegate not working properly - iphone

I am trying to pass some information between a subview and a parentview on the navigation stack using delegates.
However for some reason when the I execute the delegate from the subview then pop the subview from the navigational controller it never enters the delegate method that is set up in the parent view.. I have tried NSLogs & Breakpoints the thread is defiantly not making it to this delegate method in the main view so I was hoping you could help me out.
First Of all I will show you how I have set up my delegate, where I call it in my subview and then where I set it up in the mainview hopefully you guys will be able to see something I have not so far.
Subview.h // I have left out things not related to the delegate
#import <UIKit/UIKit.h>
//Delegate - Protocol stuff for passing data from this view to the parent view
#protocol PassSearchData <NSObject>
#required
- (void) setManufactureSearchFields:(NSArray *)arrayValues withIndexPath:(NSIndexPath *)myIndexPath;
#end
#interface SecondViewController : UITableViewController <UITableViewDataSource> {
//Delegate (Used to pass information back to parent view)
id <PassSearchData> delegate;
}
//Delegate (Used to pass information back to parent view)
#property (strong) id delegate;
#end
SecondView.m
#import "SecondViewController.h"
#import "FirstViewController.h"
#implementation SecondViewController
//..
//Delegate (Used to pass information back to parent view)
#synthesize delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Access selected cells content (cell.textLabel.text)
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//Parent view logic (sends info back to the correct cell in parent view)
if (parentViewSelectedIndexPath.section == 0)
{
if (parentViewSelectedIndexPath.row == 0)
{
//Predicates restrict the values that will be returned from the query
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#",#"MANUFACTURER",cell.textLabel.text];
filterArray = [parsedDataArrayOfDictionaries filteredArrayUsingPredicate:predicate];
[[self delegate]setManufactureSearchFields:filterArray withIndexPath:indexPath];
// NSLog(#"Filtered Array = %#", filterArray);
}
}
[self.navigationController popViewControllerAnimated:YES]; //pops current view from the navigatoin stack
}//...
Then this is how I set it up inside the FirstViewController
FirstViewController.h
#import <UIKit/UIKit.h>
#import "VehicleResultViewController.h" //With this included I can now use the PassSearchData delegates of this view for passing data
#interface VehicleSearchViewController : UITableViewController <PassSearchData> {
//..
FirstViewController.m
#import "VehicleSearchViewController.h"
#import "VehicleResultViewController.h" //Subview
//..
#pragma mark - Received data from Sub view delegates
//These are the delegate method for passing data from the child to the parent view (parent being this view, with the delegate being declared in the subview)
- (void) setManufactureSearchFields:(NSArray *)arrayValues withIndexPath:(NSIndexPath *)myIndexPath
{
manufactureSearchObjectString = [[arrayValues valueForKey:#"MANUFACTURER"] objectAtIndex:0];
manufactureIdString = [[arrayValues valueForKey:#"MANUFACTURERID"] objectAtIndex:0]; //Restricts Models dataset
manufactureResultIndexPath = myIndexPath;
}
If anyone knows what I'm missing/doing wrong any help would be really really heapful
any questions let me know.
Solution
In the firstviewcontroller when I go to load the secondviewcontroller inside
tableView:didSelectRowAtIndexPath: I forgot to set the secondviewcontrollers delegate before I pushed the view to the navigational stack.. so the missing code was this.
FirstView.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Get the subview ready for use
VehicleResultViewController *vehicleResultViewController = [[VehicleResultViewController alloc] initWithNibName:#"VehicleResultViewController" bundle:nil];
//Pass the selected object to the new view controller.
[self.navigationController pushViewController:vehicleResultViewController animated:YES];
[vehicleResultViewController setDelegate:self];
//etc
thanks guys.

Ok, first, your delegate should be a weak reference to avoid retain cycles. But I suspect maybe the delegate isn't getting set. Can you show the code where SecondViewController is instantiated and the delegate is set? Can you set a breakpoint at the delegate call and verify that it is not nil?

I think you are not setting Delegate.
After Creation Instanace(object)of SecondViewController ,you have to set Delegate.
ie
SecondViewController *secondObj=[[SecondViewController alloc]initWithNibName:#"SecondViewController"> bundle:nil];
[secondObj setDelegate:self];

Related

Delegate method in the set delegate object not responding

I have a somewhat similar concern with this question a custom delegate method inside didSelectRowAtIndexPath.
However, in my case before getting to the delegate object which is a UIViewController named BarCodeViewController, I should first pass by 2 view controllers from the initial view controller which is the CardViewController which is a table view controller. I'm setting the delegate object for my custom delegate through this:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
CardDetailsViewController *details = [self.storyboard instantiateViewControllerWithIdentifier:#"cardDetails"];
Card *selectedCard = [self.myWallet objectAtIndex:indexPath.row]; // I want this selected card to be accessible until the user clicks another card or during end of program.
[self.navigationController pushViewController:details animated:YES];
[self.delegate cardWalletViewController:self withCurrentCard:selectedCard];
[self setDelegate:self.barCodeVC]; // barCodeVC is declared in CardWalletViewController.h as #property (nonatomic, strong) BarCodeViewController *barCodeVC;
if (self.delegate) {
NSLog(#"delegate is not nil");
}
}
and this is how I instantiate the view controller which I set as the delegate object
- (void)viewDidLoad
{
[self setBarCodeVC:[self.storyboard instantiateViewControllerWithIdentifier:#"myBarcodeVC"]];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
And in my delegate object, which is the BarCodeViewController I implement the delegate method
#import "CardWalletViewController.h"
#interface BarCodeViewController () <CardWalletDelegate>
#end
#implementation
- (void)cardWalletViewController:(CardWalletViewController *)sender withCurrentCard:(Card *)currentCard
{
Card *myCurrentCard = currentCard;
NSLog(#"This is my current card: %#", myCurrentCard);
}
#end
I think I am able to set my delegate object, but then the delegate method is not being implemented for I don't see in the console the NSLog(#"this is my current......"); when I reach the BarCodeViewController.
Advice please.
That's not a standard use for delegate and it's hard to tell what you really want to happen. but, it looks like your code...
[self.delegate cardWalletViewController:self withCurrentCard:selectedCard];
[self setDelegate:self.barCodeVC];
Is making the call on whatever the "old" delegate is (before setting it to barCodeVC). Are you really trying to make the call on the "new" delegate? Should it be...
[self setDelegate:self.barCodeVC];
[self.delegate cardWalletViewController:self withCurrentCard:selectedCard];
EDIT
What I am saying is that you are sending a message to the delegate in this line...
[self.delegate cardWalletViewController:self withCurrentCard:selectedCard];
and THEN you are setting the delegate to barCodeVC
[self setDelegate:self.barCodeVC];
So, the message is actually being sent to whatever the delegate was set to before it was set to barCodeVC (another view controller, or nil, or...). Maybe that's what you want to happen, but it looks suspicious.

Objective C access variables from other classes?

I'm trying to get a variable from a class that I made from a table view. Basically what I want this to do is tell the other controller what row was selected so this is what I tried to do.
Table View Class .h file:
#property(nonatomic) NSInteger itemId;
-(NSInteger)itemId;
I would then make methods that set and get the variable in the .m file of the Table View Class
(I synthesized it and did all that stuff, I'm just showing you the methods)
-(NSInteger)itemId {
return self.itemId;
}
And now the table cell selected method...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)
indexPath {
NSUInteger row = [indexPath row];
self.itemId = row;
//segue stuff (if you want me to include this just let me know)
}
Thats all for that class and now the class that I need the value for
View Controller Class .h that is being pushed via segue
#property (nonatomic) NSInteger itemId;
View Controller Class .m
#import "TableViewController.h"
//Skip a few things
#synthesize itemId;
//skip a few things
-(void)viewDidLoad {
TableViewController *tvc = [[TableViewController alloc] init];
itemId = [tvc itemId];
NSLog(#"%i", itemId);
For some reason this doesn't work... When I print out the "itemId" in the "didselectrow" method it returns the right number but when I try to print it out in the other class it just gives me '0'
Any thoughts?
If there are things that I left out that you want to see in my code I'd be more than happy to write it out :) I just wanted to save time and space by cutting down the code a little.
Thanks in advance!
EDIT:
I did find a possible solution but it involves using the delegate. I'm sure there's got to be a better way of doing this so if you have any ideas, just let me know.
TableViewController *tvc = [[TableViewController alloc] init];
Doing this in a different class you create&initialize a new object, so it will be nill(for int 0). For sharing data between classes&view controllers use Delegates and properties.
With a little code i shall explain;
#import <UIKit/UIKit.h>
//YourClassNameAppDelegate.m
#interface YourClassName : UIResponder <UIApplicationDelegate>
{
NSString *uName;
NSDictionary *YourDictionary;
}
#property (copy, readwrite) NSString *uName;
#property (copy, readwrite) NSString *YourDictionary;
And in the other class you want to use this string and dictionary,
//import your delegate class
#import "YourClassNameAppDelegate"
.
.
.
//to me, do this in viewDidLoad(or something like that) method of new view controller
YourClassNameAppDelegate *sharedData= (YourClassNameAppDelegate *)([[UIApplication sharedApplication]delegate]);
.
.
-(IBAction)sharedData{
NSLog(#"Shared String: %#\n And Shared Dictionary: %#, sharedData.uName, sharedData.YourDictionary);
}
The - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *) is not invoked - you have to select a row to change the value of itemId, and that is not possible between the initialization of the table and the itemId = [tvc itemId]; line.
this code may helps you.
#import <UIKit/UIKit.h>
extern int outsider;
#interface ViewController : UIViewController {
}
#property int outsider;
#end
to all the .m files you #import the .h file where you declared the variable in can acces it.
You are creating a new instance of your table view controller within your detail view controller, this is incorrect and is not going to give you a reference to your original table.
Simply create a property on your pushed view controller which holds whatever detail information you want to pass. Then set this in prepareForSegue: in your table view controller, where segue.destinationViewController will give you a pointer to the VC that is about to appear.
Also, fix your accessor method as suggested by Yuji in comments.
I suggest saving the indexPath for the pressed row in a singleton. Here is a guide on how to use the singleton class to store objects and use them across classes.
In this example you can also just declare an instance variable in the singleton and set it when the row is pressed in the appropriate delegate method for your UITableView. This could be done like so:
#import <Foundation/Foundation.h>
#interface Singleton : NSObject {
NSIndexPath *tableViewPath;
}
#import "DataContainerSingleton.h"
#implementation DataContainerSingleton
#synthesize tableViewPath;
static DataContainerSingleton* _theDataContainerSingleton = nil;
+ (DataContainerSingleton*) theDataContainerSingleton;
{
if (!_theDataContainerSingleton)
_theDataContainerSingleton = [[DataContainerSingleton alloc] init];
return _theDataContainerSingleton;
}
- (id)init
{
self = [super init];
if (self) {
tableViewPath = [NSIndexPath indexPathForRow:0 inSection:0];
}
return self;
}
In your view controller with the UITableView just do like this:
#implementation
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
tableViewPath = indexPath;
}
You should adjust your initialization to what would be appropriate for your specific program!
Try this:
#property NSInteger itemId;
Hope this helps you

Delegate method not being accessed

I am passing some information from one view to the other using delegates, However when I select a tableview cell I am passing the data to the delegate that will pas the information back to a view on the stack.. it makes it back to that view but doesn't actually go into the delegate method when the views change...
Here is where I set up my delegate.
subViewController.h
#import <UIKit/UIKit.h>
#protocol PassSubSearchData <NSObject>
#required
- (void) setModSearchFields:(NSArray *)modArray modIndexPath:(NSIndexPath *)modIndexPath setSubMod:(NSArray *)subModArray subModIndexPath:(NSIndexPath *)subModIndexPath;
#end
//...
//Delegate for passing Model and SubModel data back to VehicleSearchViewController
id <PassSubSearchData> delegate;
//...
//Delegate for passing Model and SubModel data back to VehicleSearchViewController
#property (strong) id delegate;
//This is how I use it
subViewController.m
#import "MainViewController.h"
#import "SubViewController.h"
#implementation VehicleSubResultViewController
//...
//Delegate for passing Model and SubModel data back to VehicleSearchViewController
#synthesize delegate;
//...
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Access selected cells content (cell.textLabel.text)
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//Predicates restrict the values that will be returned from the query
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#",#"SUB",cell.textLabel.text];
filterArray = [parsedDataArrayOfDictionaries filteredArrayUsingPredicate:predicate];
[[self delegate] setModSearchFields:tempModArray modIndexPath:tempModIndexPath setSubMod:filterArray subModIndexPath:indexPath];
//This pops to the VehicleSearchViewController view
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
}
Then in the main view
MainViewController.h
#import "SubViewController.h"
#interface VehicleSearchViewController : UITableViewController <PassSubSearchData> {
//...
MainViewController.m // However this part of the code is never accessed
- (void) setModSearchFields:(NSArray *)modArray modIndexPath:(NSIndexPath *)modIndexPath setSubMod:(NSArray *)subModArray subModIndexPath:(NSIndexPath *)subModIndexPath
{
modObjectString = [[modArray valueForKey:#"MOD"] objectAtIndex:0];
modIndexPath = modIndexPath; // Sets the selected IndexPath from the subview
subModObjectString = [[modelArray valueForKey:#"SUBMODEL"] objectAtIndex:0];
subModIndexPath = subModResultIndexPath; // Sets the selected IndexPath from the subview
NSLog(#"%#", modObjectString);
NSLog(#"%#", modIndexPath);
NSLog(#"%#", subModObjectString);
NSLog(#"%#", subModIndexPath);
[self.tableView reloadData];
}
So thats it, I'm just not sure what I'm missing if anyone knows any help would be appreciated.
Most likely the delegate never got set, so it is nil and nothing happens.

How to call a method of another Class?

EDIT2: I try to summarize my problem and the solutions:
I've got a TableViewController named DetailedViewController. My intention was to activate TouchesBegan to recognize actions like sliding etc, and normally, the method touchesbegan is replaced with the DidSelectRow method. In many posts on stackoverflow, subclassing the UITableView is the only possibility to realize this.
So i created a SpecificTable with .xib file and i used this as a subclass of UITableViewController by adding the SpecificTable as the nib-file.
Selecting a row works fine, and also the TouchesBegan method (i called a method IN the SpecificTable.m with an Alert.) But now i want to call a Method in the UITableViewController (DetailedViewController) where moveToNextItem is declared like
-(void)moveToNextItem:(id)sender
{
[self.navigationController
pushViewController:bbarChart animated:YES];
}
But by calling this method with [self moveToNextItem] the App crashes by touching. (in the Debugger-Mode, the App crashes in the line of [self moveToNextItem].
What is the right way to call the method of DetailedViewController.m?
Update: You should probably subclass UITableViewCell rather than UITableView. Then in your table view controller's cellForRowAtIndexPath: method, return an instance of this subclass rather than an instance of UITableViewCell.
You will also need to pass a DetailedViewController pointer on to the cell, so that you can invoke its moveToNextItem method in the touchesBegan, etc. methods.
Adapt this example to your needs:
MyTableViewCell.h
#class DetailedViewController;
#interface MyTableViewCell : UITableViewCell {
DetailedViewController *dvc;
}
#property (nonatomic, retain) DetailedViewController *dvc;
#end
MyTableViewCell.m
#import "MyTableViewCell.h"
#import "DetailedViewController.h"
#implementation MyTableViewCell
#synthesize dvc;
- (void)someMethod { // This would be your touchesBegan, etc. methods
[dvc moveToNextItem];
}
- (void)dealloc {
[dvc release]; // We retained dvc so we have to release it when we're done with it
[super dealloc];
}
#end
DetailedViewController.h
#interface DetailedViewController : UITableViewController {
// iVars here
}
// Methods and properties here
- (void)moveToNextItem;
#end
DetailedViewController.m
#import "DetailedViewController.h"
#import "MyTableViewCell.h"
#implementation DetailedViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyTableViewCell"];
if(cell == nil) {
cell = [[[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyTableViewCell"] autorelease];
cell.dvc = self; // This gives the cell a reference to the detailed view controller
}
return cell;
}
- (void)moveToNextItem {
// ...
}
#end
There are probably far better ways to achieve what you want, but this is the best I can do without more information.
Declare the method in DetailedViewController.h, and #import that file in SpecificTable.h.
if SpecificTable is really a subclass of DetailedViewController you can call
[self moveToNextItem];
as already mentioned.
but i think you mean a subview or not? so SpecificTable.view is a subview ob DetailedViewController.view
you have several options then. for example using NSNotificationCenter.
or what is probably also a good way for you is to setup an instance variable of DetailedViewController in your SpecificTable and assign it when you init your SpecificTable.
as an example:
// the parent view .m
testTVC *tableview = [[testTVC alloc] initsomething];
tableview.parentVC = self;
[self.view addSubView:tableview.view];
[tableview release];
now in your testTVC
// the .h
#interface testTVC : UITableViewController {
testVC *parentVC;
}
#property(nonatomic,retain) testVC *parentVC;
#end
// the .m
[parentVC moveToNextItem];
you also have to synthesize and release your parentVC.
Is [NSNotificationCenter defaultCenter] something you are looking for?

How to push UIViewController into UINavigationController from seperate UIView of different UIViewController which uses this view

I have a UIViewController (AbcViewController) with NavigationController. AbcViewController uses UIView (AbcView) as its view. AbcView has a UITableView. I have set this TableView's datasource in AbcViewController and delegate in its SuperView i.e. AbcView. How will I push another UIViewController (XyzViewcontroller) into navigationController when I select a row in this table because it gives
"error: request for member 'navigationController' in something not a structure or union"
when I do this:
[self.navigationController pushViewController:xyzViewcontroller animated:TRUE];
I also did this:
AbcViewController *parentVC;
[parentVC.navigationController pushViewController:xyzViewcontroller animated:TRUE];
Though it builds successfully, XyzViewcontroller's view does not appear. It does not push XyzViewcontroller's view onto navigationController.
We can make a delegate on AbcView so that we can refer back to the view's viewController which in this case is AbcViewController. We can set delegate as:
#interface AbcView : UIView
{
id delegate;
}
#property(nonatomic, assign) id delegate;
Then in AbcViewController, set the view's delegate like this:
[abcView setDelegate:self];
Now in table method using our delegate from within AbcView as:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[delegate pushOtherView];
}
it will call - (void)pushOtherView method in AbcViewController whose definition is:
- (void)pushOtherView
{
XyzViewcontroller * xyzViewcontroller = [[[XyzViewcontroller alloc] init] autorelease];
[self.navigationController pushViewController:xyzViewcontroller animated:YES];
}
But before using this method, it should be mentioned in protocols otherwise it will show
Warniing:
-pushOtherView' not found in protocol(s).