Fatal Error while call method from another class - ios

I have two view controller.
I have one test method in first view controller as follow
class ViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
myLabel.hidden = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func showLabel(){
myLabel.hidden = false
}
}
If i call showLabel from another class it give me fatal error: unexpectedly found nil while unwrapping an Optional value
Another viewController is as follow
class SecondViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func Save(sender: AnyObject) {
ViewController().showLabel()
}
}
If i call showLabel Method from ViewController the its works fine but if i call it from SecondViewController then i got error.

Both your view controllers use storyboard/xib; when you create such view controller instance in code (as you do in Save function) you need use UINib class or instantiateViewControllerWithIdentifier method of UIStoryboard class, since default initializers (like init() you used for ViewController) know nothing about outlets and storyboard/xib associated files (outlet property myLabel will always be nil).
If your code not just template, then you should refactor it, because performing UI changes in view controller that not presented on screen (and never will be) not have sense

It's because your label "myLabel" is always nil.
Your label is part of your first ViewController. The label loads when the view loads. Since the ViewController view has not loaded, the label has not loaded either, and therefore will be nil

You need use delegate:
1-Creat a protocol with a function describes with you are planning to do.
protocol ViewControllerDelegate: AnyObject {
func showLabel()
}
2-Add a delegate in your SecondViewController with the type if the protocol ViewControllerDelegate.
class SecondViewController: UIViewController {
weak var delegate: ViewControllerDelegate? // add delegate
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func Save(sender: AnyObject) {
delegate?.showLabel() // call the method from delegate
}
}
3-Implement the ViewControllerDelegate in your ViewController.
class ViewController: UIViewController, ViewControllerDelegate {
3-Set the delegate in the first view controller inside prepareForSegue:
class ViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
myLabel.hidden = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func showLabel(){
myLabel.hidden = false
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let viewController = segue.destinationViewController as? SecondViewController {
viewController.delegate = self
}
}
}

just add class before function:
class Math{
class func addition(numberOne: Int, numberTwo: Int) -> Int{
var ans: Int = numberOne + numberTwo
return ans
}
}
Then you can call it from another Swift class like this:
Math.addition(40, numberTwo: 2)
To assign it to a variable i:
let i = Math.addition(40, numberTwo: 2) // -> 42

Related

Delegate without performSegue not getting called Swift 5

My protocol (where "VehicleRegVCs" is enum):
protocol VehicleRegVCDelegate: class {
func presentedVC(_ currentVC: VehicleRegVCs)
}
My Buyer Class:
class BuyerOwnerInfoViewController: UIViewController {
weak var delegate: VehicleRegVCDelegate?
override func viewDidLoad() {
super.viewDidLoad()
delegate?.presentedVC(.buyerOwnerInfo)
}
}
My Main class (where delegate function "func presentedVC" at the bottom not getting called):
class VehicleRegContainerViewController: ICTViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
func setupView() {
let buyerVC = getBuyerOwnerInfoVC()
buyerVC.delegate = self
}
}
extension VehicleRegContainerViewController: VehicleRegVCDelegate {
func presentedVC(_ currentVC: VehicleRegVCs) {
}
}
I expect "presentedVC" to get called... I made a delegate too...
and in UIViewController extension i have made this function...
func getBuyerOwnerInfoVC() -> BuyerOwnerInfoViewController {
let vc = UIStoryboard.exciseAndTaxation.instantiateViewController(withIdentifier: "BuyerOwnerInfoViewController") as! BuyerOwnerInfoViewController
return vc
}
ViewController inside containerView are connected using segue. You can use prepareForSegue method to get the controller and assign the delegate to it.
NOTE: Go to storyboard and click on the segue connecting the container view and the view controller, and assign it an identifier. In below example i have used "yourSegueIdentifier", replace it with your identifier.
class VehicleRegContainerViewController: ICTViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let buyerVC = segue.destination as? BuyerOwnerInfoViewController {
buyerVC.delegate = self
} else {
print("Error in segue")
}
}
}

Delegate data from one UIViewController to another one

