Interface Builder outlets managing - ios

I want to create UIViewController subclass that will be container for two other controllers and it has properties
#property (nonatomic, strong) UIViewController *firstController;
#property (nonatomic, strong) UIViewController *secondController;
then i wanted to connect these properties via interface builder to instantiate them automatically. But if i just make them IBOutlets
#property (nonatomic, strong) IBOutlet UIViewController *firstController;
#property (nonatomic, strong) IBOutlet UIViewController *secondController;
i cant connect other controllers. but UINavigationController has property rootViewController and we can connect other controllers in IB. if it's possible to make such trick in custom controllers please help

You can't connect outlets from one controller to another controller -- outlets only work within a controller, not across controllers.
If you want a controller to be a container for two other controllers, you should drag two container views into your controller's view in the storyboard. You will automatically get two controllers connected to those container views with embed segues.

It should work the way you have it now. Are you sure you're adding View Controller objects in your XIB? Your UIViewController subclass xib file should look like this:
Then you should be able to right-click and drag the connections for firstController and secondController.

Related

Extend UIViewController's UI down to children UIViewControllers

I have a base view controller BaseUIViewController which is extended from UIViewController. I have two UIButtons at the bottom of this ViewController. Basically I want these two buttons on every UIViewController at the same place through out my app. When I extend BaseUIViewController, I don't see them in the children view controllers.
I have given IBOutlets to the buttons too!
I am new to programming. Please help. Isn't this way inheritance work?
You can create a UIViewControllerContainment. This Stackoverflow's post explains it in detail how you can create it and make it work. Similalry, also have a look at this Stackoverflow's post. Here it is done using childViewControllers.
Make sure you put these button properties in #interface instead of #implement, only properties in #interface can see in subclasses. Here is example:
#interface BaseUIViewController
#property (nonatomic, weak) IBOutlet UIButton *button1;
#property (nonatomic, weak) IBOutlet UIButton *button2;
#end
Both the ways which MUNAHIL answered above, are the best ones I believe. In case you want to achieve this in a more basic way, you can do as below.
Add the two UIButtons in the BaseUIViewController (either programmatically in viewDidLoad or in storyboard). In case you need, you may like to add a UIToolBar first and then the buttons on top of it.
Make other view controllers a subclass of BaseUIViewController.
#interface SomeViewController: BaseUIViewController
Now, all your view controllers will have the two buttons by default.

Adding an IBOutlet to custom class

I'm learning iOS and am new to the concept of IBOutlets - so I'm making a simple app in an attempt to learn how it works.
The problem:
I created an interface using a Storyboard and want to hook it up to an IBOutlet in my custom class ("TapCounter") in order to access (and be able to set) its text field. However when trying to hook my class' #property (nonatomic, weak, readwrite) IBOutlet UILabel* numberOfTapsTextField;
up to the UILabel in the Storyboard the line does not want to attach to the label.
Here is an image of the situation: http://gyazo.com/0050ef0a78772adcad214cdc4603f932 (Dragging a line from the hollow circle next to the #property to the label in the Storyboard does not snap to it).
I have not modified anything of the boilerplate code except for that I added #import "TapCounter.h" in viewController.m
This feels like it should be a very simple thing - but again; I am new to this.
EDIT
Have I got this idea wrong? Should all IBOutlets be in the viewController of a view (and simply be accessed by other custom classes)?
It work like this:
create a CustomView class
add a view in you storyBoard
set class for this custom view as CustomView in identity inspector cmd+opt+3
Create an IBOutlate of your component inside customView
Link those component with respective outlet
Refer Image:

Xcode displays outlets from multiple projects

I have a Workspace in which there are two Projects. Both projects contain a ViewController with the same name, but with different IBOutlets. This all works fine while coding, but 'Interface Builder' gets confused.
An example of the situation:
The contents of both FGViewControllers:
-- MyApp1
#interface FGViewController : UIViewController
#property (nonatomic,weak) IBOutlet UIView *myApp1Outlet;
#end
-- MyApp2
#interface FGViewController : UIViewController
#property (nonatomic,weak) IBOutlet UIView *myApp2Outlet;
#end
When you now open Main.storyboard (either one), in the Connection Inspector both outlets are shown:
Is there a way to have Xcode only show the outlets that are located in the project of the storyboard you're editting?

programatiically creating views strong properties

