I have a simple custom view that is connected via outlet to a NIB. For this particular view, there are actions that I would like to perform on the view when it is initialized, no matter what NIB it is on.
Trouble is, neither the (id)init or the (id)initWithFrame:(CGRect)frame methods are getting called on the custom view.
Which method gets called on a UIView when it is instantiated from a NIB? I would just use the view controller and viewDidLoad method except that this particular view appears on a lot of different NIBs.
You can use awakeFromNib for this kind of initialization. The regular initialization methods are called when the object is actually created by IB and then archived using NSCoding, so those methods are never called within your application. You could also override initWithCoder: which will be called, but I don't recommend it since other outlets may not be wired at that point.
Related
iOS newbie question: I have a UITableViewController with a navigation controller. I need to add an edit button to that controller. The table view controller is accessed from a tab controller. I have read several posts that suggest overriding the initWithNibName method. While this makes sense, I'm not understanding where/when this overridden method gets called or what I need to do force it to be called.
In other words, when I override this method, I get a successful build but the method never gets called and the code seems unreachable. What have I possibly left out?
Thanks!
if initWithNibName is not called, then your view controller is probably loaded from a storyboard file. In that case, you have to override initWithCoder: instead.
I have a root view controller which loads a custom UIView subclass I have created and adds it as a subview.
Inside this custom UIView subclass I code/generate a UIButton in the awakeFromNib method.
Is there a simple way to access the File Owner without creating a delegate if the UIButton's action method is inside the root view controller?
E.g
[myButton addTarget:[self.file_owner ?] action:#selector(methodInFileOwner:) ....
Using Interface Builder it's still easy to assign a UIView my custom UIView subclass and just drag a UIButton's selector reference to the file owner. Voila!
How is this done through code though? Do I have to create a delegate and use
[myButton addTarget:[self.delegate] ...
?
File's Owner is an Interface Builder concept. It doesn't exist on the programming side, basically, because it's not needed. In interface Builder, File's Owner is the class that instantiates the nib file. Often, it just refers to the class of the nib file you're currently working with. Since you're working with a view controller, the File's Owner is your view controller subclass, and it allows you to make connections to instance variables and methods of that class.
On the programming side, in this case, the equivalent of File's Owner would just be self. And, you access an instance variable, using properties, as self.instanceVariable.
On to your question. If you want the selector method to be in the view controller, that makes perfect sense. But then, the view controller can create the button, set its target/action, and add it as a subview to the custom view. You could do this in -viewDidLoad, which is called after the nib file is loaded and is the standard place where you would make any programmatic additions to the view controller. So, you could do it as follows:
- (void)viewDidLoad {
self.myButton = [[[UIButton alloc] initWithFrame:CGRectMake(x, y, width, height)] autorelease];
self.myButton.buttonType = ...;
[myButton addTarget:self action:#selector(actionMethod)...];
self.myCustomView = [[[MyCustomViewClass alloc] initWithFrame:...] autorelease];
[self.myCustomView addSubview:self.myButton.view];
[super viewDidLoad];
}
The above code is just an example. You can initialize your objects in different ways. In this case, the button would now be an instance variable of the view controller. But, you could just as easily leave it in the custom view and just refer to it as: self.myCustomView.myButton
I hope this is helpful.
Correction: The above code should be in viewWillAppear rather than viewDidLoad. When viewDidLoad is called, the geometry (i.e. the view's bounds) has not yet been set. So, in order to set the frame of any object, it must be done in viewWillAppear.
The target should be an object of the root view controller class. In your UIView subclass you will need a reference to your root view controller class.
If a nested widget is hidden from the controller, then that essentially means that the custom view should manage all aspects of that nested widget. Here are some options (and probably not a complete list of them either):
You could have the custom subview handle UIControl events and propagate them into the button. Your custom subview would implement the methods of UIControl and essentially hand them down to the button.
You could also use a delegate like you mentioned.
Or you could restructure it so that the widget hierarchy is flattened, but their display is nested.
If you plan on making a custom component that you reuse in multiple places, then the first and second options are probably better since they are more flexible. If this is not the case, the third option is probably best since there is actual interaction between the button and the controller.
The Delegates and DataSources section of the Cocoa Fundamentals Guide gives an example of what the code looks like to create delegates.
I have created an UIView in my iPhone app. I want to handle something when user closes or opens when UIView is present as current screen. I thought, i can do this under viewWillAppear:. But, viewWillAppear: is not called in UIView. Does it work only on UIViewController? How can i handle viewWillAppear: or viewDidAppear: for an UIView?
Update: UIView what I created everything through program, not in .xib.
Please advise.
Thanks!
From your message I infer that you wrote your viewWillAppear: method on the UIView class. As you suspect, that method is part of [UIViewController]1, not [UIView]2 therefore it only gets called on the UIViewController.
You should connect the property view of the UIViewController to the UIView object in the interface builder and then implement that method in the UIViewController.
If your view is created in response to an user action,
Update for your update:
You should tag the views either in code (view.tag=1) or IB.
Then you can do if (self.window.rootViewController.view.tag == 1) { ... } from your delegate (assuming you are looking for the view of the controller who is the rootController, otherwise post more details).
It's even better if you define constants on one place instead writing 1 as a literal.
These delegate methods are called every time the superview is presented to the screen and should be implemented in the UIViewControllers.
The gotcha is that these methods aren't called when subviews are presented on the screen, so your superview-view-controller will have to respond to these events accordingly.
You can find more information in this post here.
If you study the documentation for UIView and UIViewController what you will find is -(void)viewWillAppear:animated: is a method of UIViewController and not of UIView, so in order to use it, it must be implemented by subclassing UIViewController. Generally for best practice if you want to follow MVC, any functionality that does not pertain to the view itself should be delegated to the view controller and not be in the body of your UIView subclass.
Create a new view controller with xib file, and then link your custom view class to the view in your xib file.
EDIT 2: I now think the best soluton is to create ListeningView.h that just includes a ListeningView protocol, instead of subclassing ListeningView (since we can't do multiple inheritance in Obj-C). Then, you still need ListeningViewController as well.
EDIT: Ok, I figured out what the approved idiom is here. I should subclass UIViewController to create ResponderViewController, which will loop through its subviews for ResponderViews when it appears/disappears. Then, any viewController that has responderViews should inherit from ResponderViewController.
=======
UIViewControllers have viewWillAppear, viewDidDisappear, etc. delegate methods.
I would like to create a UIView subclass that can be added to a viewController's view, and when that UIViewController apears or disappears, a delegate function is called.
I could easily do this by putting function calls in the UIViewController viewWillAppear/viewWillDisappear delegate functions, but how can I encapsulate this behavior in the UIView?
I wouldn't do that if I were you. All that sort of behavior should not be controlled by a view; that's just was controllers are for.
I'm learning to develop for iPhone without Interface Builder (a personal preference), and I'm not sure which function of a view controller I should be setting up the view in: init, viewDidLoad, or loadView. I read somewhere to only use init for the view controller, if anything, and not setting up the view as it could cause problems. I also read that viewDidLoad is only for loading from nib files, but It worked when I tried using it.. so what stuff should I put in each of these 3 methods?
Thanks!!
Well each method has its own purpose
1) init
This method is intended to just initialize the ViewController , you are not required to override this method, but if you want to do some custom initialization BEFORE any views are loaded then this could be a place to do it. You have different flavors of the init methods, you can look at the in the docs at apple site.
2) loadView
this method here is used to programatically create your view. If this method is not overriden, the default w ill create an empty view for you, but if it is you MUSt initialize viewController.view property, this gets called when a UIViewController view gets pushed into a super view.
3) viewDidLoad
this method is called after you view has loaded on the screen (After loadView has been called and the view is pushed on the super view or window). Here you can do you can add subViews to your controllers views and also do other set up that you want to occur once your view loads. This method works regardless of making a view f rom a nib or programatically.