I'm calling a modal viewcontoller from a number of locations and when i close it i'd like to find out what view it is on top of so i can call a update function if it is this custom list i've made.
I'm wondering how i might call a method in the ViewController under the modal view.
Right now i've set up a delegate, but it doesnt seem to call the method that i've set up.
Please see code.
ViewController.h
#interface PICTSharePictViewController : PICTBaseShareViewController <PICTConnModalViewControllerDelegate>
.m
-(void)viewDidLoad{
PICTConnModalViewController *cmodal = [self.storyboard instantiateViewControllerWithIdentifier:#"connModal"];
cmodal.pictDelegate = self;
}
-(void)checkSwitches:(PICTConnModalViewController*)sender{
NSLog(#"-----Check-----");
}
And ModalView
.h
#class PICTConnModalViewController;
#protocol PICTConnModalViewControllerDelegate
-(void)checkSwitches:(PICTConnModalViewController*)sender;
#end
#interface PICTConnModalViewController : PICTBaseViewController {
__weak id <PICTConnModalViewControllerDelegate> sliderDelegate;
}
#property (nonatomic, weak) id <PICTConnModalViewControllerDelegate> pictDelegate;
.m
-(void)viewDidLoad{
[pictDelegate checkSwitches:self];
}
I get no errors or any warnings. Can anyone tell me what I'm doing wrong?
You can access the View Controller that presented the modal View Controller by using the -[UIViewController presentingViewController] method on the modal/presented VC.
Related
When the views are simple, their IBActions and IBoutlets are in viewcontroller, viewcontrollers assigns respective models to be loaded and viewcontroller get notified when models are prepared.
As My project contains lot of custom views for each viewcontroller, I want to implement actions in custom view itself and set data from controller (ViewController).
I should be able to use the same controllers and models for both iPhone and iPad where only UI changes.
I am concerned about how to pass data from view to viewcontroller and displaying data back on view when model changes?
Can anyone please suggest me to pass data between views <---> viewcontroller (controller) <---> model?
To do this I use Delegate design-pattern. It looks like this :
MyView.h
#protocol MyViewDelegate <NSObject>
- (void)customViewDidSomething;
#end
#interface MyView : UIView
#property (nonatomic, assign) id<MyViewDelegate> delegate
#end
MyView.m
- (void)userDidSomething {
[_delegate customViewDidSomething];
}
MyViewController.h
#import "MyView.h"
// ViewController has to implement the protocol
#interface MyViewController <MyViewDelegate>
#property (nonatomic, retain) IBOutlet MyView myView;
MyViewController.m
- (void)viewDidLoad { // Set the delegate somewhere
_myView.delegate = self
}
- (void)customViewDidSomething {
// Ok VC is aware that something happened
// Do something (tell subview to do something ?)
}
Instead of using different custom views, try using a UIViewController and then use the viewcontroller's view to display your UI. Also, this will also ensure that you will be able to communicate between the views and controller efficiently without confusion.
I have a popover view that I added a PFQueryTableViewController too, as a childviewController. I have a button on the popover that, when pressed, should reload the tableview in the PFQueryTableViewController.
Here is the code in the buttonPressed method that should do this:
NotificationsTableViewController *note = (NotificationsTableViewController *)self.childViewControllers[0];
[note loadObjects];
[note.tableView reloadData];
The table is not reloaded, though, and the only way I can get it to reload is by instantiating a whole new controller and adding it to the popover, which is not something I want to end up doing.
Here is some more code:
//NotificationsPopoverController
#class NotificationsTableViewController;
#protocol PopDelegate <NSObject>
-(void) changedQue;
#end
#interface NotificationsPopoverController : PDPopoverController
#property (nonatomic, assign) id<PopDelegate> myDelegate;
#property NotificationsTableViewController *noti;
When my button is pressed I call [self.myDelegate changedQue];
//NotificationsTableViewController.h
#interface NotificationsTableViewController : PFQueryTableViewController <PopDelegate>
//NotificationsTableViewController.m
-(void)changedQue
{
NSLog(#"Did it work?");
[self.tableView reloadData];
[self loadObjects];
}
The log statement is not printed for some reason, not sure why...
I haven't understand the flow completely yet. I think somewhere you will have to add self.note.myDelegate = self;. Hm... I think your have implemented delegate wrongly. Can you paste more complete code on both the view controller.
As per Jacob, add self.myDelegate = self.noti; right after the child view noti solves the problem.
I have an initial ViewController, lets call it HomeViewController, that has a button which calls a modal view controller, lets call it ModalViewController. Inside that ModalViewController I have a table view with two sections. If you click on any cell from section 0 it sends information back to HomeViewController (this part I have working with Protocol). If you click on any of the cells from section 1 it pushes to another view controller with options, lets call it OptionsViewController. Here is where it gets tricky for me. If you click any of those options, dismiss OptionsViewController and close ModalViewcontroller and send that information to HomeViewController, just like ModalViewController to HomeViewController. I have tried to set up a protocol similar to the one in ModalViewController but it is never called.
OptionsViewController protocol & .h file
#protocol OptionsViewControllerDelegate <NSObject>
#optional
-(void) optionsInfo:(NSArray *)optionsViewArray;
#end
#interface OptionsViewController : UITableViewController
#property (retain) id delegate;
#property (nonatomic, strong) NSArray *sendArray;
#end
OptionsViewController.m where it's called to pop off the stack.
{
[self dismissOptionsView];
}
-(void) viewWillDisappear:(BOOL)animated
{
NSLog(#"Send Array: %#", self.sendArray);
[[self delegate] optionsInfo:sendArray];
}
-(void)dismissOptionsView
{
[self.navigationController popViewControllerAnimated:YES];
}
Inside ModalViewController.h
#protocol ModalViewControllerDelegate <NSObject>
#optional
-(void) sendInformation:(NSArray *)infoArray;
#end
#interface ModalViewController : UITableViewController <ConditionsViewControllerDelegate, UISearchBarDelegate>
{
UISearchBar *searchDrugBar;
}
#property (retain) id delegate;
#property (nonatomic, strong) IBOutlet UISearchBar *searchDrugBar;
#property (nonatomic, strong) NSArray *infoArray;
#end
ModalViewController.m where OptionsInfo is supposed to come in.
-(void) optionsInfo:(NSArray *)optionsViewArray
{
//IT NEVER REACHES HERE :(
NSLog(#"HERE");
self.infoArray = optionsViewArray;
NSLog(#"Finished");
[self dismissViewControllerAnimated:YES completion:nil];
}
Has any one has done something similar like this or knows the solution to this? Any information, link, guidance and etc. to the right direction will be appreciated. Thanks in advance.
You need to set the delegate in your OptionsViewController below:-
In your OptionsViewController.m Include below line on your method
[self setDelegate:ModalViewController];
I ultimately want to write an iOS app incorporating ALAssetsLibrary, but as a first step toward understanding delegation, I'm trying to pass a simple message between two view controllers. For some reason, I can't seem to get the message to pass. In particular, the delegate object (derpy) doesn't appear to exist (if(self.derpy) returns NO)).
I asked the same question on the Apple forums and was told that I should be using segues and setting properties / calling methods using self.child instead, but that seems strange. If I were to pass messages using the parent / child properties, would I still be able to create my views in Interface Builder? Once I have my two views set up, say inside a UINavigationController, I'm not sure how to actually "wire them up" so I can pass messages between them. Sorry if the question is overly broad.
Here's the controller I'm declaring the protocol in (called PickerViewController):
Interface:
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#protocol DerpDelegate <NSObject>
#required
- (void) test;
#end
#interface PickerViewController : UIViewController
#property (nonatomic, assign) id<DerpDelegate> derpy;
#end
Implementation:
#import "PickerViewController.h"
#interface PickerViewController ()
#end
#implementation PickerViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.derpy) { // If the delegate object exists
[self.derpy test]; // send it this message
} else {
NSLog(#"Still not working."); // This always returns (i.e., self.derpy doesn't exist)
}
}
Delegate controller (MainViewController) interface:
#import <UIKit/UIKit.h>
#import "PickerViewController.h"
#interface MainViewController : UIViewController <DerpDelegate> // public promise to implement delegate methods
#property (strong, nonatomic) PickerViewController *picker;
- (void) test;
#end
And lastly, the delegate controller (MainViewController) implementation:
#import "MainViewController.h"
#import "PickerViewController.h"
#interface MainViewController ()
#end
#implementation MainViewController
// Here's that method I promised I'd implement
- (void) test{
NSLog(#"Test worked."); // This never gets called
}
- (void)viewDidLoad {
[super viewDidLoad];
self.picker.derpy = self;
//lazy instantiation
- (PickerViewController *) picker{
if(!_picker) _picker = [[PickerViewController alloc]init];
return _picker;
}
EDIT: Many thanks to rydgaze for pointing me in the right direction with self.picker.derpy = self, but for some reason, things still aren't working properly. Importantly, once that property has been set, if(self.picker.derpy) returns YES from MainViewController. But if(self.derpy) is still returning NO when called from inside the PickerViewController's viewDidLoad. How can the property exist and not exist at the same time?
You need to be sure that you're setting the delegate on the instance of the view controller that you put on screen. If you're using a navigation controller and segues to go between MainViewController and PickerViewController, then you should set the delegate in prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
self.picker = (PickerViewController *)segue.destinationViewController;
self.picker.derpy = self;
}
You need to populate the delegate first.
Basically, your MainViewController shoudl at somepoint do a
picker.derpy = self;
Then when the delegate fires in PickerViewController, the callback will happen.
Edit:
A good practice is to do something like in PickerViewController
#property (nonatomic, assign) id<DerpDelegate > derpy;
and in your MainViewController indicate that you will implement the delegate
#interface MainViewController : UIViewController<DerpDelegate>
Eventually in your implementation of MainViewController
You will have something like
picker = [[PickerViewController alloc]init];
picker.derpy = self;
[picker doYourThing];
Once picker is all done, it may want to return results using the delegate.
I'm trying to set the delegate for my custom protocol that has one required method allowing me to pass an array of objects back in the hierarchy of two UITableViewControllers. My delegate continues to return nil. Due to this, my required method is never called.
I'm wondering if the datasource and delegate implementations with my UITableViewControllers is causing a conflict. Also, perhaps ARC is getting in the way when declaring the delegate?
It should be noted that both UITableViewControllers were built using Storyboard and are navigated using segues within a UINavigationController (not sure if this may be causing issues or not).
The nav is --> AlarmViewController --> AlarmDetailsViewController. I create an Alarm object in my AlarmDetailsViewController that contains all the details for an alarm, place it into an array and I want to pass that array back to my AlarmViewController to be displayed in a custom cell in the table.
NOTE: I want to use the Delegate pattern here. I'm not interested in solutions that invoke NSNotifications or use my AppDelegate class.
AlarmDetailsViewController.h
#import "Alarm.h"
#protocol PassAlarmArray <NSObject>
#required
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray;
#end
#interface AlarmDetailsViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate>
{
//.....
id <PassAlarmArray> passAlarmsArrayDelegate;
}
#property (nonatomic, retain) id <PassAlarmArray> passAlarmsArrayDelegate;
#end
AlarmDetailsViewController.m
#import "AlarmDetailsViewController.h"
#interface AlarmDetailsViewController ()
#end
#implementation AlarmDetailsViewController
#synthesize passAlarmsArrayDelegate;
-(void) viewWillDisappear:(BOOL)animated
{
NSLog(#"delegate = %#", self.passAlarmsArrayDelegate); // This prints nil
[[self passAlarmsArrayDelegate] passAlarmsArray:alarmsArray];
}
//....
#end
AlarmViewController.h
#interface AlarmViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, PassAlarmArray>
{
//...
AlarmDetailsViewController *alarmDetailsViewController;
}
#property (nonatomic, retain) AlarmDetailsViewController *alarmDetailsViewController;
#end
AlarmViewController.m
#import "AlarmViewController.h"
#import "AlarmDetailsViewController.h"
#import "AlarmTableViewCell.h"
#import "Alarm.h"
#interface AlarmViewController ()
#end
#implementation AlarmViewController
#synthesize alarmDetailsViewController;
- (void)viewDidLoad
{
[super viewDidLoad];
// This is where I'm attempting to set the delegate
alarmDetailsViewController = [[AlarmDetailsViewController alloc]init];
[alarmDetailsViewController setPassAlarmsArrayDelegate:self];
}
//....
//My #required protocol method which never gets called since my delegate is nil
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray
{
alarmsTableArray = theAlarmsArray;
NSLog(#"alarmsTableArray contains: %#", alarmsTableArray); // Never gets called due to delegate being nil
NSLog(#"theAlarmsArray contains: %#", theAlarmsArray); // Never gets called due to delegate being nil
}
#end
I've attempted to set the delegate in a method that fires when a button is pressed in AlarmViewController (as opposed to the viewDidLoad method) but that does not work either.
I'm assuming I've got a logic flow error somewhere here . . . but nearly 2 days of hunting and rebuilds haven't uncovered it. Ugh.
You're setting your delegate in the wrong place, and on a different instance of the controller than the one you will get when you do the segue. You should set the delegate in the prepareForSegue method if you're pushing AlarmDetailsViewController from AlarmViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AlarmDetailsViewController *alarm = segue.destinationViewController;
alarm.passAlarmsArrayDelegate = self;
}
You really need to understand the life cycle of view controllers, how and when they're instantiated, and when they go away. This is the very heart of iOS programming, and Apple has extensive documentation on it. Reading up on segues would also be very useful. A segue (other then an unwind segue) always instantiates a new instance of the destination controller. So, when your segue is performed, whether directly from a button, or in code, a new (different from the one you alloc init'd directly) details controller is instantiated. Before that segue is performed, prepareForSegue: is called, and that's when you have access to the one about to be created. That's the place to set a delegate or pass any information on to the destination view controller.
Did you try replace (nonatomic, retain) with (nonatomic, strong) since you are using ARC?
Auto-synthesized properties like your alarmDetailsViewController property have backing ivars prefixed with underscores, e.g. _alarmDetailsViewController. Your alarmDetailsViewController ivar (the alarmDetailsViewController declared inside the #interface ... {} block in AlarmViewController.h) is different from the backing ivar of your alarmDetailsViewController property.
Just delete your alarmDetailsViewController ivar and use the #property, preferably through self.alarmDetailsViewController.