Delegation from 'grandchild' view - objective-c

I have a UIView that presents a tableView in a Popover. This tableView then presents another tableView with selectable data. Could someone please explain to me how rouse delegation to get the selected data all the way back to the UIView? I initialize the 2nd tableView and set it's delegate to 'self' when I present the popover. But when I actually do to use the delegate in the 2nd tableView, it is set to null.

That would be something like:
TopMostView.h
#protocol ParentViewDelegate
-(void) operateOnData:(NSObject *)data;
#end
#interface TopMostSubview <ParentViewDelegate>
...
in TopMostView.m
-(void)crateSubview {
... create subview stuff
subview.delegate = self;
...
}
Then in each of the subviews have something like:
#property (weak, nonatomic) id<ParentViewDelegate> delegate;
Whenever you wish to pass data to the superview, you use the operateonData: selector.

Related

Objective C - iPhone/ handle subView events on ParentView

I'm having issues trying to handle the events from a Subview of my Parent View, right now I have a UIViewController that has a a subView another UIViewController, in this subView I have a paging scrollView, I want to fire a method on the parent view when I swipe the subView scroll View, do you have any suggestions on how can I develop this?, thanks
You could make the parent view a delegate of the subview.
Add this to the SubView.h:
// add
#protocol SubViewClassNameDelegate
#required
- (void)triggerMethodFromSubView:(NSString *)value;
#end
//
#interface SubViewClassName : UIView
// add
#property (nonatomic, assign) id<SubViewClassNameDelegate> delegate
//
#end
Then in your parent view class, add this to ParentView.h:
#interface ParentViewClassName : UIView /* add -> */ <SubViewClassNameDelegate>
and this in ParentView.m right after the instantiation of your subview:
[mySubView setDelegate:self];
Finally, add your delegate trigger method somewhere in ParentView.m:
- (void)triggerMethodFromSubView:(NSString *)value {
// do stuff
}
Now, you can call [self.delegate triggerMethodFromSubView:#"Hello World"] anywhere in your subview class, and it will tell the parent view to call your delegated method.
If you need additional info, here's a helpful tutorial: http://www.alexefish.com/post/522641eb31fa2a0015000002

IBOutlet in ARC releases and sets to nil. How to avoid this? objective c

I'm new to ARC and Storyboarding. I've set IBOutlet to UITableView from my UIViewController.
After some time my IBOutlet sets to nil and I can't reload it from other classes.
Here is my dataTable IBOutlet:
#property (weak, nonatomic) IBOutlet UITableView *dataTable;
At the start dataTable is not nil, but not when I try to access it from another class (via appDelegate). How to solve this problem?
UPDATE
I call this method from my UIViewController
[appDelegate.myClass loginWithUserName:loginField.text andPassword:pwdField.text];
When it's done, and I have data to show, I call this code from loginWithUserName method:
MyViewController *controller = [[AppDelegate sharedStoryboard] instantiateViewControllerWithIdentifier:#"MyViewController"];
[controller audioLoaded];
And here is that method in my UIViewController, wich reloads data
-(void) audioLoaded
{
//it is nil here
[self.dataTable reloadData];
}
Set the property to strong retain the object:
#property (strong, nonatomic) IBOutlet UITableView *dataTable;
It's not good practice to access a UITableView from another view controller though..
EDIT:
You shoul reconsider the whole approach, by moving that logic from your appdelegate to a dedicated class that will perform the login. You can create a simple protocol that the UIViewController with the table can implement, then, when calling the login method, pass a reference to the current viewcontroller, something like
loginWithUserName:andPassword:andCaller:(id<LoginDelegate>)sender
Where LoginDelegate is something on this line:
#protocol LoginDelegate
- (void)audioLoaded;
#end
In this way you can just call
[sender audioLoaded];

Modifying properties of a view controller form another view controller

In my project, there are two view controllers - let's say firstViewController and secondViewController. The second view controller has a button, and I want to make sure when the button gets pressed, the second view controller is telling somehow the first view controller - "hey, I got pressed, do something!", and it will do something, like changing a label. How is this possible to perform? Thanks in advance. Some code :
#interface firstViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#end
#implementation firstViewController
#synthesize textLabel;
#end
#interface secondViewController : UIViewController
-(IBAction)buttonPressed;
#end
#implementation secondViewController : UIViewController
-(IBAction)buttonPressed{
// Hey, I got pressed! Set the text on textLabel to "OK"!
}
#end
This is a very simple case of delegation and protocol mechanism of objective-c..
have a look at this tutorial which will explain you how its done.. you can do this via notification also but that is not usually advised...(because notification is usually used when the receiver is unknown , like in the case of UIDeviceBatteryLevelDidChangeNotification you don't exactly know which view controller wants to know about this.)
I'd first consider what the button press means. Does it change the state of the model?
Say your model is an int, and the button increments it. The view controllers wouldn't message each other about that, they would just both observe the state of the model. (The one with the button could change the state, too).
Thinking about it this way, the solution probably isn't delegation. It's probably notification or KVO.
See the answer to this question: Passing data between two view controllers via a protocol
However, ask yourself if you really need a protocol here. If it is just between this classes or just about the question of accessing data of a class or sending information to a class then that is what the interface of a class is made for.
#interface firstViewController : UIViewController{
UILabel *textLabel; // I personally alway add IBOutlet here too, but I think that is not required.
}
#property (weak, nonatomic) IBOutlet UILabel *textLabel;
#end
And in SecondViewController.m:
#import "FirstViewController.h"
#implementation secondViewController : UIViewController
-(IBAction)buttonPressed{
// You will have to have a properly set instance variable firstViewController
[firstViewController.textLabel setText:#"OK"];
}
#end
So your second view controller needs to 'know' the first one. One way of achieving that is defining
FirstViewController *firstViewController;
as property and set it from wherever the second view controller is created and the first one is already known. How to do that exactly depends very much on the architecture of your app.

Passing delegate to a viewcontroller through a viewcontroller

I have three viewControllers in my storyboard and three viewController classes for each of them. From my main viewController, I am opening a navigation viewController in a 'modal' type segue, which is a multi step form and has two views in it. When the user hits 'Finish' on the last (which is second) view, the modal is dismissed and user is back to the main screen.
I am doing this with delegates. and the code for the finish button is also in a delegate and is placed on the main viewController's implementation file. In achieving this I passed the delegate from main view to the navigation's first view, and then from the first view on clicking 'next', I passed the delegate to the second (last) view (which has the finish button).
the passing of delegate from main to navigation's first page is like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"CreateCast"])
{
UINavigationController *navigationController = segue.destinationViewController;
CreateCastStepOneVC *createCastStepOneVC = [[navigationController viewControllers] objectAtIndex:0];
createCastStepOneVC.delegate = self;
}
}
the passing of delegate from navigation's first view to second view is like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ToCastStepTwo"])
{
CreateCastStepTwoVC *createCastStepTwoVC =
segue.destinationViewController;
createCastStepTwoVC.delegate = delegate;
}
}
Things are done well and delegate is doing its job as required. But a warning pops up which is a concern:
Passing '_weak id' to parameter of
incompatible type 'id'
Property declaration in first navigation view is like this:
#property (nonatomic, weak) id <CreateCastStepOneVCDelegate> delegate;
Property declaration is second navigation view is like this:
#property (nonatomic, weak) id <CreateCastStepTwoVCDelegate> delegate;
How have you declared the delegate property on CreateCastStepTwoVC? Also,
are your delegates conforming to a protocol you have defined?
A typical declaration for a delegate property would look something like this:
#property (nonatomic, __unsafe_unretained) id<MyProtocol> delegate;
or if you're not using a protocol (not recommended):
#property (nonatomic, __unsafe_unretained) id delegate;
EDIT:
Having seen your property declarations, you need to change weak to __unsafe_unretained as per this question: Recommended way to declare delegate properties with ARC
You can subclass UINavigationController and add a custom protocol in your subclass. With this approach you will be able to call your delegate from all your view controllers inside your navigation controller. For example, this is the way I used to do that:
#class CustomNavigationController;
#protocol CustomNavControllerDelegate <NSObject>
- (void)editImageController:(CustomNavControllerDelegate *)controller
didFinishPickingMediaWithInfo:(NSDictionary *)info;
- (void)editImageControllerDidCancel:(CustomNavControllerDelegate *)controller;
#end
#interface CustomNavigationController : UINavigationController
#property (nonatomic, weak) id <UINavigationControllerDelegate, CustomNavControllerDelegate> delegate;
#end
In this example I've implemented a similar functionality to a UIImagePickerController. In fact, this is the way the picker is implemented if you look at it's declaration file.

Get subView's containing view

If I have a view (mainView) in which I have added subViews. How do I get to subviews instance to mainView ?
I have a button in those subviews which when pressed should call a method in mainView, so I tried:
[myButton addTarget:self.presentingViewController
action:#selector(myMethod:)
forControlerEvents:UIControletcetc];
and
[myButton addTarget:self.parentViewController action:#selector....];
I read that parentViewController now returns nil in iOS 5, but presentingViewController doesn't seem the way to do it because its not presented modally. Its just a subview. Any hints?
Your question doesn't make it quite clear whether you are talking about views or view controllers. Use the superview property to access a view's parent.
There is generally no way to get from a view to its view controller.
It feels to me that you're trying to let your views know about objects beyond their scope.
If you need to notify about an event to anyone that included your view, you could use a delegate to do that.
Say:
#protocol YourClassDelegate
#optional
- (void)instanceOfYourClass:(YourClass *)instance tappedButton:(UIButton *)button;
#end
and then
#interface YourClass
#property (nonatomic, assign) id<YourClassDelegate> delegate;
#end
I hope you can take it from here, by synthesizing the property, assigning the delegate and calling the method when you need to.