Call Method from other Class in Swift - ios

I have 2 view controller classes. I want to call a method of ViewController2 from ViewController, but the console gives me this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Here is my method in the ViewController class:
class ViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {
#IBAction func testButton(sender: AnyObject) {
ViewController2().setText("It's a Test!")
}
}
And here is some code from ViewController2:
class ViewController2: UIViewController {
#IBOutlet weak var directionsTextField: UITextView!
func setText(var fieldText:String){
directionsTextField.text = directionsTextField.text + "\n \n" + fieldText
}
}
I'd be glad for every help! :-)
Thank you in advance :)
EDIT:
I also get this:
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
on the setText method...
Seems like directionsTextField isn't yet there maybe(??)

You're pretty close to figuring it out yourself. The crash is because your directionsTextField does not yet exist. Being an IBOutlet it won't come into existence before viewDidLoad is called. How do you fix this?
You change your API for your SecondViewControllerand give it a directionsText property. Winding up with something like this:
#IBOutlet weak var directionsTextField: UITextView!
var directionsText = ""
override func viewDidLoad() {
super.viewDidLoad()
directionsTextField.text = directionsTextField.text + "\n\n\(directionsText)"
}
In your FirstViewController you change your IBAction to match the new API of the SecondViewController:
#IBAction func testButton(sender: AnyObject) {
let secondController = SecondViewController() // Felt a bit odd creating an instance without having a way of referencing it afterwards.
secondController.directionsText = "It's a test"
// Do what you want. (Perhaps pushing your secondController)
}

The error occurs when you try instance the Second ViewController. Because you need implement the init method.
For example:
public class FirstViewController : UIViewController {
public override func viewDidLoad() {
super.viewDidLoad()
let secondviewController = SecondViewController().setText("YOURTEXT")
}
}
The Second ViewController:
public class SecondtViewController: UIViewController {
public required init(coder aDecoder : NSCoder) {
super.init(coder : aDecoder)
}
public init(nibName nibNameOrNil : String){
super.init(nibName : nibNameOrNil, bundle: SBTVPayViewController.frameworkBundle())
}
public convenience init() {
self.init(nibName: "MyNibName")
}
public func setText(texto : String) {
directionsTextField.text = directionsTextField.text + "\n \n" + fieldText
}
}
When you try to instantiate a ViewController the first method to execute it's init

Related

Changing Label text on main controller after modal closed swift macOS

I am using delegates to get a string value from my modal. When the modal closes I am trying to update Label text using that string. However, I am getting error: Unexpectedly found nil while implicitly unwrapping an Optional value: file. I am not sure how to fix this. I think it's happening because the view is not yet active.
import Cocoa
class ViewControllerA: NSViewController, SomeDelegate {
#IBOutlet weak var msgLabel: NSTextField!
var s: String = "";
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func setDetails(s: String) {
self.user = s;
print("Notified", self.s) // <-- prints: Notified hello again
msgLabel.stringValue = self.s <-- DOESN'T WORK
}
func showModal() -> Void {
msgLabel.stringValue = "hello" // <--- WORKS
let cbvc: NSViewController = {
return self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! NSViewController
}()
self.presentAsModalWindow(cbvc);
}
#IBAction func onBtn(_ sender: Any) {
self.showModal();
}
}
protocol SomeDelegate {
func setDetails(s: String)
}
class ViewControllerB: NSViewController {
#IBOutlet weak var textF: NSTextField!
var delegate: SomeDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let vc = ViewControllerA()
self.delegate = vc
}
#IBAction func onBtn(_ sender: Any) {
DispatchQueue.main.async {
self.delegate?.setDetails(s: self.textF.stringValue)
self.dismiss("ControllerAVC")
}
}
}
You have a number of problems.
In ViewControllerB.viewDidLoad you are assigning a new instance of ViewControllerA to the delegate property. Don't do that. Your viewDidLoad method should look like this:
override func viewDidLoad() {
super.viewDidLoad()
}
In the showModal method ViewControllerA should assign itself as the delegate on ViewControllerB before ViewControllerB it is presented.
func showModal() -> Void {
let cbvc: NSViewController = {
let vc = self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! ViewControllerB
vc.delegate = self
return vc
}()
self.presentAsModalWindow(cbvc);
}
In the setDetails method just assign the string to your text field directly:
func setDetails(s: String) {
msgLabel.stringValue = s
}

Passing data to various view controllers via delegate