Previously I've been creating my views with interface builder.
When creating views with storyboards or nibs I would connect my outlets. I understand that the outlets are creating a strong connection to the properties on the view.
If I am creating views programmatically should my properties be strong?
.h
#interface LoginViewController : UIViewController <UITextFieldDelegate>
#property (nonatomic, strong) UIView *loginView;
#property (nonatomic, strong) UITextField *usernameTextField;
#property (nonatomic, strong) UITextField *passwordTextField;
#property (nonatomic, strong) UIButton *signInButton;
#end
.m
#interface LoginViewController ()
#end
#implementation LoginViewController
- (void)initViewsAndLayout
{
_loginView = [[UIView alloc] init];
_loginView.frame = self.view.bounds;
[self.view addSubview:_loginView];
//...
}
#end
A few things:
Your code isn't using the properties you defined
Don't put the private properties in the .h file
Don't state that your class conforms to the UITextFieldDelegate protocol in the .h file
As for whether the properties should be strong or weak I prefer strong but since you will be adding each of these properties (views) to the view controller's view, it would be fine to make them weak since there will always be a reference to them as long as the view controller is alive.
Your .h should just be:
#interface LoginViewController : UIViewController
#end
Your .m should be (assuming you do want to use the properties):
#interface LoginViewController () <UITextFieldDelegate>
#property (nonatomic, strong) UIView *loginView;
#property (nonatomic, strong) UITextField *usernameTextField;
#property (nonatomic, strong) UITextField *passwordTextField;
#property (nonatomic, strong) UIButton *signInButton;
#end
#implementation LoginViewController
- (void)initViewsAndLayout
{
self.loginView = [[UIView alloc] init];
self.loginView.frame = self.view.bounds;
[self.view addSubview:self.loginView];
//...
}
#end
When you use the strong attribute, you are basically writing retain, as in, you want Objective-C to allocate memory for the property and hold it until it is released.
That is all strong means.
This is only necessary if you are using ARC (though you can still use retain in ARC). If not, use retain.
"If I am creating views programmatically should my properties be strong?"
If they are objects and not primitives, then yes.
I recommend you to make properties with strong attribute if you want to create it manually not to use xib or storyboard.
As your code in initViewsAndLayout, if you always create a subview and add it to a view of a viewcontroller simultaneously in same method scope, there is no problem even if you use weak or assign attribute. addSubview will increase a reference count of the subview. But, I don't think it's such a good habit because all of us could make a mistake.
Therefore, you had better make a property of UIView with strong attribute.
You asked:
If I am creating views programmatically should my properties be strong?
Two part answer:
The view controller should definite maintain a strong reference to its top level view.
When not using NIBs or storyboards at all and doing everything programmatically, the root view is instantiated in loadView and generally stored in a retain/strong property. UIViewController already has a view property that bears the retain memory semantics, thats generally used. (For more information about programmatically created views, see the Creating a View Programmatically section in the Resource Management in View Controllers chapter of the View Controller Programming Guide for iOS)
(If you're not creating the root view in loadView and are instead instantiating the root view with a NIB or storyboard and are only programmatically creating the subviews, don't worry about the above discussion, as the NIB/storyboard takes care of all of that for you.)
For the subviews, when you call addSubview, the view is retained by its parent view. It's unnecessary for the view controller to also maintain strong reference to it as well. You can, but it is not necessary.
In my mind, the view owns its subviews, not the view controller. If one of these subviews is removed from its parent view, I don't think the view controller should be retaining it and it doesn't seem like good design that I have to remember to nil the property in the view controller, too. Worse, if I remove a container view that has nested subviews, I don't want to have to manually keep track of setting all of those individual properties in the view controller that I have to nil, as well.
Don't get me wrong: You can use strong with the subviews if you want/need. But I think it's incorrect to imply that it's ill-advised to use weak.
As a simple rule of thumb,
Any view is always owned (maintained by strong reference) by its
superview, when they are added to the superview.
A top-level view is always owned (maintained by strong reference) by its VC.
Now, a view can be added to its superview in two different ways,
When a view is created from code and added to some superview using addSubview: method. (This is what your question suggest).
When the view hierarchy is loaded from a nib file. (Here also implicit addSubview: calls are made by UIKit to create the hierarchy) and thus subviews are retained by strong reference their respective superviews.
So in either cases views are implicitly retained by their superviews and thus never get disposed until/unless the top-level view gets disposed by itself. So declaring strong properties for subviews imposes another ownership on the subviews:
An implicit ownership by its superview, and
An explicitly ownership by the property.
So in general, declaring strong property for subviews are not required, however it has been created (from nib / by code).
However, under some special situation declaring strong properties for views might be required. For example, when a view should be removed and re-added to its superview, the view should be declared as strong. When such a view is removed from its superview, the superview releases its ownership as well. So if we need to maintain a strong reference of that view if we need to reassign the same view again to some superview. In that case, a strong property reference to the view becomes handy and it disallows the view to be released.
PS:
When creating views with storyboards or nibs I would connect my
outlets. I understand that the outlets are creating a strong
connection to the properties on the view.
I found that there's merely a misconception, in your question. When creating view from storyboard/nib, outlets does not create any so-called strong connection with the properties. IBOutlets only describe how a property loads a view. In case of an outlet property, the view pointed by the property is unarchived and loaded if it has not already been loaded. However, its retention still depends on the strong/weak property accessor.

iOS Storyboard - Custom Outlet from a ViewController to another?

I am trying to implement something similar to AplitView where you can hace separate scenes in storyboard and connect a viewController to another one as an outlet. Is this possible?
#Interface MenuNavigationController : UINavigationController
#property (nonatomic, strong) IBOUtlet MenuViewcontroller *menuViewController;
#end
In interfaceBuilder I want to drag and drop, and assign another viewController to my outlet
Xcode won't allow you to make connections between different scenes in a storyboard. It does allow such connections for the container view controllers that it knows about, like UISplitViewController, but not for your own. See Linking child view controllers to a parent view controller within storyboard for some useful ideas on this topic.

Resources