iphone sdk - calling a method of view's superview's viewcontroller - iphone

hello how can i call in the current view, a method implemented in the viewcontroller of the current view's superview?
can you help me please.
thanx

Typically this is done through delegates.
Have your view interface define a protocol and a reference to some delegate. Then have your parent viewcontroller implement this protocol.
Then the parent would do this:
someView.fooDelegate = self;
then the view would do something like this:
if(self.fooDelegate != nil) {
if([fooDelegate respondsToSelector:...]) {
[fooDelegate performSelector:...];
}
}
This is not compiled, but I think you get the gist.

You can add a function -(void)initWithView:(EchiquierDisplayView *)aSuperview or something like that, define a reference in your
#interface pieceDraggableImageView : UIImageView {
CGPoint startLocation;
CGPoint startLocationInView;
EchiquierDisplayView *theSuperview;
}
#property (nonatomic, retain) EchiquierDisplayView *theSuperview;
-(void)correctDestinationPosition;
-(void)initWithView:(EchiquierDisplayView *)aSuperview;
...
-(void)askSuperview;
#end
#implementation pieceDraggableImageView
...
-(void)initWithView:(EchiquierDisplayView *)aSuperview
{
theSuperview = aSuperview;
}
...
-(void) correctDestinationPosition
{
[theSuperview correctIt];
}
Now be sure to implement the function correctIt in your superview.
Hopefully i understood your question right...

UIViews have no knowledge of their view controllers. You will need to create a custom UIView subclass that maintains a reference to one (or potentially more than one) view controller, although doing so introduces further coupling between UIView and UIViewController.
You should consider implementing the method in the superview's or view's class rather than implementing it in a view controller.

Here is another way:
SuperviewsViewController *controller = self.superview.nextResponder;
if (controller && [controller isKindOfClass:[SuperviewsViewController class]])
{
[controller method];
}
It should work in most cases.
Apple's UIResponder Reference

Related

viewDidLoad in UITextView subclass?

