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)
}
Related
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
}
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
}
I'm practising how to communicate between two view controllers using protocol and delegate (in the xCode background even when I'm using protocol in my project I get the same problem, Delegate is nil), but the problem after setting everything it shows me that my delegate is nil and the sender VC does not send any data since the delegate is nil.
I have confirmed to the protocol and I have set the receiver VC as the delegate, but still can not see where the problem is.
The Protocol
protocol theCommunicationsStructionProtocol{
func dataToTransmit(Data: String)
}
The Sender VC
class TheSenderVC{
var delegate: theCommunicationsStructionProtocol?
func lookingForDelegate(){
self.delegate?.dataToTransmit(Data: "Data has been sent")
}
}
The Receiver VC
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj = TheSenderVC()
func delegateLuncher(){
TheSenderVCObj.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
calling delegateLuncher() to set the delegate in the receiver VC
TheSenderVC().lookingForDelegate()
calling lookingForDelegate() from the sender VC to look for the
delegate and send it the data
TheReceiverVc1().delegateLuncher()
Note: I have tried accessing the delegate from the receiver VC using this way:
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj: TheSenderVC?
func delegateLuncher(){
self.TheSenderVCObj?.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
but I still getting the same problem:
delegate is nil
Finally, I found the solution!
the problem is I was making instances of the TheSenderVC, instead of takling to the original TheSenderVC.
when I was making an object (an instance) of TheSenderVC the problem occurred! instead I have to access the original TheSenderVC, which means I have to use static :)
here is the old delegate set up
var delegate: theCommunicationsStructionProtocol?
from TheSenderVC
here is the new delegate set up
static var delegate: theCommunicationsStructionProtocol?
therefore the
func lookingForDelegate(){
self.delegate?.dataToTransmit(Data: "Data has been sent")
}
will be changed to
static func lookingForDelegate(){
self.delegate?.dataToTransmit(Data: "Data has been sent")
}
since now it includes a static property (delegate)
on the other hand, the The ReceiverVC1 should be changed from:
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj = TheSenderVC()
func delegateLuncher(){
TheSenderVCObj.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
to:
class TheReceiverVc1: theCommunicationsStructionProtocol{
func delegateLuncher(){
TheSenderVC.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
accessing the delegate from the original TheSenderVC()
Where are you create the reference of TheSenderVCObj
replace var TheSenderVCObj: TheSenderVC? to var TheSenderVCObj = TheSenderVC()
let try below code:
class TheReceiverVc1: theCommunicationsStructionProtocol{
var TheSenderVCObj = TheSenderVC()
func delegateLuncher(){
self.TheSenderVCObj?.delegate = self
}
func dataToTransmit(Data: String) {
print("from VC1: \(Data)")
}
}
your TheSenderVCObj also nil according to your code.
NOTE: use proper naming conventions.
Because the TheReceiverVc1 was automatic deinit by ARC.
You need to save reference of the instance like that's:
class ViewController: UIViewController {
let theReceiverVc1: TheReceiverVc1 = TheReceiverVc1()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
theReceiverVc1.delegateLuncher()
}
}
Also make sure when you using delegate set it as weak var:
weak var delegate: theCommunicationsStructionProtocol?
In my project I have implemented a protocol which makes some URL call and return result, and my intent is to show result in UILabel. Following is my code :
protocol RestAPIResult
{
func retriveDriverInfo()
}
class RestAPICall : RestAPIResult
{
func retriveDriverInfo()
{
self.dashBoardViewController.getDriverInfo(driverProfile)
// calling another function of Next View for Lable Setup
}
}
getDriverInfo is in NextView which has Outlet of textVIew
class DashBoardViewController: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
restDeledate = RestAPICall()
restDeledate!.retriveDriverInfo()
// IF LABEL SET HERE NO ERROR
//totalTripLabel.text = "Testing" // NO ERROR
}
func getDriverInfo(driverInfoArray : NSArray)
{
totalTripLabel.text = "Testing" // HERE IS ERROR
}
}
If Text is set in ViewDidLoad() it doesn't crash. but when i tried to set value in delegate function it crash saying found null.
protocol RestAPIResult: NSObjectProtocol
{
func retriveDriverInfo(message: String)
}
class RestAPICall : RestAPIResult
{
override func viewDidLoad()
{
super.viewDidLoad()
//create an instance of your vc and
instance.delegate = self
//if you code for push vc then write this line there insatance.delegate = self
}
func retriveDriverInfo(message: String)
{
yourLbaelOutlet.text = message
}
}
class DashBoardViewController: UIViewController
{
weak var delegate: RestAPIResult!
override func viewDidLoad()
{
super.viewDidLoad()
}
func getDriverInfo(driverInfoArray : NSArray)
{
self.delegate.retriveDriverInfo(message: "youMessage")
}
}
*
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