Update UI from another controller - ios

I would like to update my UILabel on click the button of ContainerView contains table ViewController. When I try to do this UILabel's outlets reference shows nil value exception. I am using Swift3 with Xcode8

Most probably the problem you are seeing is due to the fact that the view that owns this label on another view controller is still not loaded.
This happens often, basically because views owned by a view controller are instantiated in a lazy manner, this means that they are loaded only when required.
To fix that before setting the value on the label, just preload the view by doing something like.
_ = another_viewcontroller_instance.view
In this way you are forcing the destination view controller to load the view and creating all the necessary connection on the xib.
Even if this fix works, this is not a good way to deal with this kind of pattern (sending info from a VC to another), but since you didn't gave us any further detail this is the only solution I have.

Related

Reusing view on different scenes in IB or programatically

I've a view which I want to reuse on other scenes in IB. This view contains user details such as name, avatar, description, few buttons etc. These views are exactly same and have same elements inside them. Right now it's pain to copy them across scenes, fix the constraints and then code the same elements over and over again. It's not quite productive and it's time consuming. Ideally I want to see these views on IB so I don't want to code do everything programmatically without any visual. Is there a way we can make it in better way so that I can just reuse it?
Not only is it pain, it is poor design to rebuild the same component. I would create a xib file, create the backing swift or obj-c files. Wire up all the outlets as you would normally.
In each view controller or view that you need it, initialize it and add it as a subview.
In swift, I would do something like:
if let subview = Bundle.main.loadNibNamded("SpecialView", owner: self, options: nil)?.first as SpecialView {
// set constraints
containerView.addSubView(subview)
}
Yes you can. I've done this recently. I started in a VC that was a child of a NavigationController and pushed a view onto the view stack that was outside of the NavigationController's scope so the new view did not have the NavigationBar up top.
Assuming you are using a storyboard, you'll create the view with all of it's actions and outlets and link them up to its own class file. Also give the storyboarded view an ID. Then you need to define the controller as a constant and push it to your view stack when you want it used.
// define the controller
let controller = self.storyboard!.instantiateViewController(withIdentifier: "YourCustomControllerID") as! YourCustomController
// if you want to pass data to the new controller
// first you must define some class variables in that class then you do this:
controller.image = whateverImage
// then you push it to the stack like this
self.navigationController!.pushViewController(controller, animated: true)
To dismiss that view, you call dismiss(animated: true, completion: nil) in YourCustomController
Yes, there are a few.
Custom views are loaded as cnbecom said, using LoadNibNamed. Owner is a proxy class, meaning it just represents "anything". Owner is like a connection that is fitted but not made until you create the class, if that makes sense.
Another method is to create the custom view in code, but instead of having a separate nib, you just re-create the view and change the type in the main Xib/Container Xib. You will have to copy/paste the nib, and that's made easier by embedding it into a view before copying. Even with constraints, this method is easier. Hook up the outlets in the containing Xib.
Third is pure code. This is one primary reason constraints are just extra work, no benefits.
Fourth, is to load the Nib but inside a container. Basically it loads itself into its own type via the AwakeFromNib method. You then have to hook up the outlets to the inner Xib realizing that Owner changed. This method is useful if you can visualize what is inside the white square.
Also I never use constraints. The few times it would be helpful, it's still faster to write a basic single-line of frame x,y code in layoutSubviews or similar. Custom views and manually using layoutSubviews will save you lots of time. Springs and struts are extremely powerful, and iOS lacks the CSS media queries for full layout-changes, just has ways to move constraints around (which modifies existing layout, not helpful if changing menu entirely for two different device types).
Create different xibs for tablet, then write a loading func that tests if on tablet and appends a prefix, will give you an amazing system once you get custom loading down.
Anyway, enjoy! I believe this question is a slight duplicate, as your marker was the frustration with auto-layout, but your real question is "How do I load custom views in Swift", which has been answered many.
There are two ways to that:
Programatically (or writing code might be involved)
create a custom view and include all the interface setup you need including the data and add it to each controller you want it to be shown
Take the advantage of Container view for loading the other content in another controller as in this Github repo
Here is what I did in the second example:
Create a base controller that holds the view that I want to always be shown
Add a view and customize it as required
Add a Container View in the same controller
Add a NavigationController and embed it in the Container View

Whose View is not on hierarchy

I am getting this error from swift and I am unsure why there is only 1 view controller that actually has this occurring the error is whose view in not on the hierarchy. My question is why would this occur for one of the view controllers presented from this primary viewcontroller button but not the other view controller linked from this primaryview controller? Is there something that could cause this to occur specifically. I am trying to present this modally and it is being called programmatically so that I can pass data objects.
For me it just seems very strange that this would occur for one viewcontroller presented from this viewcontroller but not the other. The only thing I did which I didn't think would effect this was duplicating the primary viewcontroller but again why would one work but not the other? The problem is specifically happening with iOS.
Should have checked the buttons to make sure they were linked correctly. I realized after reading a few of the same questions that I should check the button selectors under the view controller references tab to see what was linked to what. I had 2 actions doing 2 different things for 1 button by accident I must have miss clicked the control drag function.