Cocoa/Objective-C noob here.
I'm working on a simple app to learn some more about iOS development, and am struggling to see how my subclass of UITextView has it's viewDidLoad method called.
I am subclassing UITextView to CMTextView.
Using storyboard, I have a CMTextView in the window.
In CMTextView.m, I have the following:
#import "CMTextView.h"
#interface UITextView ()
- (id)styleString;
#end
#implementation CMTextView
- (id)styleString {
return [[super styleString] stringByAppendingString:#"; line-height: 1.1em"];
}
- (void)viewDidLoad {
NSLog(#"LOADED!"); // not doing anything...
}
I'm not doing anything fancy to add this as a subview of my window, but I thought the storyboard did that for me?
Does anyone have any advice?
The above answers are correct if you manually initialize the UITextView. If loading them from a nib, you need to override the -awakeFromNib method.
-(void)awakeFromNib
{
[super awakeFromNib]; // Don't forget to call super
//Do more intitialization here
}
If you want to handle the resizing also override the -layoutSubviews method
viewDidLoad is a method in UIViewController not UIView/UITextView
if you want to do any initialize then put it in initWithFrame:
viewDidLoad is a UIViewController method (see here).
UIKit ensures that viewDidLoad is called at appropriate times when you instantiate a view controller's view, but it has no role to play in a UIView like UITextView.
Usually, you prepare your view at initWithFrame time.
A view can never have the method viewDidLoad.
Some methods are tethered only to the viewcontroller and viewDidLoad is one of them.
The method constructors for views would be
-(id)init;
-(id)initWithFrame;

How to trigger an action from one view controller to another in iOS

How would I go about changing the a UILabel property in another view controller?
I have #import "SecondViewController.h" imported in the FirstViewController.m file and then
I have the following in a method in FirstViewController
-(IBAction) someAction {
SecondViewController *objV1 = [[SecondViewController alloc]init];
objV1.secondViewControllerLabel.alpha = 0.2;
NSLog(#"someAction");
}
when someAction is called nothing happens to the UILabel in the SecondViewController.
also, in this example both first and second view controllers are in another view controller called MainViewController. So, they are both onscreen at the same time.
thanks for any help.
From what you tell us, it would seem that you need to set the "embeded view controllers" as childs of the parent View Controller.
[mainViewController addChildViewController:childViewController];
[childViewController.view setFrame:self.view.bounds];
[self.childContainerView addSubview:childViewController.view];
[childViewController didMoveToParentViewController:self];
This is very powerful, because you can forward IBActions from the mainViewController to their child...
[mainViewController childViewControllers]
Returns an array of them, and also take a look at
– shouldAutomaticallyForwardRotationMethods
– shouldAutomaticallyForwardAppearanceMethods
So your child get automatically informed about the rotations of their parent.
To answer your question, you could do something like:
// In Parent View Controller
- (IBAction) anAction:(id) sender
{
for (CustomChildController *child in self.viewControllers) {
[child handleSomeAction];
}
}
Check out what the docs say for more details.
#Goles answer will work, but if you specifically want to trigger the change from FirstViewController.m you need to pass in a reference to SecondViewController somehow.
So you could do it with a custom init that takes a reference to your second viewcontroller as a parameter, or create a property on your FirstViewController that you can set from outside, which would be something like this:
FirstController.h:
#interface
..
#property (strong, nonatomic) UIViewController *second;
...
#end
FirstController.m:
#implementation
#synthesize second
In your parent ViewController you would create both the child view controllers, then:
ViewController1.second = ViewController2;
Then your action method would become:
-(IBAction) someAction {
self second.secondViewControllerLabel.alpha = 0.2;
NSLog(#"someAction");
}
Since in the secondViewController, secondViewControllerLabel has not been created yet, 'objV1.secondViewControllerLabel.alpha' will have no effect. Ideally, you should create a NSNumber property called labelAlpha in the secondViewController, set that property in the firstViewController, and then in the viewDidLoad of the second controller, add this line ::
self.secondViewControllerLabel.alpha = self.labelAlpha;
This will work for you.

Pushing a UIViewController from a UIView

I need to push a UIView into my UINavigation controller. I am doing it by
[self.view addSubview:showContactFlow];
And on a button click in UIView I need to push another UIViewController over the UIView. From the UIView I am not able to access self.navigationcontroller How can I do this?
Edit:
I have set the UIView as the view of a new UIViewController I am pushing into, the before mentioned UIViewController . Now I would like to know, how to handle the UIView button event inside its UIViewController, in which's view it is set.
Add a UINavigationController ivar to the UIView and assign it to the main view controller's. Then you should be able to access it from the UIView.
Edit:
Your UIView subclass:
// CustomView.h
#interface CustomView: UIView {
// ...
// your variables
// ...
UINavigationController *navController;
}
#property (nonatomic, assign) UINavigationController *navController; // assign, because this class is not the owner of the controller
// custom methods
#end
// CustomView.m
#implementation Customview
// synthesize other properties
#synthesize navController;
// implementation of custom methods
// don't release the navigation controller in the dealloc method, your class doesn't own it
#end
Then before the [self.view addSubview:showContactFlow]; line just add [showContactFlow setNavController:[self navigationController]]; and then you should be able to access your hierarchy's navigation controller from your UIView and use it to push other UIViewControllers.
You should try to work with an MVC approach. So your controller has access to all that stuff and can keep pushing and popping views, so the view doesn't need to know too much about the controller.
Otherwise, and for this case you can solve it fast by using delegation. So:
showContactFlow.delegate = self;
[self.view addSubview:showContactFlow];
So later in the UIView, you can just say:
[self.delegate addSubview:self];
This is gonna work, but it's not likely to be the best approach you should use.
On button click, you can present a view controller like,
-(void)buttonFunction{
ThirdVC *third= [[ThirdVC alloc]initWithNibNme];......
[self presentViewController:third animated:NO];
}
Using Core animation you can make NavigationController's pushviewController like animation on writing code in ThirdVC's viewWillAppear: method.
where do you add the UIButton is it in showContactFlow view or in the ViewController's view??
In regard to the modalViewControllers issue the correct method is
[self presentModalViewController:viewController animated:YES];
the standard animation in upwards

Parent view -> Subview -> button -> subview method

I have a parentview with a ui view on it. This loads a subviewcontroller on viewdidload. The subviewcontroller has a button on it that is linked up on touch up inside to a subviewcontroller method called clicked.
This causes a bad access error to fire and crashes the app. My question is, is this setup possible or do I have to have the method in the parent view? The subview will be loaded in 8 different parentviews so I would like to keep the method in the subview.
What would be the correct way of doing this?
The good approach for this kind of setup is to have a protocol including the click message, a delegate property of type id in the view containing the button and a method in the same view that fires the delegated message like so [self.delegate clicked]. The TouchUpInside event is linked to that method in IB and the parent view set itself as delegate of the subview and conform itself to the protocol. It can sounds a bit tricky but its definitely the proper way to do.
the Protocol
#protocol viewWithButtonDelegate
-(void)buttonClicked:(UIButton*)button inView:(UIView*)view;
#end
in the subview interface
#interface viewWithButton {
...
id<viewWithButtonDelegate> delegate;
}
...
#property (nonatomic, retain) id<viewWithButtonDelegate> delegate
-(void)buttonClicked:(id)sender;
...
#end
in the subview implementation
-(void)buttonClicked:(id)sender {
if([sender class] == [UIButton class]) {
[self.delegate buttonClicked:(UIButton*)sender inView:self]
}
}
the controller interface is declared like this
#interface myController<viewWithButtonDelegate>
and finally in the controller implementation :
-(void)buttonClicked:(UIButton*)button inView:(UIView*)view {
//do something in response to button clicked
}
hope this helps...

Clearing "may not respond" warnings for UIView and UIViewController

In an iPad app, I'm using a custom subclass of UIView with UIViewController. Here's the view header:
#interface pdfView : UIView {
CGPDFDocumentRef doc;
}
-(void)setDoc:(CGPDFDocumentRef)newDoc;
#end
And here's the controller header:
#interface iPadPDFTestViewController : UIViewController {
CGPDFDocumentRef doc;
}
- (void)loadPDF;
#end
Part of the controller implementation:
- (void)viewDidLoad {
[super viewDidLoad];
[self loadPDF];
[self.view setDoc:doc];
}
In Interface Builder, I've set the view object to use the class pdfView.
At compilation, [self.view setDoc:doc]; gives the warning "'UIView' may not respond to '--setDoc'." I'm guessing that this warning appears because the compiler thinks it's looking at UIView (which does not implement the setDoc method) instead of pdfView. But why does it think that? And how can I tell it what class it's really looking at, so as to clear the warning?
The compiler only knows what the code defines, and a UIViewController defines it's view property as a UIView, which is why you're seeing warnings.
You can avoid warnings by casting the view to your PDFView: (PDFView *)self.view;
To make this simpler implement a basic getter method
- (PDFView *)view {
return (PDFView *)self.view;
}
Also, just as a side note, you should really name your classes so they start with atleast one uppercase char, and ideally a prefix (i.e. PDFView, ideally MYPDFView (where MY is a custom prefix)).