Obj-C Delegate inside Delegate - ios

I have subclassed a view that I am using as header view it has some buttons delegate inside it and it works perfect .
However I am presenting a modalViewController above my viewController .
(in my modalViewController I have implemented the same header , and it does get the delegates from the header) but this view it self has to delegate to the previous viewController if the back button of the header is pressed.
I have made the same functions but my viewController never gets it's delegate... :(
I am quite new to Obj-C and I don't know maybe I am doing something illegal here.
here is the code of modalViewController trying to delegate to the previous viewController
#pragma mark - header delegate
- (void)header:(header *)header backbuttonPressed:(UIButton *)sender
{
if(header == logo)
{
NSLog(#"gotBackButtonDelegate");
//delete the items array
//_itemSourceArray = nil;
[delegate allEventsDrillPage:self backbuttonPressed:sender];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
This delegate does triggers from the header view.
however in my previous viewController:
- (void)allEventsDrillPage:(allEventsDrillPage *)allEventsDrillPage backbuttonPressed:(UIButton *)sender //doesn't work :(
{
NSLog(#"got back delegate!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
// [self dismissViewControllerAnimated:YES completion:nil];
_drillPage = nil;
}
never get called
I calling the modalViewController like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[_allEventsTableView deselectRowAtIndexPath:indexPath animated:YES];
[self->_allEventsTableView setNeedsDisplay];
[self->_allEventsTableView reloadData];
_drillPage = [[allEventsDrillPage alloc]initWithDictionary:((NSDictionary*) [_tableDataSource objectAtIndex:indexPath.row])];
_drillPage.delegate = self;
[self presentViewController:_drillPage animated:YES completion:nil];
}
in its .h file I did
#interface allEvents : UIViewController <headerDelegate , UITableViewDataSource , UITableViewDelegate ,allEventsDrillPageDelegate>
I don't get what am I missing here :-/ can some1 take a look please ?
if needed more info I will added just ask for it.
EDIT:
protocol of delegate inside the modalViewController
#class allEventsDrillPage;
#protocol allEventsDrillPageDelegate //define delegate protocol
- (void)allEventsDrillPage:(allEventsDrillPage*)allEventsDrillPage backbuttonPressed:(UIButton*)sender;
#end
#interface allEventsDrillPage : UIViewController
{
id<allEventsDrillPageDelegate> __weak delegate;
....
}
#property (weak, nonatomic) id <allEventsDrillPageDelegate> delegate; //define

Let's try:
- (void)header:(header *)header backbuttonPressed:(UIButton *)sender
{
if(header == logo)
{
NSLog(#"gotBackButtonDelegate");
// delete the items array
//_itemSourceArray = nil;
// my comment: you should replace "delegate" to "_delegate"
// and it works. I tested. It's OK. Wow.
[_delegate allEventsDrillPage:self backbuttonPressed:sender];
[self dismissViewControllerAnimated:YES completion:nil];
}
}

nmh's answer is correct. I wrote up an answer earlier but his came in faster, so I thought I would take out the other parts and just add the explanations here.
You have this:
#interface allEventsDrillPage : UIViewController
{
id<allEventsDrillPageDelegate> __weak delegate;
....
}
#property (weak, nonatomic) id <allEventsDrillPageDelegate> delegate;
With this id<allEventsDrillPageDelegate> __weak delegate; you declare an ivar.
With this #property (weak, nonatomic) id <allEventsDrillPageDelegate> delegate; you are declaring a property.
Since Xcode 4.4 you get auto-synthesization.
And so this line:
_drillPage.delegate = self;
You are setting the one via the property.
And not this:
id<allEventsDrillPageDelegate> __weak delegate;
So what you have here:
[delegate allEventsDrillPage:self backbuttonPressed:sender];
You are using the ivar above, not the one via the property.
And delegate is thus nil.
And so, if you try to send a message to the delegate using nmh's solution or:
[self.delegate allEventsDrillPage:self backbuttonPressed:sender];
It should work as expected.
Addendum to dismissing modal view controller:
Instead of dismissing it from the current view controller, dismiss it from the one who presented it, so:
- (void)header:(header *)header backbuttonPressed:(UIButton *)sender
{
if(header == logo)
{
NSLog(#"gotBackButtonDelegate");
[_delegate allEventsDrillPage:self backbuttonPressed:sender];
//or self.delegate
}
}
And in:
- (void)allEventsDrillPage:(allEventsDrillPage *)allEventsDrillPage backbuttonPressed:(UIButton *)sender
{
NSLog(#"got back delegate!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
[self dismissViewControllerAnimated:YES completion:nil];
_drillPage = nil;
}
Or even better:
- (void)allEventsDrillPage:(allEventsDrillPage *)allEventsDrillPage backbuttonPressed:(UIButton *)sender
{
NSLog(#"got back delegate!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
[self dismissViewControllerAnimated:YES completion:^{
_drillPage = nil;
}];
}
Hope this helps.

Related

iOS self.delegate is nil even after being set

I have a controller that gets instantiated and pushed onto the navigation controller like this -
In ParentVC.m
ThingContainerViewController *thingContainer = [[ThingContainerViewController alloc] init];
thingContainer.delegate = self;
[self.navigationController pushViewController:thingContainer animated:YES];
Now I want to send back a value to ParentVC when the thingContainer is closed. So I have implemented a delegate as follows:
in ParentVC.h
#interface ParentVC : UIViewController <..., ThingContainerViewControllerDelegate>
in ThingContainer.h
#protocol ThingContainerViewControllerDelegate <NSObject>
- (void)addItemViewController:(id)controller didFinishEnteringItem:(NSInteger)page;
#end
....
#interface
....
#property (nonatomic, weak) id <ThingContainerViewControllerDelegate> delegate;
....
#end
in ParentVC.m
- (void)addItemViewController:(id)controller didFinishEnteringItem:(NSInteger)page {
self.page = page;
}
in ThingContainer.m
- (IBOutlet) ... closeButtonWasTapped:(UIButton *)button {
NSLog(#"%ld", (long)indexOfPage);
[self.delegate addItemViewController:self didFinishEnteringItem:indexOfPage];
[[self navigationController] popViewControllerAnimated: YES];
}
At this point, self.delegate is null, so the method in the ParentVC never gets called. Any idea how I can fix it?

modalViewController not dealocs with ARC

My view controller I represent modally never get reallocates it is always living (saw by count in instruments).
I saw similar questions on this site, the answers were "you should find what strong object is pointing to the modal view controller"
I cannot find it out, please help me
here is my code:
here I call for modal view:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self dismissKeyboard];
[self CheckAndStore:indexPath.row];
NSLog(#"At Select");
self->DetailsView = [[InfoViewController alloc]initWithParameter:[PersonsFromSearch objectAtIndex:indexPath.row]];
DetailsView.delegate = self;
[tableView deselectRowAtIndexPath:indexPath animated:YES];
[self presentViewController:DetailsView animated:YES completion:nil];
}
here inside modal view:
-(void) Back
{
NSLog(#"Back Clicked");
[self dismissViewControllerAnimated:NO completion:nil];
}
initWithParameter:
- (id) initWithParameter:(id)parameter
{
Dict = parameter;
return self;
}
inside detailsView.h
#interface InfoViewController : UIViewController <UITableViewDelegate, UITableViewDataSource , UISearchBarDelegate
,MFMessageComposeViewControllerDelegate,MFMailComposeViewControllerDelegate>
{
id<InfoViewControllerDelegate> __weak delegate;
NSDictionary *Dict;
…
}
#property (weak, nonatomic) id <InfoViewControllerDelegate> delegate;
...
DetailsView is an iVar (could it be a problem ?)
If need more code please tell me I will post (I am quite newbie in iOS development).
You should declare your delegate in DetailsView to be weak to avoid strong reference cycle. Also you need to set your self->DetailsView to nil when you want to release it. Because if you still hold a strong reference to it, how could it be deallocated?

My program not going inside the delegate method

I am trying to use a delegate method in AddCity.m controller that I created in the City.m controller. The method is
City.m
- (void)EditCityController:(id)controller didEditItem:(id)item
{
if(item)
{
NSDictionary *d = (NSDictionary *)item;
[self.model addNewCity:[d valueForKey:#"cityName"] forProvince:self.ro inMayor:[d valueForKey:#"mayorName"] inPopulation:[[d valueForKey:#"population"]intValue] inYearEstablished:[[d valueForKey:#"yearEstablished"]intValue]];
[self.model saveChanges];
}
// Dismiss the modal view controller
[controller dismissViewControllerAnimated:YES completion:nil];
}
City.h
#interface Cities :
UITableViewController<NSFetchedResultsControllerDelegate, EditCityDelegate>
And then in AddCity.h i have
#protocol EditCityDelegate;
#interface AddCity : UIViewController<UITextFieldDelegate>
#property (nonatomic, assign) id <EditCityDelegate> delegate;
#protocol EditCityDelegate <NSObject>
- (void) EditCityController:(id)controller didEditItem:(id)item;
#end
I am calling it from AddCity.m (Currently trying to the cancel button).
- (IBAction)cancel:(id)sender {
[self.delegate EditCityController:self didEditItem:nil];
}
When i put a breakpoint what happens is that it hits the self.delegate line but it does not go into the EditCityController method in the City.m controller.Any idea on what i am doing wrong?
I assume you call AddCity.m in City.m and present it using presentViewController
AddCity *addcityVC = [AddCity new];
addcityVC.delegate = self; // initialize the delegate here
[self presentViewController:addCityVC animated:YES completion:nil];
You need to initialize the delegate back to self so it can call the method you need
Hope this helps

delegate = nil, transfer information between VCs issue

I just started to learn obj-c and I have question about delegates. I know that on SOF is a lot of similar threads, but I was looking for and really didn't get my issue (maybe cause I'm beginner). Here's my problem: I want to use my own delegate and transfer an information from SlaveClass to MainClass. In SlaveClass in buttonDidClick: action, I declare delegate which is equal to NIL. Even I don't know where I should start to looking for mistake. Thanks in advance for any type of advice. Here's my code which refer to delegate:
SlaveClass.h
#protocol slaveDelegate <NSObject>
-(void)transferNameDidClick:(NSString *)text;
#end
// --------------------------------------------------------------------------------
#interface SlaveClass : UIViewController
#property (nonatomic, strong) id <slaveDelegate> myOwnDelegate;
#end
SlaveClass.m (here appears NIL)
-(void)buttonDidClick:(id)sender
{
if ([_myOwnDelegate respondsToSelector:#selector(transferNameDidClick:)])
{
[_myOwnDelegate transferNameDidClick:(_textField.text)];
}
}
MainClass.h
#interface MainClass : UIViewController <slaveDelegate>
#end
MainClass.m
-(void)transferNameDidClick:(NSString *)text
{
SlaveClass *delegate = [[SlaveClass alloc] init];
[delegate setMyOwnDelegate:self];
[_label setText:text];
NSLog(#"text: %#",text);
}
You are setting your delegate in wrong place. You have to set the delegate before going to slaveClass
mainClass.m
Present slave view controller like this
SlaveClass *slaveClass = [[SlaveClass alloc] init]
[slaveClass setMyOwnDelegate:self];
[self presentViewController:slaveClas animated:YES completion:nil];
-(void)transferNameDidClick:(NSString *)text
{
// This is the method getting called by the slaveClass. So it should know the delegate to call this.
[_label setText:text];
NSLog(#"text: %#",text);
}
Set you delegate out side the Custom delegate method. you are mistakenly setting inside the custom delegate method thats y delegate show nil. use like this.
Main Class .M
-(IBAction)nextView
{
nextView = [[ViewController2 alloc]init];
nextView.myOwnDelegate = self;
[self presentViewController:nextView animated:YES completion:nil];
}
-(void)transferNameDidClick:(NSString *)text;
{
NSLog(#"Value from Slave Delegate %#",text);
}
SlaveClass.h
#protocol slaveDelegate <NSObject>
-(void)transferNameDidClick:(NSString *)text;
#end
// --------------------------------------------------------------------------------
#interface SlaveClass : UIViewController
#property (nonatomic, strong) id <slaveDelegate> myOwnDelegate;
#end
SlaveClass.m
-(void)buttonDidClick:(id)sender
{
if ([_myOwnDelegate respondsToSelector:#selector(transferNameDidClick:)])
{
[_myOwnDelegate transferNameDidClick:(_textField.text)];
}
}

ios custom delegate setup

I am trying to make a custom protocol that i hope somebody might help with.
I have a mainViewController (mainVC) that has a label. That label needs to be updated with a string when i press a button in edwwVC.
I am using ARC and storyboard.
The problem is when i press the Done Button on the edwwVC, the "done" method is called BUT the delegate method is not called in mainVC.
Whereas, if i call the done method VIA the mainVC, then the done method is called AND the delegate method. So I can see the connection is there, I just do not understand why the delegate method is not called when i press the done button in the edwwVC.
I imagine it has something to do with the init of the edwwVC. Because it is already initiated by storyboard, so it looks to me as if I am initializing it again the in the viewDidLoad method of the mainVC. But that is how far i got :)
Thanks in advance!
edwwVC.h
#import <UIKit/UIKit.h>
#import "IIViewDeckController.h"
#class EDWWViewController;
#protocol EDWWViewControllerDelegate <NSObject>;
#optional
- (void)edwwVCDidFinish:(EDWWViewController *)edwwVC;
#end
#interface EDWWViewController : UIViewController <IIViewDeckControllerDelegate> {
__weak id<EDWWViewControllerDelegate> delegate;
NSMutableArray *edwwPoints;
}
#property (weak) id<EDWWViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITableView *theTableView;
#property (strong, nonatomic) NSString *testString;
- (IBAction)done:(id)sender;
- (IBAction)add:(id)sender;
#end
edwwVC.m:
#pragma mark - delegate method
- (IBAction)done:(id)sender {
testString = #"This is the test string!";
[delegate edwwVCDidFinish:self];
[self.viewDeckController closeRightViewAnimated:YES];
NSLog(#"Done pressed");
}
MainVC.m:
- (void)viewDidLoad
{
[super viewDidLoad];
edwwViewController = [[EDWWViewController alloc] init];
edwwViewController.delegate = self;
}
- (void)edwwVCDidFinish:(EDWWViewController *)edwwVC {
edwwLabel.text= edwwVC.testString;
NSLog(#"delegate method called");
}
Remove the line ...
__weak id<EDWWViewControllerDelegate> delegate;
From the .h and change the line...
[delegate edwwVCDidFinish:self];
to...
[self.delegate edwwVCDidFinish:self];
In the .m.
That should sort it.
The way you have it set up the ivar delegate is not the same as the property delegate (which is actually an ivar called _delegate) (thanks #Joris Kluivers, just adding for clarity). They are pointing to different things.
If you add a breakpoint where you are calling the delegate method I think you'll find that delegate is nil. Whereas _delegate (or self.delegate) is not nil.
::EDIT::
Ahh... just spotted the second bit too.
If you are setting up the edwwvc in storyboard then you should be alloc initing it too.
If you are segue-ing to the edwwvc then you should intercept the segue in mainVC.m like this...
- (void)prepareForSegue: //blah the rest of the name...
{
if ([segue.identifier isEqualToString:#"the name of your segue"])
{
EDWWViewController *controller = segue.destinationViewController;
controller.delegate = self;
}
}
This will take the controller that you are pushing to from the storyboard and set the delegate to it.
:: ANOTHER EDIT ::
If EDWWVC is inside a containerViewController then you can do this inside viewDidLoad in MainVC.m...
- (void)viewDidLoad
{
// other stuff...
for (UIViewController *controller in self.childViewControllers) {
if ([controller isKindOfClass:[EDWWViewController class]]) {
EDWWViewController *edwwvc = (EDWWViewController*)controller;
eddwvc.delegate = self;
}
}
}
You may find this code has to go in viewDidAppear or something but I think viewDidLoad shouldd work just fine.
You may actually be able to set the delegate property directly by using the storyboard to (but I'm not 100% certain on this).
The answer was in the containerVC of both controllers.
Where i initialized the view controllers: the viewDidLoad of the containerVC m file:
- (void)viewDidLoad
{
[super viewDidLoad];
mainVC = (MainViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"MainVC"];
edwwVC = (EDWWViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"EDWWVC"];
//THIS LINE WAS MISSING
edwwVC.delegate = mainVC;
self.centerController = mainVC;
self.rightController = edwwVC;
}
BUT guys thanks for the help! :) Appreciate it got me in the right direction! :) THANKS! :)

Resources