2

As a C++ dev picking up Swift, I'm wondering how, in a struct or other class, to store a "pointer" or "reference" to a property of of another object of another class.

For example- a controlResponder class (or struct) that listens for events to modify the value target of a target in an effect class.

Control responder:

struct controlResponder {
    var ccNum : Int!  // CC number to respond to
    var target : Double! // Points to the variable of another object
    var min : Double!
    var max : Double!
}

Effects, in my case, can be of different classes but the thing that will be targeted for modification will always be a Double (To be precise- I'm working with AudioKit and am targeting effects like AKVariableDelay.time, or AKMoogLadderFilter.cutoff )

Any insight would be greatly appreciated, thanks!

Below is an abridged version of some of my actual (non functioning) code:

import Foundation
import AudioKit
import SwiftyJSON

class Effect : AKNode, AKMIDIListener {

  enum CustomError: Error {
    case badEffectName
  }

  struct ccListener {
    var ccNum : Int!
    var target : Int!
    var min : Double!
    var max : Double!
  }

  var listeners : [ccListener]

  var effectType = ""
  var effect = AKNode()
  var channel = 0
  var midi : AKMIDI

  init(connectionInput : AKNode, midi : AKMIDI, subJson : JSON, channel : Int) throws {

    self.midi = midi
    self.channel = channel
    var insertType = subJson["type"]

    if insertType == "distortion" {
      print("Adding a DISTORTION")
      effect = AKTanhDistortion(connectionInput)

      if let efx = effect as? AKTanhDistortion {
        let gainVal = random(subJson["gain random low"].doubleValue, subJson["gain random high"].doubleValue)
        print("gainVal: \(gainVal)")
        efx.pregain = gainVal
      }

    }
    else if insertType == "moog" {

      print("Adding a MOOG FILTER")
      /// CUTOFF
      let cutoffVal = random(subJson["cutoff random low"].doubleValue, subJson["cutoff random high"].doubleValue)
      print("cutoffVal: \(cutoffVal)")
      /// RESONANCE
      let resonanceVal = random(subJson["resonance random low"].doubleValue, subJson["resonance random high"].doubleValue)
      print("resonanceVal: \(resonanceVal)")

      effect = AKMoogLadder(connectionInput,
        cutoffFrequency: cutoffVal,
        resonance: resonanceVal)
    }
    else {
      print("BAD EFFECT TYPE: \(insertType)")
      throw CustomError.badEffectName
    }

    /////// MIDIZ

    midi.openInput("vIn")

    super.init()

    for (key, cc) in subJson["ccs"] as JSON {
      let efx = effect as! AKMoogLadder
      listeners.append(ccListener(ccNum: cc["cc number"].intValue, target: efx.cutoffFrequency, min: cc["min"].doubleValue, max: cc["max"].doubleValue))
    }

    midi.addListener(self)
    print("End of Effect init()")
  }


  func receivedMIDIController(_ controller: MIDIByte, value: MIDIByte, channel: MIDIChannel) {
    print("Self channel: \(self.channel), incoming channel: \(Int(channel))")
      if self.channel == Int(channel){
        print("Effect got a CC!")
      }
    }

    func changeVal(ccNum: Int, newValue: Int) {

      for listener in listeners {
        if listener.ccNum == ccNum {
          listener.target = newValue
        }
      }

    }

  }
4
  • 1
    If the question is not about C++ itself, please leave out the c++ tag. Commented Sep 17, 2017 at 21:25
  • What you're asking is how to say var target = «Some syntax»responder.target and then target = 0.5, such that the original "responder"'s property value changes? Commented Sep 17, 2017 at 21:44
  • @JoshCaswell Essentially, yep! This "Effect" class will receive an event and I want to store an array mappings so that the incoming value of the event, will modify the actual value of a property in another object. Commented Sep 17, 2017 at 22:30
  • If you're working in Swift 4, key paths should do the trick. Commented Sep 18, 2017 at 13:24

1 Answer 1

1

In Swift, the only pointers that you can reliably store are those allocated with UnsafeMutablePointer.allocate. The pointers that you can get from the address-of operator and withUnsafeMutablePointer are cheats and they are only valid for a short time; using them beyond that point will have unpredictable results.

This means that, generally speaking, you can't store a pointer to a value type (struct instances) that was allocated with "automatic storage" (to borrow from C++ terminology). If you need to share value types, you need to wrap them, at some convenient level, in a reference type (class instances).

The most generic you could get would be to use a pair of closures, one that returns the value and another one that sets it. However, there's probably a less generic but more useful way to do it for your specific case.

Sign up to request clarification or add additional context in comments.

2 Comments

Ah! So, if in the code above I were to make ccListener a class rather than a struct, if I init one and pass, say, let newListener = ccListener(target: self.effect.cutoff) (a double) as an init parameter, that would actually be a reference and not just the double value?
@EricR, did you understand that a class's init parameters become references by virtue of class being a reference type? If so, that's not what I meant, and it's not the case. newListener would be a reference (more like a C++ pointer, I guess), but its target would still be a value with automatic storage. You still can't create a long-term pointer to a value with automatic storage, but you can share the newListener reference with other components so that they can work on the right, shared Double.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.