Accessing parent view of current view - iOS - ios

When I want to access the parent UIView of current UIView I declare object of parent UIView in current UIView and access it by assigning the parent UIView object to current view's object property.
Is there any way to get rid of this and directly call the parent view's methods or properties?
I also tried (parentView *) self.view.superview but didn't help.
It gives error while calling function for this object as
[UIVIew unrecognized selector......

If you're calling this directly from a UIView (and not a UIViewController), it should be self.superview instead of self.view.superview.

# Naveed: This is the common code u can use to any view whether it is parent or child view, Just change button name which u want to press and the view name on which u want to go. For example on back button press u want to go on library view then write this code -
-(IBAction)backButtonPressed:(id) sender
{
llibraryView *libraryview=[[libraryView alloc] initWithNibName:nil bundle:nil];
libraryview.modalTransitionStyle=UIModalTransitionStyleCoverVertical;
[self presentModalViewController:libraryview animated:YES];
[libraryview release];
}
Let me know whether ur problem is solved or not.

What I can think is that you want to call the viewcontroller's method from your view, which you added to the viewcontroller's view.
Now you have two options from here, either you set your view controller your view's delegate and then call your viewcontroller's method by [delegate performSelector:] approach.
The other approach is you access your view's superview, and then get it's controller. You can not do that directly, coz if you could do that it would defeat the entire purpose of MVC.
But, still there is a way out, here you go:-
Get to UIViewController from UIView?
Hope, this helps you.

Related

Subview acessing superview methods

How can a subview access the methods from its superview? I have a button, and when pressed I would like the button to call a method from its superview, but I do not know how.
suppose your super View class name is
MainView.h
sub View Name
SubView.h
So In sub class you can do
MainView *myMainView = (Mainview *)[self superview];
[myMainView someMethod];
Make sure someMethod is public Method.
Other way you could have reference to all the view is set a tag
For example
myMainView.tag = 100; or self.tag = 100;
In the subview you could do
MainView *myMainView = (Mainview *)[self viewWithTag:100];
[myMainView someMethod];
a weird construct but just call the method:
inside a view you have have self.superview
since self.superview is a UIView*, the compiler will claim it is invalid to call method XYZ on it. Cast it to id or to your class name to use it
e.g.
[(id)self.superview myMethod];
or even
id myValue = [(id)self.superview myMethod:param1];
One method is to use delegates.
#protocol ButtonHandlingDelegate <NSObject>
- (void) subviewButtonWasPressed;
#end
In your Subview add this:
#property (nonatomic, weak) id selectionDelegate;
When subview is created, set delegate to superview.
Define Superview as delegate in .h file
#interface SuperView : UIView <ButtonHandlingDelegate>
in Superview .m file
- (void) subviewButtonWasPressed{
// Do somethign about it
}
All of the answers listed are hacky and bad style. You should be using delegation through the subview's ViewController. What you will want to do is create a protocol for your subview with a void method called something like specialButtonPressedOnView:(SUBVIEWCLASS *)view. Then in the subview's view controller you should make yourself the delegate for this protocol and respond to the delegate method from the VC's context.
Using self.superview is a bad idea because you cannot guarantee what your superview is going to be and generally blindly calling method on objects (ESPECIALLY those cast to id) is a really bad idea.
The other answer that suggested having the superview implement the subview's protocol is also not good style because you're creating a dependency between your views. If you were thinking of going down this path your subview should probably just be a subclass of the superview.
One of the core parts of the MVC design pattern is making sure that your views are reusable and totally independent. They are just structures that you can inject your content into, to which they will respond with pretty UI, and they don't need to know anything about what's being passed to them and don't have to ask other views for help. So either using delegation through the subview's ViewController or subclassing is probably the best direction. Both methods preserve the MVC pattern and are much safer than the other suggestions.

Why do I get a black screen when I insert a subview?

Using the following code to insert a subview in my UIView I get presented with a black screen. Can someone tell me why?
CJGBoardLabels* whiteLabels = [[CJGBoardLabels alloc] initWithFrame:self.frame
andOrientation:#"white"
andOrigin:self.boardOrigin
andSquareSize:_squareSize
andHorizontalOffset:_horizontalOffset
andVerticalOffset:_verticalOffset];
[self insertSubview:whiteLabels aboveSubview:self];
I get the same result with the following line too:
[self insertSubview:whiteLabels belowSubview:self];
Don't add subviews in the drawRect: method. Instead, use the actual triggering method to add the subviews, and preferably get the controller to add the subviews (not the view itself). So, call addSubview: in the controllers viewDidLoad or an action method.

How can I get the ViewController instance starting from subView

I've an object of UIImageCustom that extend UIImageView, and in a method this class I want to get instance the ViewController, where my object UICustom is added.
In touchesBegan method of my class UIImageCustom, when I touch in UIImage, I want add other UIImage in my ViewController:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UIImageView* newImageView=[[UIImageView alloc] initWithFrame:CGRectMake(60, 200, 200, 200)];
//Here I need add newImageView in my ViewController
[??? addSubview:newImageView];
}
Someone can help me?
You'll have to add a custom property to your UIImageCustom class that contains a reference to the owner view controller if you want to do what you're saying you want to do. But there's a better way.
What I suggest you should be doing is implementing touchesBegan in the view controller that owns the view, and performing any custom logic there.
There are a bunch of ways you could do this (set a custom property in your UIImageCustom class, just have UIImageCustom add this new image view to its own superview (e.g. [self.superview addSubview:newImageView]). But these approaches seem conceptually flawed. A view shouldn't be adding anything other than to itself (and if you turned off clipping, adding this new image view as a subview of the UIImageCustom, itself, might be another approach, certainly less offensive than the previous two I alluded to).
But I might suggest a couple of other approaches:
If your goal is simply to avoid duplication of your touches code, I might put it in a gesture recognizer subclass, rather than attaching it to some random UIImageView subclass. Gesture recognizers is the right place to put this sort of touch-related code. See the Gesture Recognizers section of the Event Handling Guide for iOS.
Or if you really need to marry this gesture with with a bunch of image views, I might use a custom container view controller to mediate this interaction between gestures and image views. See Creating Custom Container View Controllers in the View Controller Programming Guide for more information.
But you could wrap the touches code and the handling of these two image views all within a view controller, and then use view controller containment to add that to an existing view controller.
We don't know enough about the particular design to suggest one over another, but those are a couple of ideas to pursue. Most likely, the custom gesture recognizer approach should be more than sufficient.
Create a category like this
#interface UIViewController (TOP_MODAL)
-(UIViewController*) topModalController;
#end
#implementation UIViewController (TOP_MODAL)
-(UIViewController*) topModalController{
if (self.presentedViewController == nil){
return self;
}
return self.presentedViewController.topModalController;
}
#end
then
AppDelegate* delegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
UIViewController* viewController = [delegate.window.rootViewController topModalController];
...
[viewController.view addSubview:newImageView];

Where and when to initialize/create view programatically

I had this question when/where to create and initialize views that are created programatically, so I hope some discussions here will shed more light on this topic for me.
This slide:
says: "not to initialize something based on the geometry of the view in viewDidLoad" and suggests viewDidAppear.
Imagine my view controller has view. I want to add 10 dynamic UIButtons to it.
Shall I put the code like below to the viewDidAppear?
-(void) viewDidAppear:(BOOL)animated
{
...
UIButton *button1 = [[UIButton alloc] initWithFrame: rect1];
[self.view addSubview: button1];
UIButton *button2 = [[UIButton alloc] initWithFrame: rect2];
[self.view addSubview: button2];
...
}
But this creates the buttons each time the view is shown. Is it what we want?
On the other hand if I put the code in viewDidLoad slide suggest not to initialize geometry of these views there.
Or shall we create buttons in viewDidLoad and set their frames in viewDidAppear?
What approach do you usually take?
But this creates the buttons each time the view is shown. It's true.
So the best thing you can do is to add a boolean (lets name it isLaunched). You set it to FALSE in the method -(void)viewDidLoad
Then add a if condition in your -(void)viewDidAppear where you perform creation of buttons (or other stuff) and set the boolean to true at the end.
You should have something like that :
-(void)viewDidLoad
{
//some settings
isLaunched = FALSE;
}
-(void)viewDidAppear:(BOOL)animated
{
if(!isLaunched)
{
//creating and adding buttons
isLaunched = TRUE;
}
}
zbMax (and now Amar) offered good solutions to implement the view creations in viewDidAppear: I will provide the rational for doing this (over viewDidLoad).
It is pretty simple actually. In viewDidLoad none of the views are actually setup yet, so any attempt to set/create frames or bounds will be extremely inconsistent. Struts and springs (or autolayout) will take effect after this method which will create additional changes to your views. viewDidAppear: is the correct place to do this because you can now rely on existing views and setting frames.
Reason for not playing with the geometry in viewDidLoad is because view is still in the memory and not on the window. Once the view is put on the window, then you can specify geometry. That happens when viewDidAppear is called for your controller.
As recommended, you should do all the initialisation in viewDidLoad as this is one time task and need not be repeated. Hold references to the added subviews and give them appropriate frame in viewDidAppear.
When you are dealing with custom UIView and its subviews, layoutSubviews is the method you need to override in the custom view in order to rearrange the geometry of its subviews.
Hope that helps!

how to make a custom scroll container view controller?

There are two view controllers in my app, e.g, vc1 and vc2. The two view controllers are as the subviews of a scrollView, so the user can scroll the screen to switch the view. However, the simple implement has a problem: the viewWillAppear method of vc1 and vc2 is called only once. so I want to implement my scroll container view controller, which can call viewWillAppear method correctly, please tell me how to implement it.
I am not sure what you are trying to do, but I think a simple UITableView or UICollectionView may be better for you because they have datasource method that will automatically called when a view will show up in the screen. You can update your two views when you need to return a UITableViewCell or UICollectionViewCell.
I'm not sure if this will work, but I'm thinking you can check if the vc1 and vc2's frames are withing the screen's bounds in the delegate method of the scrollView.
I'm pretty sure there's a method being called every time the scrollView is being scrolled. In this method, you can check
//put this in your .h or something
BOOL vc1IsVisible = true;
//in the scrollView delegate-method that is called upon scrolling
if([self isInsideView:vc1])
{
if(!vc1IsVisible)
{
vc1IsVisible = true;
[vc1 viewDidAppear:NO]; //or whatever it is for animation
}
}
else
{
if(vc1IsVisible)
vc1IsVisible = false
//and viewDidDisappear?
}
and then create a method somewhere like this
-(BOOL)isInsideView:(UIViewController*)vc
{
//Check if vc.origin.y is greater than scrollView.size.height or something maybe?
//You can probably also try using the scrollView's contentOffset and use that
//relative to the viewController's sizes.
//if the viewControllers bounds are withing the scrolls bounds, return YES;
//else, return NO;
}
Sorry I can't really test anything just now. Maybe I'll make something and update the answer later if you haven't figured it out. And you need to do it with both. I'm sure you can figure out a better way to include both in one method with this, or even with one variable.
Since you are using ViewController by adding it subview of scrollview, by adding ViewController this way viewDidLoad, viewWillAppear, viewDidAppear will be called only once, I mean there is no use of viewWillAppear here as such, rather if you want to update anything in the added ViewController you should create a public class in ViewController and call it when you need an update..

Resources