Swift - Set a UI element from outside - ios

I have this UIViewController
import UIKit
class UIViewController1: UIViewController {
#IBOutlet weak var someTitle: 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.
}
}
And I am trying to set someTitle when I instantiate it from another view controller:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
let stb = UIStoryboard(name: "Main", bundle: nil)
let vc1 = stb.instantiateViewControllerWithIdentifier("someSTBID") as! UIViewController1
vc1.someTitle.text = "My Title" // it fails here!!!!!
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The reason it fails at the line above is that I was trying to force unwrapping a nil optional, which is someTitle.
Please show me a way to set someTitle in this situation.

Your second UIViewController hasn't been loaded yet, so the someTitle IBOutlet will be nil. You got two options:
The easy one: you force the load of the second UIViewController, for example: vc1.view is enough and then you set it (I don't recommend this)
The proper one: you let the second UIViewController be responsible for setting its own title at the right time. If you need to pass the "My title", you can simply pass it via a function like configureVc(title: String), or by exposing a variable like var title: String, so on viewDidLoad of the second UIViewController you would someTitle.text = title.

Do you need it to go into the superclass viewDidAppear, because it should work if you put it into the superclass viewDidLoad(). I hope that helps you and future viewers.

Related

How to: User Add/Remove from array in other ViewController?

I have an empty userArray in viewController1 that will use Strings.
In a popup, viewController2, I want to have the possibility for the user to add or remove from this userArray.
I'm gonna use a textField for the user to add their string but what is an easy way for the user to see the contents of the array and remove from it?
How do I pass this data between the viewControllers, whilst making sure it gets saved, and what would you recommend me using for removing from the array?
Assuming you have a segue from viewController1 to viewController2, you can use segue.destination and set the segue.destination.userArray property to whatever you want.
If you don't have a segue, and what you are trying to do is have a model shared between view controllers, one thing you can do is make another class with a static property userArray and access it that way.
As for array removal, see https://developer.apple.com/documentation/swift/array/1641390-remove
Write your Array outside of your ViewController Class. Then you can access it from other ViewControllers.
Example:
//ViewController1.swift
import UIKit
var userArray = [String]()
class ViewController1: 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.
}
}
//ViewController2.swift
import UIKit
class ViewController2: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
userArray.append("A")
userArray.append("B")
userArray.remove(at: 0)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Swift3.0 I want to get object of AppDelegate

I wanna get object of AppDelegate.
This program can build but it will stop running with lldb error.
Maybe the problem is the dirrerence of Swift2.0 and 3.0.
My textbook is for swift2.0 but I am using xcode8.0 and Swift3.0.
Error is here.
let ap = UIApplication.shared.delegate as! AppDelegate
I used this page for fixing.
How do I get a reference to the app delegate in Swift?
import UIKit
class FirstViewController: UIViewController {
#IBOutlet weak var dataTextField: UITextField!
let ap = UIApplication.shared.delegate as! AppDelegate
override func viewWillAppear(_ animated: Bool) {
dataTextField.text = String(ap.cmValue)
}
#IBAction func tapInpu() {
dataTextField.resignFirstResponder()
if let text = dataTextField.text{
if let cmValue = Double(text){
ap.cmValue = cmValue
}
}
}
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.
}
}
If you remove ap initialization and ap.cmValue = cmValue, does it works ?
If it does work check your outlet referencing in your storyboard you may have old non existent references

Cannot unwrap optional value to label

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

UIscrollview delegation