I am completely new to Swift programming and tried to delegate a single String from one ViewController to another by clicking a send button. The problem is , that it does not work ...
I guess it would be easy for you to solve this and considering that it would be very helpful wether you explain me what I did wrong. :)
Thank you a lot
import UIKit
protocol protoTYdelegate {
func didSendMessage(message: String)
}
class New: UIViewController {
#IBOutlet weak var SendButton: UIButton!
var tydelegate: protoTYdelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func SendButtonAction(_ sender: Any) {
let nachricht = "It works fine."
tydelegate?.didSendMessage(message: nachricht)
}
}
import UIKit
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let controller = New()
controller.tydelegate = self
}
}
extension ThankYouPage: protoTYdelegate{
func didSendMessage(message: String) {
numbersView.text = message
}
As far as I understand, this code block doesn't work but the problem is not in the code, it's actually way that you choose to send data. In iOS development, there are many ways to send data. In your case, you need to use prepareForSegue method to send data to new class, not necessary to use delegates.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "ThankYouPage") {
let vc = segue.destination as! ThankYouPage
vc.message = "Message that you want to send"
}
}
And you need to implement your ThankYouPage as:
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
var message = ""
override func viewDidLoad() {
super.viewDidLoad()
numbersView.text = message
}
}
In addition to that, you can use didSet method to print out the message to label instead of printing it directly in viewDidLoad method. Simply:
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
var message: String?{
didSet{
numbersView.text = message
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
I hope this helps you.
#Eyup Göymen's answer is right.
I have another way, assuming that you are not using segue and you are pushing to next controller by manual-code.
So your ThankYouPage code should be like :
import UIKit
class ThankYouPage: UIViewController {
#IBOutlet weak var numbersView: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func someButtonAction(_ sender: Any) { // By clicking on some, you are opening that `New` controller
let detailView = self.storyboard?.instantiateViewController(withIdentifier: "New") as! New
detailView.tydelegate = self
self.navigationController?.pushViewController(detailView, animated: true)
}
}
extension ThankYouPage: protoTYdelegate {
func didSendMessage(message: String) {
numbersView.text = message
}
}

Swift Protocol Delegate return nil

protocol testDelegate: class {
func open(channel: String, vc: UIViewController)
}
class test: UIViewController{
weak var delegate: testDelegate?
}
override func viewDidLoad() {
super.viewDidLoad()
if self.delegate != nil {
print("hello")
self.delegate?.openGroupChannel(channel: channel!, vc: self)
}
that is Class Test! protocol init in Test class as well
class calling:testDelegate{
override func viewDidLoad() {
//blah blah
}
func func open(channel: String, vc: UIViewController){
print("calling")
}
This is calling class.
I want to call open func in calling class but it does not calling at all,
even print("hello") in test class is not calling it keeps return nil therefore does not call calling function as well.
You need to set your calling as delegate of test ViewController.
In your calling class create object of test class before navigation and set calling class as delegate of your test class as
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let testVc = segue.destinationViewController as? test {
testVc .delegate = self
}
}
Hope it helps.. Happy Coding!!

prepareForSegue function not working

I am sure I have two view controllers, that have the appropriate files as their classes. (ViewController1.swift and ViewController2.swift) I am trying to pass data from one of the view controllers to the other one with the following code; but I get the error "UIView Controller is not convertible to ViewController2". What should I do? I tried to change as to as! and var to let; neither worked.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!){
if (segue.identifier == "btnSubmitSegue") {
var svc = segue.destinationViewController as ViewController2;
svc.DataPassed = textField.text
}
}
the code for ViewController2
import UIKit
class ViewController2: UIViewController {
var toPass: String = ""
#IBOutlet weak var labeld: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.labeld.text = "passed: \(self.toPass)"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
the code for ViewController1
import UIKit
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.
}
#IBOutlet weak var textField: UITextField!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "TheSegue" {
let vc = segue.destinationViewController as! ViewController2
vc.toPass = self.textField.text!
}
}
}
The following example works fine for me. Code for the first view controller:
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "TheSegue" {
let vc = segue.destinationViewController as! ViewController2
vc.passedText = self.textField.text!
}
}
}
And in the second view controller:
class ViewController2: UIViewController {
var passedText: String = ""
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
self.label.text = "passed: \(self.passedText)"
}
}
Don't forget to name the segue in the Storyboard:
Your destination view controller is referring to the wrong controller. You should have this in your code, not as! ViewController1:
let vc = segue.destinationViewController as! ViewController2
Also need to fix your IBOutlet name, the vc.toPass = self.textField.text! should be:
vc.toPass = self.labeld.text!
Make sure the custom class is set for the second view controller:
It may just be that ViewController2 is not declared as a subclass as UIViewController.
At the top of the ViewController2 file you would declare it as follows:
class ViewController2: UIViewController {
\\ ...
}
Have you set the name in the Storyboard ? Under custom class, Class needs to point to the view controllers associated class.
this class is not key value coding-compliant for the key
labelPassedData.' But I do not even have a variable like
labelPassedData
Click you view controller and press right hand arrow button, it shows all connections.
I guess you copy and pasted the view controllers and hence you get this problem.

I am trying to pass a string from one view controller to another view controller while unwinding using segues and I am not able to do so

It shows that the source view controler does not have the string variable so what should I do?
This is the code in my source view controller
#IBOutlet var textfield: UITextField!
#IBOutlet var tofirstbutton: UIButton!
#IBOutlet var tosecondbutton: UIButton!
var s:String!
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "unwindtosecond"{
self.s=self.textfield.text
}
}
and this is the code in my destination view controller
#IBOutlet var textfield: UITextField!
#IBOutlet var tofirstbutton: UIButton!
#IBOutlet var tothirdbutton: UIButton!
#IBOutlet var label: UILabel!
#IBAction func unwindtosecond(Segue:UIStoryboardSegue){
if Segue.identifier == "unwindtosecond" {
var source:ViewController = Segue.sourceViewController as ViewController
var s:String = source.s!
}
I am getting an error saying that viewcontroller does not have a member named s.
Here is some example code to implement a main controller segueing to a second VC, and the second unwinding to the main controller. Notice that in the function the second cVC unwinds to, you can refer to the second controller and access a variable in the second controller. If you want to initialize a variable in the second VC from the main VC, you can use a prepareForSegue in the main VC.
import UIKit
class ViewController: UIViewController {
var varInMainVC = ""
#IBAction func segueToSecondVCAction(sender: UIButton) {
performSegueWithIdentifier("segueToSecondVC", sender: self)
}
#IBAction func unwindFromSecondVC(segue: UIStoryboardSegue) {
// return here from second VC
let vc = segue.sourceViewController as! SecondViewController
varInMainVC = vc.varInSecondVC
println("varInMainVC = \(varInMainVC)")
}
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.
}
}
import UIKit
class SecondViewController: UIViewController {
var varInSecondVC = ""
var varLoadedFromMainVC = 0
override func viewDidLoad() {
super.viewDidLoad()
varInSecondVC = "Test String to be returned"
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Try these solutions:
Protocol delegate: https://stackoverflow.com/a/24299231/1925852
Setup a closure as a property: https://stackoverflow.com/a/24318588/1925852

Resources