I am new to Xcode and Swift so I don't know much about how it all works, but I am trying to make a pop-up view. I want a small view to pop up when I click a button. The view is a View Container (I don't know if that is the best way to do this so if not please tell me a better way to do this) and it starts out hidden then when I click a button it becomes visible. This View Container also has a button that if clicked, it will make the view hidden again.
Here is the code:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBOutlet weak var popUpView: UIView!
#IBAction func startButton(sender: UIButton) {
popUpView.hidden = false
}
}
import UIKit
class PopUpViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func prepareForSegue(segue:UIStoryboardSegue,
sender:AnyObject?)
{
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
#IBAction func backButton(sender: UIButton) {
ViewController().popUpView.hidden = true
}
}
When I run the app it starts fine because the start button is there and when I click it the pop up shows up but when I click the back button it gives me an error which says that in the console
Unknown class MKMapView in Interface Builder file.
fatal error: unexpectedly found nil while unwrapping an Optional value
and in line 31 ViewControler().popUpView.hidden = true
it says Thread 1: EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP, subcode=0x0)
Can someone help. Thanks
Access popUpView variable from didPrepareForSeque method (this method gets called automatically when you segue to another view). Problem is that if you try to set value to soon (meaning, that button is not drawn on view), you will get nil error. Here is a little workaround. You use temporary variable (tmpValue) to store state of your button (to be hidden or not), so when viewDidLoad, you method will read this value and set button to hidden state as you intended.
In ViewController class declare temporary variable (must be optional):
var tmpValu:Bool?
Then in your PopUpViewController class remove this line from backButton action:
ViewController().popUpView.hidden = true
Instead, you will use prepareForSegue method, like this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationViewController = segue.destinationViewController as! ViewController
destinationViewController.tmpValu = true
}
Now, back in ViewController class in viewDidLoad add this code:
override func viewDidLoad() {
super.viewDidLoad()
if let value = tmpValu {
popUpView.hidden = value
}
}
Related
I am new to this board. Please, excuse my bad english in advance.
I am trying to send a string from a subview to his parent view. If I try to set that string to a label, my app crashes with the message "unexpectedly found nil while unwrapping an Optional value".
Example code from the subview:
class TableViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blueColor()
sendDataToVc("test")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func sendDataToVc(myString : String) {
let Vc = ViewController()
Vc.dataFromContainer(myString)
}
Example from the parent view:
class ViewController: UIViewController {
#IBOutlet weak var label1: UILabel!
var cacheStr1 : String!
var cacheStr2 : String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
label1.text = ""
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func dataFromContainer(containerData : String){
label1.text = cacheStr1
}
#IBAction func changeLabel(sender: AnyObject) {
}
I have no more ideas what I am doing wrong. Thank you for your help.
The problem is this line:
let Vc = ViewController()
You are creating a new instance — a new ViewController instance. That's not what you want to do. You want to get a reference to an existing instance — the one that is your view controller's parent view controller, if that's what a View Controller is in relation to your TableViewController.
You better instance your ViewController form StoryBoard and define what you want to pass as property, and then set this property to the value that you need to show, and in the viewDidLoad of your ViewController update your view as you need
I have two view controllers. In the first one i have label and 4 buttons representing a color, and a button called next. I want to accomplish that when a user selects a color in the first view controller and clicks next, that the label in my next viewController will automatically have that color.
This is what i have so far but i can't make it work.
import UIKit
class ViewController: UIViewController {
var backGroundColor = UIColor()
#IBOutlet var face: UILabel!
#IBAction func red(sender: AnyObject) {
face.backgroundColor = UIColor.redColor()
}
#IBAction func green(sender: AnyObject) {
face.backgroundColor = UIColor.greenColor()
}
#IBAction func blue(sender: AnyObject) {
face.backgroundColor = UIColor.blueColor()
}
#IBAction func yellow(sender: AnyObject) {
face.backgroundColor = UIColor.yellowColor()
}
#IBAction func next(sender: AnyObject) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("face") as! Face2
vc.newFace.backgroundColor = self.face.backgroundColor
self.navigationController?.pushViewController(vc, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
// My Face2 class:
import UIKit
class Face2: UIViewController {
var backGroundColor = UIColor()
#IBOutlet var newFace: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// var vc = ViewController()
self.newFace.backgroundColor = backGroundColor
}
}
Welcome to SO.
You are making a common design mistake.
Don't try to manipulate the second view controller's views directly. That's bad design, and often doesn't work.
Instead add a property/properties to your Face2 class.
In this case, a backgroundColor property is probably all you need.
Set that property in your next function, and then in your Face2 class's viewDidLoad method, use the color to set the background color of whatever views need to use the custom color. If you decide later that the set of views that need to change color is different, you can change the code for your Face2 class and the first view controller doesn't need to change at all.
You also need to get rid of vc2. That makes no sense. You create a new Face2 view controller vc with a call to instantiateViewControllerWithIdentifier. That's the one you should be configuring. The one you create in vc2 is never used for anything. It will get deallocated as soon as you exit the next() function.
my suggestion is to set a nsstring (string that you set when you press the color button) property to second view controller and in the second view controller view did load make a switch based on the passed string to set the background color
I am a little confused on how to use container views correctly, i will try to explain it the best i can.
I have a main view controller that has an animation function.
import UIKit
class MainViewController: UIViewController,UIPickerViewDataSource,UIPickerViewDelegate {
// Run view setups
override func viewDidLoad() {
super.viewDidLoad()
}
func closePicker(){
self.view.layoutIfNeeded();
UIView.animateWithDuration(0.5, animations: {
self.countryPickerConst.constant = -206;
self.view.layoutIfNeeded();
})
}
}
In interface builder i have added a container view with a new view controller that contains a button like so:
import UIKit
class ContainerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func runAnimation(sender: UIButton) {
//I want to call the function in my other view controller
}
}
In the action runAnimation i want to call the function in the MainViewController. If i just create an instance of MainViewController and call the function it seems to loose its 'self' relevance.
If someone could explain to me the best practice for doing things like this that would be great.
Thanks
From your explanation MainViewController is the parent of ContainerViewController so to access closePicker from ContainerViewController you would do:
#IBAction func runAnimation(sender: UIButton) {
(self.parentViewController as! MainViewController).closePicker()
}
I have a very simple app so far. Two view controllers. I've set up a new .swift file for the second view. On each view I have a button that when pressed, changes a label to say "Pressed". Pretty simple.
On the first view controller everything works as expected. However, on the second view controller the app crashes when I press the button. I've set up IBOutlets and actions for all appropriate parts.
Does anyone have any insight?
code:
import UIKit
class PlayViewController: UIViewController {
#IBOutlet weak var newCardButton: UIButton!
#IBOutlet weak var labelTest: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func newCardButtonPressed(sender: UIButton) {
self.labelTest.text = "Pressed"
}
}
Screenshot:
Screenshot after crash- http://i.imgur.com/CHt8kA5.png
I think you should change the sender part like this.
#IBAction func newCardButtonPressed(sender: AnyObject) {
self.labelText.text = "Pressed"
}
If your connections are not set properly your app also crash. Delete them and reconnect it.From Utilities/connections inspector.
I'm programming a iOS app in Swift language and all I have to do is create a custom input for a textfield.
I created an additional View Controller with two buttons and what I want is this view controller (instead of the keyboard) to pop-up when I highlight my textfield.
Basically what I want is to create a small custom keyboard, but I just want it to be inside my app: I found lots of tutorials about creating custom keyboards, but it is not the same as having a simple View Controller that pops-up when text field is highlighted.
Can you suggest how to assign my view controller to textField.inputViewController in Swift?
Thanks
You can assign your own viewcontroller to inputViewcontroller:
Your viewController has to be a subclass of UIInputViewController for example:
class CustomInputViewController: UIInputViewController {
#IBOutlet var insertTextButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.inputView?.translatesAutoresizingMaskIntoConstraints = false
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func insertText(_ button: UIButton){
self.textDocumentProxy.insertText((button.titleLabel?.text)!);
}
}
Here with only one button insertTextButton which I design in the xib-file.
In your main view controller you need a subclass of your textfield (or textview):
class textfield: UITextField {
var _inputViewController : UIInputViewController?
override public var inputViewController: UIInputViewController?{
get { return _inputViewController }
set { _inputViewController = newValue }
}
}
which you assign to your textfield.
Now you can assign your own inputViewcontroller to your textfield, for example:
class ViewController: UIViewController {
private var customInputViewController = CustomInputViewController(nibName: "CustomInputViewController",
bundle: nil)
#IBOutlet var textField: textfield!
override func viewDidLoad() {
super.viewDidLoad()
self.textField.inputViewController = customInputViewController
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I used the xib-file with the name CustomInputViewController.xib to design the keyboard
As far as I know, you cannot use a view controller. You need to make your own view and assign it to the inputView field. Make sure the view has a delegate so it knows which field to use:
MyInputView keyboard = ...
field.inputView = keyboard
keyboard.delegate = field