Swift Changing View with performSegueWithIdentifier / programmatically

So I am trying to programmatically change views when some condition is triggered.
I have created a simplistic project, whereby I want to change to View 2 from View 1, once View 1 has loaded. In reality, there is some logical operation that checks if some variable is true, then it invokes the performSegueWithIdentifier function, however to keep this as simple as possible I have removed that code.
The steps I have performed are, firstly to create two views:
I then click View 1, and inspect its properties and then created a manually triggered segue to View 2
I selected the 'Show' option, so now my Views are connected by a segue
Then under attribute inspector, I give the storyboard segue and identifier of "GoToView2".
From there I go to the ViewController.swift file, and in the viewDidLoad function. I insert performSegueWithIdentifier code:
self.performSegueWithIdentifier("GoToView2", sender: self)
However, when I then run the code. View 2 does not load, and only View 1 appears in the simulator.
Any help and explanation would be greatly appreciated.
I have had the same problem with attempting to perform a segue inside the viewDidLoad function, and the error that comes up seems to be that the view you are attempting to load with the segue is not in the window hierarchy.
Changing the call to viewDidAppear seemed to fix the issue as mentioned in this other post: whose view is not in the window hierarchy (note the language is objective-c not swift, but it can be translated).
It seems you have to be careful at what point in the view lifecycle you want to change it to another view controller - at viewDidLoad all the views in the storyboard are not available.
BTW, without having a conditional in there, the segue will be fired (and load the view controller) every time the view is loaded!
I am working on a project that does exactly what you want to do. Perform segue with identifier is the right thing to do. My project also does the check in viewDidLoad.
All your steps look fine, so I believe it's a subtle issue. Check the identity inspector to see if you connected the view controller with view 1

Accessing a ViewController's subview that's added on the storyboard

Please see the image below for a storyboard visual. I have a ViewController called StudioViewController (It's labeled ViewController on the storyboard). And I have a UIScrollView that's called CanvasViewController (the thing to the right of the view controller that actually sits on top of the View Controller). I want to be able to access the CanvasViewController in the StudioViewController class, how do I do that? Because I created it in the storyboard here, I dont' seem to have a variable that allows me to access the CanvasViewController... Should I create it in code instead, or is there some obvious way to access it that I'm completely missing?
Thanks
******** UPDATE *********
The question has been answered in the comments below by rdelmar:
You could make a shared variable in the app delegate. This is not very secure but I have resulted to this when I can't access a child or parent due to page transitions.

Can a view be added to multiple other views safely, if so what does removeFromSuperView: do in that case?

I am wondering what happens if a single instance of a UIView object gets added as a subview of multiple other views simultaneously.
If UIView:removeFromSubview: gets called then does it get removed from all superviews or just the currently displayed one?
For background:
I have a status-bar like view object that needs to be displayed within several different other views (each other view is managed by its own view controller).
[i.e. a) the user is in one view, b) something happens to make the status-bar-like view appear, c) the user switches to another view d)the status bar is still visible in the new view e) the status bar expires after a time and disappears from site. And so on]
Initially I implemented this by adding/removing it as required as a subview of the window, and this was managed by a singleton.
However due to some complications with some animations I have instead added it as a subview of each of the main view's for each of the view controllers.
Note that there are not multiple copies
When the view needs to be removed I am calling its removeFromSuperview:, and everything is all working perfectly.
However I am wondering what the situation is regarding the removal of the view, is it being fully removed or is there something else I need to do?
For example the view might get added to N view controller's views by calling addSubview as required (it will only get added to each view controller if that view controller actually launches)
However when it is being removed I am only calling removeFromSuperview: for the view of currently loaded view controller, not all view controllers it might have been added to.
Next time I navigate to one of these other view controllers it displays fine without the view being there, even though I didn't explicitly call removeFromSuperView.
As I said everything is working as it is, however at the back of my mind I feel there might be something missing?
Hope this was understandable.
You can only have it added to one view. Documentation is your friend!
(void)addSubview:(UIView *)view:
Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.
From my point of view, having to add a same view to different parent views (and more important, from different view controllers) is an indication that something is wrong on the design...
However, if you really (really) need so, I had always thought that a view instance could have one and only one parent view... Moreover, you can access it by [myView superview] message, which gives you a UIView instance instead of an array... It may auto remove from its old parent before adding to a new superview?
About the design, what about creating it each time you need a new one and have a singleton to manage their status/logic?
Good luck with that!

Resources