Error setting values for one VC for another VC - swift

I am trying to set the values of UILabel's on another view controller. However I keep getting a nil value when I am trying to set temp values for the other view controller's UILabels and such. This is the function that executes the segue:
func swipe(Sender: UISwipeGestureRecognizer!) {
print("swiped left")
let vc = self.storyboard!.instantiateViewControllerWithIdentifier("OnDeck") as! OnDeck
vc.firstBase = UIView(frame: CGRectMake(178, 136, 10, 10))
vc.firstBase.backgroundColor = UIColor.redColor()
vc.firstBase.layer.cornerRadius = vc.firstBase.frame.size.width/2
self.presentViewController(vc, animated: true, completion: nil)
}
I am getting the following error on the line vc.firstBase.backgroundColor = UIColor.redColor()
fatal error: unexpectedly found nil while unwrapping an Optional value
is there something I am missing when attempting to declare the temp values for the outlets?

You should not set those related UI elements, because the UI haven't loaded yet. Instead, pass a value and set it in viewDidLoad of destination controller
class OnDeck: UIViewController {
var color = UIColor.white()
override func viewDidLoad() {
...
firstBase = color
}
}
Then in your swipe method, pass the value only rather than modify the unloaded UILabel or UIView. Else, move the UI related code to the destination viewDidLoad() such as the cornerRadius, frame size, etc

Related

Swift sub view hold old values (stacking new values on top of it)