Struggling to learn the basics of passing data via delegates. I am trying to pass a string from my viewController to my viewController2 and print it. I am getting the error:
"Type ViewController2 has no member delagate" in my view controller 2.
I cannot figure out where I have gone wrong.
viewController 1:
protocol datadelagate {
func printThisString(string: String)
}
class ViewController: UIViewController {
var delegate: datadelagate?
override func viewDidLoad() {
delegate?.printThisString(string: "This was passed from first controller to second controller")
}
}
This is my viewController 2:
class ViewController2: UIViewController, datadelagate {
func printThisString(string: String) {
print(string)
}
override func viewDidLoad() {
super.viewDidLoad()
ViewController2.delagate = self
print(String.self)
}
}
If you want ViewController2 to print some value from ViewController, you might have to do it this way:
protocol datadelagate {
func printThisString(string: String)
func getStringFromVC1() -> String
}
class ViewController: UIViewController, datadelagate {
let someString: String = "From VC1"
func printThisString(string: String) {
print(string)
}
func getStringFromVC1() -> String {
return someString
}
override func viewDidLoad() {
ViewController2.delagate = self
}
}
class ViewController2: UIViewController {
var delegate: datadelagate?
override func viewDidLoad() {
super.viewDidLoad()
//This is how something from VC2 is sent to VC1's scope.
delegate?.printThisString(string: "Calling the delegate to print something from ViewController2 on first ViewController")
//The below call gets you some value from VC1. (This is what you wanted, I belive...)
print(delegate?.getStringFromVC1())
}
}
Now for some explanation:
For simple understanding, assume a delegate as a person who does some specific job (protocol).
You have a `delegate'
You ask your delegate to work with your friend, and your friend acknowledges. (assigns your delegate by You.delegate = self, where self is your friend)
Now, through your delegate, you can do something with your friend, by asking your delegate to do some job (defined in protocol).
EDIT
The code above won't work, as non-static data members are trying to be accessed without creating an instance
Working code
import UIKit
class ViewController2: UIViewController {
static let sharedInstance = ViewController2()
weak var delegate: DataDelagate?
override func viewDidLoad() {
super.viewDidLoad()
//This is how something from VC2 is sent to VC1's scope.
delegate?.printThis(string: "Calling the delegate to print something from ViewController2 on first ViewController")
//The below call gets you some value from VC1. (This is what you wanted, I belive...)
print(delegate?.getStringFromVC1() ?? "s")
}
}
class ViewController: UIViewController {
static let sharedInstance = ViewController2()
var someString: String = "From VC1"
override func viewDidLoad() {
super.viewDidLoad()
ViewController2.sharedInstance.delegate = self
}
}
extension ViewController: DataDelagate {
func printThis(string: String) {
print(string)
}
func getStringFromVC1() -> String {
return someString
}
}
protocol DataDelagate: AnyObject {
func printThis(string: String)
func getStringFromVC1() -> String
}

self.name.text value change from another view controller gives fatal error:

I have viewcontroller and subviewcontroller I want to change self.name.text from subViewController changeIt function , to inside viewcontroller gives me
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
How can I resolve it , my codes under below.
subViewController
import UIKit
import CoreData
class subViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if prefs.string(forKey: "session") == "yes" {
let newname = prefs.string(forKey: "name")
ViewController().changeIt(name : newname)
}else{
}
}
}
ViewController
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet weak var name: UITextField!
class func sharedInstance() -> ViewController {
struct Singleton {
static var sharedInstance = ViewController()
}
return Singleton.sharedInstance
}
override func viewDidLoad() {
super.viewDidLoad()
}
public function changeIt(name : String){
print("New Name \(name)") /// WORKS!!
self.name.text = "\(name)" /// GIVES FATAL ERROR
}
}
(*ViewController also inside ContainerView)
you cannot set the IBOutlet directly from another controller instead declare a variable var tempName set that in your previous controller and use this variable to set your textfield self.name.text = tempName Hope this helps you

Delegate and UIActivityIndicatorView error

And just that I'm exercising the delegated pattern. I created a simple application where a delegate sends a message to UIViewController saying if you stop or start UIActivityIndicatorView. Unfortunately I get the following error: error atal: unexpectedly found nil while unwrapping an optional value.
It would seem that UIActivityIndicatorView is not initialized. I can not understand where I'm wrong.
protocol ProgressBarDelegate {
func UpdateProgressBar(progress: Bool)
}
class Dao: NSObject {
var delegate: ProgressBarDelegate?
override init() {
super.init()
//DELEGATO
//I who should I send the message? to FirstViewController
let messaggero = FirstViewController()
self.delegate = messaggero
scriviUnMessaggio(progress: true)
}
func scriviUnMessaggio(progress: Bool){
print("I'm writing a message ...")
delegate?.UpdateProgressBar(progress:progress)
}
My controller
class FirstViewController: UIViewController,ProgressBarDelegate {
#IBOutlet var activity: UIActivityIndicatorView!
func UpdateProgressBar(progress: Bool){
print("I received the message from Dao class (the delegate)")
switch progress{
case true:
// At this point I get the following error:Fatal error: unexpectedly found nil while unwrapping an Optional value
self.activity.startAnimating()
case false:
self.activity.stopAnimating()
default:
self.activity.startAnimating()
}
}
override func viewDidLoad() {
super.viewDidLoad()
let dao = Dao()
/// dao.caricamentoDati()
The problem is that you're creating a new object of FirstViewController in init of Dao. Since FirstViewController object is not created via xib/storyboard hence the outlet is not connected. That's why it's giving crash at self.activity.startAnimating()
Set the delegate to self in viewDidLoad
Change your Doa's init method as follow
class Dao: NSObject {
var delegate: ProgressBarDelegate?
init(delegate: ProgressBarDelegate) {
super.init()
//DELEGATO
//I who should I send the message? to FirstViewController
self.delegate = delegate
scriviUnMessaggio(progress: true)
}
func scriviUnMessaggio(progress: Bool){
print("I'm writing a message ...")
delegate?.UpdateProgressBar(progress:progress)
}
Then in viewDidLoad do this
override func viewDidLoad() {
super.viewDidLoad()
let dao = Dao(delegate: self)
}

How to pass data between UIViewControllers with protocols/delegates

In the code below I have a ViewController("SenderViewController"), which passes a message to the main ViewController when a button is tapped. What I don't fully understand is how does messageData() method in the main ViewController know when to listen for the message.
Can someone please explain me what is triggering the messageData() method in the main ViewController?
SenderViewController:
import UIKit
protocol SenderViewControllerDelegate {
func messageData(data: AnyObject)
}
class SenderViewController: UIViewController {
#IBOutlet weak var inputMessage: UITextField!
var delegate: SenderViewControllerDelegate?
#IBAction func sendData(sender: AnyObject) {
/
if inputMessage.text != ""{
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
self.delegate?.messageData(inputMessage.text!)
}
}
}
Main ViewController:
import UIKit
class ViewController: UIViewController, SenderViewControllerDelegate{
#IBOutlet weak var showData: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goToView(sender: AnyObject) {
let pvc = storyboard?.instantiateViewControllerWithIdentifier("senderViewController") as! SenderViewController
pvc.delegate = self
self.presentViewController(pvc, animated:true, completion:nil)
}
// What triggers this method, how it know when to listen?
func messageData(data: AnyObject) {
self.showData.text = "\(data)"
}
}
Thanks a lot!
Objects don't exactly listen for method calls. They sit there, waiting to invoked.
The line
self.delegate?.messageData(inputMessage.text!)
From your SenderViewController is a function call. (The term method and function are pretty much interchangeable, although the method is usually used for the functions of objects.) It invokes the function messageData in ViewController.
While Presenting SenderViewController from MainViewController you are setting the delegate as self. So whenever you call the delegate method in SenderViewController
self.delegate?.messageData(inputMessage.text!)
following method of MainViewController will act as a callback
func messageData(data: AnyObject) {
self.showData.text = "\(data)"
}
In SenderViewController:
When you tap button you invoke sendData method. In this method you ask delegate to invoke its messageData method. Delegate property declared as SenderViewControllerDelegate type, so you can do that (see this protocol defenition).
In ViewController (first view controller):
Before you open second view controller, in method goToView you seting up property delegate of SenderViewController to 'myself', to exact instance of ViewController, since you declared that it confirm protocol SenderViewControllerDelegate by implementing method messageData. So, ViewController is now saved as delegate property in SenderViewController, and can be used to invoke messageData!
self.delegate?.messageData(inputMessage.text!)
#IBAction func sendData(sender: AnyObject) {
if inputMessage.text != ""{
self.delegate?.messageData(inputMessage.text!)
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}else{
//handle here
}
Note: If you need to pass multiple data to mainViewController then use dictionary to pass them. i.e.
SenderViewController:
import UIKit
protocol SenderViewControllerDelegate {
func messageData(data: [String : Any])
}
class SenderViewController: UIViewController {
#IBOutlet weak var inputMessage: UITextField!
var delegate: SenderViewControllerDelegate?
#IBAction func sendData(sender: AnyObject) {
let myDict = [ "name": "Name", "age": 21, "email": "test#gmail.com"] as! [String : Any]
self.delegate?.messageData(myDict)
self.presentingViewController!.dismissViewControllerAnimated(true, completion: nil)
}
}
Main ViewController
import UIKit
class ViewController: UIViewController, SenderViewControllerDelegate{
#IBOutlet weak var showData: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goToView(sender: AnyObject) {
let pvc = storyboard?.instantiateViewControllerWithIdentifier("senderViewController") as! SenderViewController
pvc.delegate = self
self.presentViewController(pvc, animated:true, completion:nil)
}
// What triggers this method, how it know when to listen?
func messageData(data: [String : Any]) {
print(data["name"])
print(data["age"])
print(data["email"])
}
}

Resources