Swift equivalent of C++ Pointer / Reference convention? - swift

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
}
}
}
}

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.

Related

Swift Function Input Generic Conform To Both Class And Protocol

I'm trying to have a function take a generic input that conforms to both a class and a protocol in order to process values where some belong to the class and others belong to the delegate. It works fine for individual types, but not for an array of types (which conform to both the super class and the delegate). Instead the compiler throws the error "Instance method 'printValues(for:)' requires that 'MeasurementClass' conform to 'UnitDelegate'"
I've added the code below, which will make much more sense. Just put it in a Swift Playground. If you run it as is, you can see that it properly prints the users distance and steps individually. If you uncomment the last few lines, the same function cannot be used with an array.
My goal is to be able to pass an array of types that conform to the UnitDelegate and MeasurementClass (aka MeasurementObject typealias) and have the values processed. I want an array, because I will need up having a bunch of different classes that conform to MeasurementObject.
protocol UnitDelegate: class{
var units: [String: String] { get }
}
class MeasurementClass{
var imperial: Double!
var metric: Double!
convenience init(imperial: Double, metric: Double){
self.init()
self.imperial = imperial
self.metric = metric
}
}
typealias MeasurementObject = MeasurementClass & UnitDelegate
class Distance: MeasurementObject{
var units = ["imperial": "miles", "metric":"kms"]
}
class Steps: MeasurementObject{
var units = ["imperial": "steps", "metric":"steps"]
}
class User{
func printValues<T: MeasurementObject>(for type: T) {
print("\(type.imperial!) \(type.units["imperial"]!) = \(type.metric!) \(type.units["metric"]!)")
}
}
//This is what I'm trying to achieve in the for loop below
let distance = Distance(imperial: 30, metric: 48.28)
let steps = Steps(imperial: 30, metric: 30)
let user = User()
user.printValues(for: distance)
user.printValues(for: steps)
//let types = [distance, steps]
//
//for type in types{
// user.printValues(for: type)
//}
Not a direct answer to your question but all you need is to add an enumeration to store the kind of measurement to your class, and a computed property to return the corresponding dictionary. No need to use a protocol, protocol composition, class and/or subclass to accomplish what you are trying to do:
struct AMeasurement {
let imperial: Double
let metric: Double
let kind: Kind
enum Kind { case distance, steps }
var units: [String: String] {
switch kind {
case .distance: return ["imperial": "miles", "metric":"kms"]
case .steps: return ["imperial": "steps", "metric":"steps"]
}
}
}
extension AMeasurement {
func printValues() {
print("\(imperial) \(units["imperial"]!) = \(metric) \(units["metric"]!)")
}
}
let distance = AMeasurement(imperial: 30, metric: 48.28, kind: .distance)
let steps = AMeasurement(imperial: 30, metric: 30, kind: .steps)
let types = [distance, steps]
for type in types {
type.printValues()
}
30.0 miles = 48.28 kms
30.0 steps = 30.0 steps

Swift Error Code: Instance member 'getStory' cannot be used on type 'StoryBrain'; did you mean to use a value of this type instead?

