I've created a view controller and the associated view using the interface builder. I'm trying to call a function that I added to the UIView from the UIViewController. I'm not sure how to call that function though.
I've tried
[self.view myFunction]
but that just makes my program crash.
Did you declare your IB outlets and connect the method to it?
Your view (more accurately nib)'s file owner should be set to your viewController class.
Unless your calling drawing functions and methods you shouldn't call anything on the view. You just don't need to.
Edit: grammar corrections.
How is the view getting initialized? Is it a custom view type? If your view is being initialized from a nib, make sure that the class on the view type is the class that has the method implemented.
It is probably crashing because UIView does not have a method named myFunction. In order to add myFunction to a UIView object, you need to subclass it.
I assume you have subclassed your UIView, and called it something like MyView. You also probably have subclassed your UIViewController and called it MyUIViewController. Therefore you may have:
#interface MyViewController : UIViewController {
MyView *myView;
....
}
Now you can call [self.myView myFunction];
That's one way. Another way may be:
[(MyView *)self.view myFunction];
This depends on whether myView is the first view in the hierarchy (or should be set up in your NIB files).
Related
I have a subclass of UIViewController that I want to add from the storyboard.
So I'm using what seems the standard methodology:
SubViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SubViewControllerID"];
[self addChildViewController:svc];
[self.view addSubview:svc.view];
Which is fine but what if I want to call a custom init method on the subview?
I can do something like:
svc = [svc initWithFoo:#"Hello"];
Which seems to have to go after the addSubview call inorder for it to work.
Is this the best way to do this?
Seems a bit unorthodox. Calling an init method on an object that has already been created seems like its no longer truly an init method.
Maybe I should call it setWithFoo: or something and not have it return anything?
SubViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:#"SubViewControllerID"];
will cause the SubViewController to be inited with it's - (id)initWithCoder:(NSCoder *)decoder {} method.
Override that method (don't forget to call super)
If you want to do additional setup to your view controller after you instantiate it form the storyboard you can create some methods in the view controller's class and call them after the instantiate method fo the storyboard.
But be careful, if you try to make changes on any UI component in those methods, they wont be applied, and probably the app will crash. So use those methods to set params to the View Controller like array of objects, or any kind of data, and apply the UI changes for the view controller's view in viewDidLoad/viewWillAppear/viewDidAppear methods of your view controller.
Essentially I think the answer is that you can't use custom initialisers on ViewControllers added from the storyboard. Instead you have to set properties directly or through a method at the appropriate time in the life cycle as stated above.
Also as mentioned, the VC will be instantiated through initWithCoder, so calling an additional initialiser might be superfluous(?).
I encountered problems trying to use a custom initialiser that contains a call to super if I called it before the subview was added. I would just get a blank view added, I think because the superclass doesn't seem to know about the storyboard at that point. I had more success removing the call to super but that seems wrong.
This case would be more pertinent when adding subviews to a scrollview. For simplicity I left this out of my example.
I have a class that subclasses UIView called DrawView. This class contains custom drawing in the drawRect: method. I want to add this to a UIScrollView programmatically in a UIViewController class controlling the view which the UIScrollView has been added to. Also, I want the instance of DrawView to be a global variable.
I kind of confused and I am not really sure of anything, except that at some point I will have to call [scroller addSubview:drawViewInstance];. Thanks
Yes what you have written is correct. Also your subview should be a new class overriding the methods you need. You can maintain it globally by providing a method to return the instance more like a singleton.
Put the variable into the app delegate class. Alloc and init it and you can access it using the getter. Declare the variable in your delegate.
[UIApplication sharedApplication].delegate].globalInstance;
Its kinda weird but i am not able to call any method defined inside the class (having the drawRect method).
This is what i do inside a UIviewcontroller class with nib for UI:
-(void)viewDidLoad {
[self.lineVar Start];
}
lineVar is an object of the class (which is a subclass of UIview) which has the function Start.
-(void)Start {
NSLog(#"Hi...");
}
I never see the log message.
I have assigned the Class with Start method to a view which occupies some part of the screen with the UIviewcontroller class with the nib file.
I want a method to be called everytime the view (subclass of uiview) is visited.
It only has awakeFromNib which is called just the first time. viewdidLoad would have done the trick but its not there by default.
Thanks
Make sure self.lineVar isn't nil when you call Start. If it's failing silently, that's probably the issue. You may have forgotten to connect the lineVar outlet in your NIB.
hope someone can help me on this as been stuck for hours.
I am trying to make a kind of picture book.
I have a view which is my container and I add subviews to that by using addsubview.
On the subview, I have swipe gestures etc that I want to trigger off method in the parent view. I worked out how to trigger the delegate but I cant get the delegate to trigger the parent view. I have read over 10 different ways of doing it and none work.
I now very confused about what a super view is to. Just to confuse matters, the delegate has a tabcontroller and the parent view is tab button 1
I tried
[self.view.superview method]
[self.superview method]
On the delegate I tried
self.tabcontroller.parentviewcontroller, selectedview, super view.super
UPDATE :
The subview needs to be independant of the parent view as its a reusable view.
Also I have not set the parentview to superview as I just thought a superview is a view with subviews (please don't kill me). So maybe I just need to set the parentview to a superview?
The proper way of doing such things is to use protocol and delegate pattern.
Define a protocol like
#protocol subViewDelegate
-(void)somethingHappened:(id)sender;
#end
then implement that protocol in your superview :
#interface superView:UIViewController<subViewDelegate> {
...
}
...
#end
define a delegate property in your SubView like this
#interface subView : UIView {
id<subViewDelegate> delegate;
...
}
#propery (nonatomic, assign) id<subViewDelegate> delegate;
...
#end
the in your subview, call the delegate like this
[self.delegate somethingHappened :self];
It's a little hard to help you without any code given, but let's try:
Create a protocol: Name it however you like (I will call it "MyProtocol") and add to it the definition of the function you want to call in your superview, let's call it "respondToSwipe"
If your superview is a UIView, you have to create your own subclass of UIView and make your superview an instance of that class.
Let your (newly) created superview class implement the protocol of 1.) an implement the "respondToSwipe" method
Create an instance variable of the the type id in your subview, and name it however you like, e.g. "myDelegate".
Pass the superview created in 2/3.) to your "myDelegate" variable
Call [myDelegate respondToSwipe] whenever you like
For a custom view, you could subclass UIControl and use control events:
Define some control events. You're free to make up 4 control events (UIControlEventApplicationReserved = 0x0F000000)
Have whoever wants to receive events call addTarget:action:forControlEvents:
Have the control call [self sendActionsForControlEvents:events]
Alternatively, you could use a UIGestureRecognizer-style interface (addTarget:action:).
Alternatively just use UIGestureRecognizer (OS 3.2+)
Did your parent view set itself to be the superview of the subview when it added the subview? Otherwise the subview doesn't know who its superview is.
The more standard way of naming things to call the method handler the delegate instead of the superview, make it a property, and have the subview check for both the existence of the delegate being set and whether it can handle the method.
Here a very good example of how apply the delegation pattern on the iPhone. I downloaded the code an it works pretty good.
http://www.hivestudio.cat/index.php?option=com_content&view=article&id=57:technical-note-the-delegation-pattern-on-the-iphone&catid=35:technical-note-category&Itemid=76
Edited for brevity:
How does a subview access properties in its superview and its superview's view controller? Easy enough to go down the chain. How do we go back up?
Original (verbose) post:
The immediate problem I'm trying to solve is simplifying the "birth" of a somewhat complex view. The large picture has to do with Nibs and how subclasses (of UIView in particular) that have beyond trivial initializers are reconstituted when the view loads.
I have some custom UIViews - subviews of a subview of my viewcontroller's view. When I instantiate these views in particular they need a reference to some properties (NSNumberFormatter, & NSDictionary) of the View Controller.
Currenty I use a method to instantiate them:
- (id)initWithFrame:(CGRect)frame items:(NSDictionary *)dictionary forEditingMode:(EditingMode)mode
I'm experimenting with moving them into a Nib to let them reconstitute themselves and running into basic design issues. One being I think I'm limited to initWithFrame as the default initializer?!? If so how can these objects look into the parent view controller and get a reference to the dictionary and some other properties?
Are there methods I could call within initWithFrame (similar to the ones that retrieve the UIApplication delegate) but would instead allow the child view to send methods to it's parent views and/or controllers?
Send in the MVC police, I'm sure I'm breaking something...
It should work the other way round.
The views only contain controls (text fields, etc.). The data lives in a model, and the view/window controllers mediate, accessing and setting the view controls values, synchronizing with the model.
OK, sometimes you may need to have a dictionary shared between the controller and the view. Then create a dictionary property in the view and set it in the awakeFromNib method of the nib owner.
You can set up outlets that get connected to the view's superview or view controller and pull out the info in awakeFromNib. You need to use awakeFromNib instead of init* because the connections won't be created until then.
FYI, if you instantiate via a Nib, your designated initializer is initWithCoder:, not initWithFrame: (but don't use either for this).
You should probably be doing this through the view controller manually just after the nib is loaded. This means that you will have to set the shared dictionary AFTER the view has been initialized. You might do it like so:
#interface MyViewController : UIViewController {
IBOutlet MyView* view1;
IBOutlet MyView* view2;
IBOutlet MyView* view3;
}
#end
#implementation MyViewController
-(void) viewDidLoad;
{
NSDictionary* sharedDict = //make the shared dictionary here;
view1.sharedDict = sharedDict;
view2.sharedDict = sharedDict;
view3.sharedDict = sharedDict;
}
#end