[solved :)
by adding self.progressScrollView?.removeFromSuperview() ]
I am new to swift.
and having below issue :( please help me.
every time I come back to this main screen (using back button)
my scroll view's content are showing new values on top of old values
for example.
I have 4 items(a,b,c,d) in an array.
and main page show in random order
a
b
c
d
after that, i went to another page and came back to this screen.
it shows new values on top of old values
a -> b (this value is on top of 'a')
b -> d (this value is on top of 'b')
c -> c (this value is on top of 'c')
d -> a (this value is on top of 'd')
what I did?
I re-initialize my array in viewdidappear()
added below in gotopage()
dismiss(animated: true, completion: nil)
add removefromsuperview & view.addsubview in self.displayProgressBar()
(what #sandeep suggested.. but doesn't work)
my flow:
1.call displayprogressbar in viewdidload
self.displayProgressBar()
class ViewController: UIViewController ,ChartViewDelegate, UIScrollViewDelegate {
...
var progressScrollView: UIScrollView!
...
override func viewDidLoad() {
super.viewDidLoad()
self.getfirebasedata()
2.add progress bars and labels dynamically based on the list size.
func getfirebasedata(...){
...
self.displayProgressBar(...)
}
func displayProgressBar(...){
self.progressScrollView?.removeFromSuperview() //this is the fix
self.progressScrollView = UIScrollView()
self.progressScrollView.isScrollEnabled = true
self.progressScrollView.frame = CGRect(x: 0, y: 300,
width: self.view.frame.size.width, height: 200)
self.progressScrollView.contentSize = CGSize(width: self.view.frame.size.width,
height: self.view.frame.size.height)
let axisXstartPoint = ( self.view.frame.size.width - 200 ) / 2
let progressView = UIProgressView(progressViewStyle: .bar)
...
let label = UILabel()
label.frame = CGRect(x: axisXstartPoint, y: CGFloat(axisY-15), width: 200, height: 20)
label.textAlignment = .left
label.text = book.bookName
label.isUserInteractionEnabled = true
label.addGestureRecognizer(tapBookName)
progressScrollView.addSubview(label)
progressScrollView.addSubview(progressView)
self.view.addSubview(progressScrollView)
}
when I go to another page I use this method
#objc #IBAction func goToAddPage(sender: UITapGestureRecognizer) {
let label = sender.view as? UIButton
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let addViewController = storyBoard.instantiateViewController(withIdentifier: "add") as! AddViewController
addViewController.modalPresentationStyle = .fullScreen
self.navigationController?.pushViewController(addViewController, animated: true)
dismiss(animated: true, completion: nil)
}
4.this is my storyboard
Not sure from where you call displayProgressBar as its not clear from your question, what you can do is add these statement as either 1st statment in displayProgressBar or as a statement before calling displayProgressBar
Approach 1:
self.progressScrollView?.removeFromSuperview() //? because for the first time implicit optional will be nil
self.progressScrollView = UIScrollView()
In ViewDidLoad you have self.view.removeFromSuperview() which I have no idea why? Makes no sense to me why would you try to remove ViewController's view? May be you were trying to remove subviews I assume, if yes, thats not the proper way to remove subviews, you iterate over subViews and call removeFromSuperview on each subView, but I dont think you need that, clearly from your code you hold a reference to progressScrollView somewhere in your code, just remove it from subview and recreate the progressScrollView as
progressScrollView = UIScrollView()
And if you are not holding a reference to progressScrollView and instead you were creating it as only local variable in displayProgressBar method, hold a reference to this view, to do that declare a instance variable var progressScrollView: UIScrollView!
Approach 2:
And if you dont prefer creating progressScrollView() again and again, you can always iterate over its subviews and remove them from superview one by one
for view in progressScrollView.subviews {
view.removeFromSuperview()
}
Make sure you run self.view.addSubview(progressScrollView) only once (like in ViewDidLoad or somewhere) if you decide to go with approach 2.
In either case you need to hold a reference to progressScrollView

swift call a func from another viewcontroller

I would like to call a func from another viewcontroller.
here with the code in pubListViewController: It is working fine.
override func viewDidAppear(_ animated: Bool) {
navigationBarTitleImage(imageTitle: "IconTitle")
}
func navigationBarTitleImage(imageTitle: String) {
// 1
// let nav = self.navigationController?.navigationBar
// 2
// nav?.barStyle = UIBarStyle.black
// nav?.tintColor = UIColor.yellow
// 3
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
imageView.contentMode = .scaleAspectFit
// 4
let image = UIImage(named: imageTitle)
imageView.image = image
// 5
navigationItem.titleView = imageView
}
now I try to call it in another viewcontroller as below, but it shows nothing.
override func viewDidAppear(_ animated: Bool) {
pubListViewController().navigationBarTitleImage(imageTitle: "addTitle")
}
When you're using notation like that pubListViewController() you call free empty initializer of pubListViewController which creates new instance of class pubListViewController, but you do already have one in your screens flow I bet, so all changes made by function you're calling later are being applied to invisible instance of pubListViewController.
To solve this problem you need a reference actually displaying instance of pubListViewController from your another viewcontroller
In another viewcontroller you can create a property of type pubListViewController, then before showing another viewcontroller set its property to self, and use that property from wherever you want in another viewcontroller.
class PubListViewController: UIViewController {
func prepareForSegue(/**/){ // actually do that in the place where you showing your another viewcontroller, I don't know if you're using segues or not
destinationViewController.parentPubListViewController = self
}
}
class AnotherViewController: UIViewController {
// declare property (weak and optional to avoid crashes or memory leaks if you forget to set that property from parent view controller
weak var parentPubListViewController: PubListViewController?
// use it anywhere you need
parentPubListViewController?.navigationBarTitleImage(imageTitle: "addTitle")
}

SIGABRT when adding a constraint to a uiview

Once again auto layout has me scratching my head. I define a UIView and UITextField at the top of my class:
var urlField = UITextField(frame: .zero)
var barView = UIView(frame: .zero)
I call my configuration method from viewWillAppear (so I know that self.view is all set):
override func viewWillAppear(_ animated: Bool) {
configureURLBar()
}
And I'm doing nothing special there.
func configureURLBar() {
barView.translatesAutoresizingMaskIntoConstraints = false
barView.topAnchor.constraint(equalTo: self.view.layoutMarginsGuide.topAnchor).isActive = true
barView.heightAnchor.constraint(equalToConstant: 30).isActive = true
}
When it gets to the topAnchor constraint I get the exception, and I don't understand why. If I reverse the 2nd and 3rd lines it doesn't blow up until it gets to the .topAnchor line, so that's the problem. I can ask a second question once I understand the reason for this exception (in case you're wondering what I'm trying to do): how do I add a user input (url) bar at the top of my UIWebView. (that didn't work either - same results if I try to constrain against my self.webView which is displaying perfectly) Also: I call self.view.setNeedsDisplay() before viewWillAppear() is called.
You have to add your view to parent view first. After that you can add constraints.
Try this:
override func viewWillAppear(_ animated: Bool)
{
self.view.addSubview(barView)
configureURLBar()
}
Include your logic in viewDidLayoutSubviews instead of in viewWillAppear...
viewDidLayoutSubviews is a much better place to handle geometry

UILabel Swift/Storyboard returns nil

I created a navigation controller with a view controller inside, containing a label. This label should be changed, when the view controller is loaded on tapping a button.
class ViewController: UIViewController {
#IBOutlet weak var btnEmergency: UIButton!
override func viewWillAppear(animated: Bool) {
self.btnEmergency.backgroundColor = UIColor.redColor();
}
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func btnEmergencyTapped(sender: AnyObject) {
let emergencyViewController = storyboard?.instantiateViewControllerWithIdentifier("EmergencyViewController") as! EmergencyViewController
emergencyViewController.emergencyLabel?.text = "Notruf"
navigationController?.pushViewController(emergencyViewController, animated: true)
}
}
But the label text does not change when loaded. I am relatively new to SWIFT so I try to learn my ropes at the moment using optionals. So I guess the reason is, that the label is not yet instantiated when the view is being loaded on pressing the button. Therefore the default text is being shown and not the text I want to have appear on screen.
I am a little bit stuck at the moment, how to correctly change the label text, when this is an optional. So I guess I cannot expect the label to be there, when I call it. But how do I handle this correctly?
Instead of this, the correct way is to set a property of your emergencyViewController.
In your emergencyViewController viewDidLoad set your label text according to the property set previously.
Anything that you do between initialize of a viewController to viewDidLoad will not take effect.

Trouble setting the frame for a custom camera overlay using Swift

As the question states, I'm having trouble setting the view frame for my custom camera overlay using the Swift language. I keep getting an error that states "value of optional type "CGRect" not unwrapped" that I don't quite understand. The problem line is this one:
cameraOverlay.frame = camera.cameraOverlayView?.frame
Xcode attempts to auto-correct the issue by adding a bang (!) at the end of frame, but that does not work either, and creates another error.
Here is my entire nib initialization code for my custom camera overlay:
#IBOutlet var cameraOverlay: UIView!
override func viewDidLoad()
{
super.viewDidLoad()
var camera = UIImagePickerController()
camera.delegate = self
camera.allowsEditing = false
camera.sourceType = UIImagePickerControllerSourceType.Camera
camera.showsCameraControls = false
NSBundle.mainBundle().loadNibNamed("CameraOverlay", owner: self, options: nil)
cameraOverlay.frame = camera.cameraOverlayView?.frame
camera.cameraOverlayView = cameraOverlay
cameraOverlay = nil
self.presentViewController(camera, animated: false, completion: nil)
}
Any help is appreciated. Thanks!
EDIT
Make sure your nib view does not have a white background, or else the camera will not appear. Set the view background color to clearColor, and make sure opaque is unchecked to be safe. I had this problem for a little while until I realized what was happening.
Use this
cameraOverlay.frame = camera.cameraOverlayView!.frame
Actually you are using ? optional chaining which returns frame as wrapped in optional.! is used for optional unwrapping
or you can also do
//it will not crash but you should handle nil case using unwrap by `!` as shown above using `if` condition
cameraOverlay.frame = (camera.cameraOverlayView?.frame)!