Can't figure out how to go about this swift error code... Do I need to make an instance or make it static??
struct Story{
var storyTitle : String
var choice1 : String
var choice2 : String
init(t: String,c1: String, c2: String ) {
storyTitle = t
choice1 = c1
choice2 = c2
} }
struct StoryBrain{
var storyNumber = 0
let stories = [
Story(t: "You see a fork in the road", c1: "Take a left", c2: "Take a right"),
Story(t: "You see a tiger", c1: "Shout for help", c2: "Play dead"),
Story(t: "You find a treasure chest", c1: "Open it", c2: "Check for traps")
]
func getStory() -> String{
return stories[storyNumber].storyTitle
}
mutating func nextStory(userChoice: String) {
if storyNumber + 1 < stories.count{
storyNumber += 1
} else {
storyNumber = 0
}
}
}
func updateUI(){
storyLabel.text = StoryBrain.getStory()}
I guess your doing Angelas "iOS & Swift - The Complete iOS App Development Bootcamp" course on Udemy.
Inside the ViewController, create a var:
class ViewController: UIViewController {
var storyBrain = StoryBrain()
#IBOutlet weak var storyLabel: UILabel! }
This allows you to tap into your StoryBrain Model. Good luck!
The issue is here:
StoryBrain.getStory()
^ Instance member 'getStory' cannot be used on type 'StoryBrain'
As the error indicates, getStory is an instance method, meaning that you can only call it on instances of StoryBrain. Here are a couple other suggestions:
struct StoryBrain {
// Make private by default
private let stories = [...]
private var storyNumber = 0
// Make a computed property
var currentStoryTitle: String {
stories[storyNumber].storyTitle
}
// Make the name imperative; reflects that this is a mutating function
// Also don't need mutating anymore since this is a class
func advanceStory(...) {
...
}
}
If you initialize this object, like let brain = StoryBrain(), then you can use instance members like advanceStory and currentStoryTitle on brain. You’ll want to create this object/store it in whatever class you have updateUI in. If you use the same brain from a couple different places, then you might want to use the singleton pattern, which you can see in the original edit to this answer.

Swift accessing struct by variable

Let me first excuse for probably missing something basic (and the right expression)
I have a struct where I store several values for a board game. It looks like this and includes about 20 values.
struct Werte {
static var geld: [Int] = [] {didSet {NotificationCenter.default.post(name: .ResourcenAnzeigen, object: nil, userInfo: ["which" : 0])}}
static var erz: [Int] = [] {didSet {NotificationCenter.default.post(name: .ResourcenAnzeigen, object: nil, userInfo: ["which" : 1])}}
static var temperatur = Int() {didSet {NotificationCenter.default.post(name: .TemperaturAnzeigen, object: nil)}}
}
There are several classes like this:
class KarteBlauVerbraucheErhalte {
let use: //what should I declare
let useHowMuch: Int
init(use: /*what should I declare*/ , useHowMuch: Int) {
self.use = use
self.useHowMuch = useHowMuch
}
override func Aktion() {
use += useHowMuch
}
If I declare use with Int and use init(use: Geld[0] , useHowMuch: 99) the code works - but only the class variable use increased by 99.
Geld[0] doesnt change.
How can I make Geld[0] change?
One way is this:
var use: Int {
get {
return Werte.geld[0]
}
set {
// You have access to the newValue by property name 'newValue'.
// Use it. E.g.:
Werte.geld[0] += newValue
}
}
Omit it in the constructor, as it wouldn't make sense and I do not think it compiles.
Background of why your code doesn't work: you are referring to geld[0], which is just an Int. It just passes the actual value, not a reference. But that is a whole other topic.

Is a static boolean a reference type in Swift?

I'm making some switches. In my MenuScene class there's some booleans that are static variables, booleans, to represent the states of these switches.
Are these addressable as reference types, so I can be sure that other objects are able to change their state with a unique reference to them?
The dream, in my dreamy pseudo code, I'm hoping changes to iAmOn impact the state of myButtonABC_state
class MenuScene {
static var myButtonABC_state: Bool = false
static var myButtonXYZ_state: Bool = false
override onDidMoveToView {
let buttonABC = Button(withState: MenuScene.myButtonABC_state)
let buttonXYZ = Button(withState: MenuScene.myButtonXYZ_state)
}
}
In a button class
class Button {
var iAmOn: Bool = false
init(withState state: Bool){
iAmOn = state
}
override onTouchesBegun(... etc...){
if iAmOn { iAMOn = false }
else { iAmOn = true}
}
}
Bool is a struct in Swift; structs are value types. It doesn't matter if it's static var, class var, let, var, etc., the type is what matters--so no, Bool is value type.
I think you are not 100% on all of the terminology (mostly because Apple doesn't really cover it much in documentation as usual, lol).
There are "Swift Types" (Bool, Int, your classes/structs, etc), and "Variable/Constant Types" (which hold data in a memory register, such as references or actual-values), as well as "Memory Register Write/Read Types" (variable vs vonstant, mutable vs immutable, var vs let).
Don't be frustrated.. It's a bit confusing for everyone... Especially at first and without great documentation. (I tried learning C++ pointers early age and it was way over my head).
Here's a good reference material: (towards the bottom)
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html
Basically, if you want to hold a reference to something, you have to use a Reference Type memory register. This means using a class instance Static makes no difference:
/* Test1: */
struct Hi {
static var sup = "hey"
}
var z = Hi.sup
Hi.sup = "yo"
print(z) // prints "hey"
/* Test 2: */
class Hi2 {
static var sup = "hey"
}
var z2 = Hi2.sup
Hi2.sup = "yo"
print(z2) // Prints "hey"
If you feel like you need a pointer to something that isn't inside of a class, then you can use UnsafeMutablePointer or something like that from OBJc code.
Or, you can wrap a bool inside of a class object (which are always references).
final class RefBool {
var val: Bool
init(_ value: Bool) { val = value }
}
And here is some interesting behavior for reference types using let:
let someBool: RefBool
someBool = RefBool(true)
someBool = RefBool(false) // wont compile.. someBool is a `let`
someBool.val = false // will compile because of reference type and member is `var`

Swift SpriteKit use struct instead of class to render sprites

I have been updating my game recently to use more value types. I am still not 100% confident with weak and unowned in some cases so I went the struct way to avoid strong reference cycles. As per apples newer keynotes it seems value types are they way to go for the most part anyway.
I have never seen an example where structs are used to render sprites in a spriteKit game so I wonder what the drawbacks are.
I understand that they are copied and not referenced but for my usage it seems to work.
So basically is there something I need to watch out for when doing this
struct Flag {
let post: SKSpriteNode
let flag: SKSpriteNode
init(postImage: String, flagImage: String) {
post = SKSpriteNode(imageNamed: postImage)
// other set ups for post sprite
flag = SKSpriteNode(imageNamed: flagImage)
// other set ups for flag sprite
post.addChild(flag)
}
func animate() {
// code to animate flag
}
}
Than in my SKScenes I simply add them as usual
let flag = Flag(postImage: "FlagPostImage", flagImage: "FlagImage")
flag.post.position = ...
addChild(flag.post)
flag.animate()
Now even if I create multiple flags in the same scene I seem to have no problems with this way.
I am just curious because I have never really seen an example like this so I wonder if I am missing something, like performance drawbacks etc.
Thanks for any help.
Personally I avoid creating Structs that contain Classes. Because Structs copy, each and every copy that get's passed around your app will increase the reference count of the Classes. This makes it harder to manage them instead of easier.
It is also useful to take a look at how UIKit uses Structs. A UIView is an object but has many defining properties that are Structs. For example it's frame.
Drop the code below in a playground to see some effects of this behaviour.
The protocol is just to get some meaningful feedback form the playground.
protocol IDLookable : CustomPlaygroundQuickLookable {
var id : Int { get set }
}
extension IDLookable {
func customPlaygroundQuickLook() -> PlaygroundQuickLook {
return PlaygroundQuickLook.AttributedString(NSAttributedString(string: "\(self.dynamicType) with id : \(self.id)"))
}
}
class MyClass : IDLookable {
var id : Int = 0
init(id : Int) {
self.id = id
}
}
struct MyContainerStruct : IDLookable {
var id : Int = 0
var object : MyClass
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 2
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 3
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
// altering the object in one struct will obvously update all references
structContainerTwo.object.id = 1
structContainer.object // 1
structContainerTwo.object // 1
}
}
let test = Scope()
One pattern that does make it easy to work with Reference Types in Value Types is to store them as weak optionals in the Value Types. This means that something will need to have a strong reference but chances are that some Class will be responsible for creating the Structs this is a good place to keep that strong reference.
struct MyContainerStruct : IDLookable {
var id : Int = 0
weak var object : MyClass?
init(id : Int, object:MyClass) {
self.id = id
self.object = object
}
}
class Scope {
// ref count = 1
var object = MyClass(id: 11)
var structContainer : MyContainerStruct
init() {
// ref count = 1
structContainer = MyContainerStruct(id: 222, object: object)
messWithAClassInAStruct()
}
func messWithAClassInAStruct() {
// ref count = 1
var structContainerTwo = structContainer
structContainerTwo.id = 333
structContainerTwo.object // 11
}
}
let test = Scope()