I am trying to pass data between my two view controllers in my UIscrollview. I am trying to use delegation to send data between Viewcontroller1 and Viewcontroller2. The delegate is Viewcontroller, while the delegator is Viewcontroller1 and Viewcontroller2.
In the code posted below, when the switch in Viewcontroller1 is toggled, it makes the switch in Viewcontroller2 put to the "off" state. I keep on getting the
fatal error: unexpectedly found nil while unwrapping an Optional value
error when I run it, but I have no clue what is causing this problem. Any ideas why?
Below is the Viewcontroller that contains the Uiscrollview and the subviews/childviews
import UIKit
class ViewController: UIViewController, testing {
var vc1 = ViewController1(nibName: "ViewController1", bundle: nil)
var vc2 = ViewController2(nibName: "ViewController2", bundle: nil)
#IBOutlet weak var scrollView: UIScrollView!
func test1() {
vc2.switch2.on = false
}
override func viewDidLoad() {
super.viewDidLoad()
self.addChildViewController(vc1)
self.scrollView.addSubview(vc1.view)
vc1.didMoveToParentViewController(self)
var frame1 = vc2.view.frame
frame1.origin.x = self.view.frame.size.width
vc2.view.frame = frame1
self.addChildViewController(vc2)
self.scrollView.addSubview(vc2.view)
vc2.didMoveToParentViewController(self)
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width * 2, self.view.frame.size.height);
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
here is the Viewcontoller1 code
protocol testing{
func test1()
}
class ViewController1: UIViewController {
var delegate:testing?
#IBOutlet weak var switch1: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
let vc = ViewController()
self.delegate = vc
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func switch1toggled(sender: AnyObject) {
delegate?.test1()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
and here is the Viewcontroller 2 code
import UIKit
class ViewController2: UIViewController {
#IBOutlet weak var switch2: UISwitch!
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 switch2toggled(sender: AnyObject) {
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
sorry for the long post, I have been stuck for a week on how to change the state of another switch from toggling a switch in another class, and this was the most efficient way that I found
Try This:
ViewController1
class ViewController1: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
let switch1Key = "view1Switch"
override func viewWillAppear(animated: Bool) {
view1Switch.on = defaults.boolForKey(switch1Key)
}
#IBOutlet weak var view1Switch: UISwitch!
#IBAction func view1SwitchChanged(sender: UISwitch) {
defaults.setBool(view1Switch.on, forKey: switch1Key)
}
}
ViewController2
class ViewController2: UIViewController {
let defaults = NSUserDefaults.standardUserDefaults()
let switch1Key = "view1Switch"
override func viewWillAppear(animated: Bool) {
view2Switch.on = defaults.boolForKey(switch1Key)
}
#IBOutlet weak var view2Switch: UISwitch!
#IBAction func view2SwitchChanged(sender: UISwitch) {
defaults.setBool(view2Switch.on, forKey: switch1Key)
}
}
This method syncs the state of the two UISwitches using viewWillAppear and NSUserdefaults. The basic thought pattern is that you save the state of the switch to NSUserdefaults so that when either ViewController1 or ViewController2 is instantiated the view1Switch or view2Switch outlet's .on property is set to the saved value.
Caveats:
The first value for the switch when ViewController1 is instantiated (in the first app run) will be off because boolForKey returns false when there is no saved value. This can be hacked by using view1Switch.on = true directly after view1Switch.on = defaults.boolForKey(switch1Key)
This method makes the switches have the same value. In order to make them have different values, you can use a ! operator like so in ViewController2 view2Switch.on = !defaults.boolForKey(switch1Key). This way switch 1 will always be the opposite of switch 2.
I recommend this method over delegation because, while delegation is powerful, its power doesn't seem needed here.
If you have any questions please ask! :D

Delegate Not Called In SWIFT iOS

I am Created 2 Views, One is and Used Protocol and Delegate. For first view the Delegate function is not called.
My FirstView Controller : Here I am Accessing the Delegate Function.
import UIKit
class NextViewController: UIViewController,DurationSelectDelegate {
//var secondController: DurationDel?
var secondController: DurationDel = DurationDel()
#IBAction func Next(sender : AnyObject)
{
let nextViewController = DurationDel(nibName: "DurationDel", bundle: nil)
self.navigationController.pushViewController(nextViewController, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
secondController.delegate=self
}
func DurationSelected() {
println("SUCCESS")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
My SecondView Controller : Here I Am creating Delegate.
import UIKit
protocol DurationSelectDelegate {
func DurationSelected()
}
class DurationDel: UIViewController {
var delegate: DurationSelectDelegate?
#IBAction func Previous(sender : AnyObject) {
//let game = DurationSelectDelegate()
delegate?.DurationSelected()
self.navigationController.popViewControllerAnimated(true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
To me, it looks like you're pushing a view controller that you haven't actually set the delegate for. If you change your "Next" function, to include the line
nextViewController.delegate = self
You should see that the delegation works. In doing this, you can also probably remove the creation of "secondController", as it looks like that's redundant.
The naming convention you have followed would confuse fellow developers in your team. The instance should have been
let durationDel = DurationDel(nibName: "DurationDel", bundle: nil)
And then as #Eagerod mentioned, the delegate you would set is
durationDel.delegate = self

Resources