0

I have 2 values that track current values of types of benefits my users can purchase within the app. I want to update them in the purchaseViewController and use them in the previous view controller once the purchaseViewController is dismissed. I have tried to do this with both a protocol/delegate and a callback. However, I get essentially the same error with both saying "Instance member 'delegate/callback' cannot be used on type 'purchasesViewController'". This is my first time trying to pass data back and I've mainly just been following tutorials and may have missed a step along the way but I think its weird both methods get the same type of error.

Code on the parent view controller:

func sendBack(staticIncreases: Int, percentIncreases: Int) { //Protocol function
    self.avalibleIncreases = staticIncreases
    self.currentPercentIncreases = percentIncreases
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier ==  "improveFromOpen"{
        let next = segue.destination as! purchasesViewController
        next.currentPercentIncreases = currentPercentIncreases
        next.username = username
        next.avalibleIncreases = avalibleIncreases
        purchasesViewController.delegate = self //Error "Instance member 'delegate' cannot be used on type 'purchasesViewController'"
        purchasesViewController.callback = { result in //Error "Instance member 'delegate' cannot be used on type 'purchasesViewController'"
            self.avalibleIncreases = result[0]
            self.currentPercentIncreases = result[1]
        }
    }

Code on the purchaseViewController:

protocol updateBoosts {
    func sendBack(staticIncreases: Int, percentIncreases: Int)
}

class purchasesViewController: UIViewController {

    var delegate: updateBoosts? = nil
    var callback : (([Int])->())?

    var username: String!
    var currentPercentIncreases: Int!
    var avalibleIncreases: Int!

func sendBackVals(){
    if self.delegate != nil {
        self.delegate?.sendBack(staticIncreases: avalibleIncreases, percentIncreases: currentPercentIncreases)
    }

    let out = [avalibleIncreases!, currentPercentIncreases] as [Int]
    callback?(out)
}

override func viewWillDisappear(_ animated: Bool) {
    sendBackVals()
}

Any idea where my error is?

  • The protocol needs to be `protocol NAME: class { }`, the `delegate` should be `weak`, and make sure that you are conforming to the protocol in your parent class. You also don't need the nil check in `sendBackVals()`, as you are using optional chaining. – rbaldwin May 21 '20 at 08:49
  • https://stackoverflow.com/questions/24099230/delegates-in-swift – rbaldwin May 21 '20 at 08:52

1 Answers1

0

There are a couple of design problems with your code.

You should use either delegate or closure at a time, as both are being used for the same purpose. Otherwise, the same thing will get execute twice.

If you using the delegate you will have to make a change in your protocol as mentioned below. And Also, you will have to confirm the protocol.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier ==  "improveFromOpen"{
        let next = segue.destination as! purchasesViewController
        next.currentPercentIncreases = currentPercentIncreases
        next.username = username
        next.avalibleIncreases = avalibleIncreases
        next.delegate = self 
    }
}

Confirm the protocol

Let say the current view controller where you want to get the callback is HomeViewController

// Confirming the protocol
extension HomeViewController: UpdateBoostsDelegate {
   func sendBack(staticIncreases: Int, percentIncreases: Int) {
    // write code here for handling the callback
   }
}

If you want to use closure then remove the delegate.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier ==  "improveFromOpen"{
        let next = segue.destination as! purchasesViewController
        next.currentPercentIncreases = currentPercentIncreases
        next.username = username
        next.avalibleIncreases = avalibleIncreases
        next.callback = { result in
                self.avalibleIncreases = result[0]
                self.currentPercentIncreases = result[1]
       }
    }
// Would be good if you add the semantic to protocol name
protocol UpdateBoostsDelegate: class {
    func sendBack(staticIncreases: Int, percentIncreases: Int)
}

A few more corrections in the PurchaseViewController

class purchasesViewController: UIViewController {
// Make it weak so that no retain cycle is formed
   weak var delegate: UpdateBoostsDelegate?
// rest code will follow ....

Suggestions

  1. For Classes, struct, enum, protocol, the first character of each word should always be in Capital.
  2. The protocol should have semantic, i.e If it is created to inform the event then add Delegate postfix, or if it is being created to fulfill the data need, then add Datasource postfix in the Protocol name.

More about closure

Delegation design pattern

Kamar Shad
  • 6,089
  • 1
  • 29
  • 56
  • I tried implementing your suggested changes and when I remove the delegate from the prepare for segue I get the same error as before about the closure. I also implemented all of you suggestions for the delegate/protocol process then got rid of the closure but again had the same "Instance member 'delegate' cannot be used on type 'purchasesViewController'; did you mean to use a value of this type instead?" error on the same line as before. Also, not sure if it should or not but when I type `purchasesViewController.delegate` it at no point auto-suggests delegate as it does with most other things – hudsonhooper May 21 '20 at 15:48
  • @hudsonhooper Let's discuss here https://chat.stackoverflow.com/rooms/214353/ios-basic-discussion – Kamar Shad May 21 '20 at 16:15
  • Check the code again, You will have to use `next` which is an instance of `purchasesViewController` you should set the delegate or closure like `next.delegate` or `next.callback = { result in self.avalibleIncreases = result[0] self.currentPercentIncreases = result[1] }` – Kamar Shad May 21 '20 at 16:24
  • You are most welcome :) Then you should accept the answer @hudsonhooper – Kamar Shad May 21 '20 at 17:05