Structs That Refer to Each Other in Swift 3

Structs that refer to each other in Swift 3

The problem is that an Optional stores its Wrapped value inline (see Mike Ash's fantastic blog post for more info about this) – meaning that an Optional instance (regardless of whether it is nil or not) will occupy at least the same amount of memory as the type you wish to store in its .some case (the Wrapped type).

Thus, as your Pin struct has a property of type DetailedPin?, and DetailedPin has a property of type Pin?, infinite storage would be required in order to store these values inline.

The solution therefore is simply to add a layer of indirection. One way of doing this would be to make Pin and/or DetailedPin a reference type (i.e a class) as @dfri has suggested.

However, if you wish to keep the value semantics of Pin and DetailedPin, one option would be to create a wrapper type backed by a class instance to provide the necessary indirection:

/// Provides indirection for a given instance.
/// For value types, value semantics are preserved.
struct Indirect<T> {

// Class wrapper to provide the actual indirection.
private final class Wrapper {

var value: T

init(_ value: T) {
self.value = value
}
}

private var wrapper: Wrapper

init(_ value: T) {
wrapper = Wrapper(value)
}

var value: T {
get {
return wrapper.value
}
set {
// Upon mutation of value, if the wrapper class instance is unique,
// mutate the underlying value directly.
// Otherwise, create a new instance.
if isKnownUniquelyReferenced(&wrapper) {
wrapper.value = newValue
} else {
wrapper = Wrapper(newValue)
}
}
}
}

You can now just use the Indirect wrapper for one (or both) of your structs properties:

struct DetailedPin {
private var _pin = Indirect<Pin?>(nil)

// Convenience computed property to avoid having to say ".value" everywhere.
var pin: Pin? {
get { return _pin.value }
set { _pin.value = newValue }
}
}

struct Pin {
var detailedPin: DetailedPin?
var foo: String
}

var d = DetailedPin()
var p = Pin(detailedPin: d, foo: "foo")
d.pin = p

// testing that value semantics are preserved...
var d1 = d
d1.pin?.foo = "bar"

print(d.pin?.foo as Any) // Optional("foo")
print(d1.pin?.foo as Any) // Optional("bar")

Swift pass struct by reference?

Structs can be passed by reference using the inout keyword and the & operator.

struct Test {
var val1:Int
let val2:String

init(v1: Int, v2: String) {
val1 = v1
val2 = v2
}
}

var myTest = Test(v1: 42, v2: "fred")

func change(test: inout Test) {
// you can mutate "var" members of the struct
test.val1 = 24

// or replace the struct entirely
test = Test(v1: 10, v2: "joe")
}
change(test: &myTest)
myTest // shows val1=10, val2=joe in the playground

This practice is discouraged unless you can prove it's the only way to get the performance you need in a critical situation.

Note that you won't save the burden of copying the UIImage by doing this. When you put a reference type as a member of a struct, you still only copy the reference when you pass it by value. You are not copying the contents of the image.

Another important thing to know about struct performance is copy-on-write. Many built in types like Array are value types, and yet they're very performant. When you pass around a struct in Swift, you don't undergo the burden of copying it until you mutate it.

Check out the WWDC video on value types to learn more.

Passing a value type as reference in Swift

structs are always passed by value. The whole point of using a struct is to have it behave as a value type. If you need delegation (which usually implies mutable state), you should be using a class.

If you really really need to, you could force pass-by-reference by using an inout parameter, but that is not recommended in general. You could also use a box type to simulate passing by reference. But, in general, you should just use a class if you need reference behavior.

Swift 3 - Structs in a Collection

extension Collection where Iterator.Element: Person

restricts Iterator.Element to types which adopt the protocol Person
or are a subclass of Person. Both is not possible with
struct Person, and in the full compiler log you'll find

error: type 'Iterator.Element' constrained to non-protocol type 'Person'

What you probably mean is

extension Collection where Iterator.Element == Person 

which restricts the extension to collections of Person.
Alternatively, define a protocol

protocol HasAge {
var age: Int { get }
}

adopt that by Person

struct Person: CustomDebugStringConvertible, Hashable, HasAge { ... }

and define the extension for collections of elements which have a age:

extension Collection where Iterator.Element: HasAge { ... }

Swift Tuples - Different from struct and from each other?

I find it's easiest to conceptualize Swift Tuples as "Anonymous Structs" with a few critical differences. They behave similarly, but a struct has a formal definition and allows more control over mutability, while tuples allow for pattern matching.

Similarities Between Tuples and Structs

  • Both may have any number of members of any type, including closures
  • Both can be constructed inline (see typealias in the code below)
  • Both prevent mutation of any members if declared as constants
  • If a tuple has labeled members, both structs and tuples allow member access by label

Differences Between Tuples and Structs

  • Structs require a definition before use
  • Structs do not allow pattern matching against their members
  • Structs allow mutability of members declared as variables if the instance is a variable
  • Tuples do not allow mutating functions or functions that refer to any of its members
  • Tuples may not implement Protocols
  • If a tuple has anonymous members, its members can be accessed by index, unlike structs

Some code for a playground illustrating these differences and similarities

// All commented code causes a compilation error. Uncomment to view error messages.

struct StructureX {
let a: Int = 0
var b: String = "string"
}

//
// Struct member variability
//
var structureA: StructureX = StructureX()
let structureB: StructureX = StructureX()
//structureA.a = 2 // declared as a constant, instance is variable
structureA.b = "allowed" // declared as a variable, instance is variable
//structureB.a = 2 // declared as constant, instance is constant
//structureB.b = "not allowed" // declared as constant, instance is constant
structureA = structureB // these are the same type
structureA


//
// A tuple can't be used as a literal to construct a struct.
//
//let StructureC: StructureX = (a: 17, b: "nope")


//
// Typealias a labeled tuple and it can be constructed similarly to a struct
//
typealias StructureT = (a: Int, b: String)
var structureD: StructureT = StructureT(a: 0, b: "asdf")
structureD
//structureD = structureA // but they are distinct types



let emptyTuple: () = () // philosophically, isn't this the definition of Void?
print(emptyTuple) // prints as ()
let single: (Int) = (23)
//let namedSingle: (a: Int) = (a: 42)


//
// Tuple Labeled Member Access
//
var labeledTupleA: (a: Int, b: String) = (a: 0, b: "string")
labeledTupleA.0 = 5
labeledTupleA.a
labeledTupleA

var check: (a: Int, b: String)
check = labeledTupleA // same type
check

//
// Tuples can have functions/closures
//
let labeledTupleB: (Int, String, fun: () -> Void) = (0, "string", { () -> Void in
print("hi")
})
labeledTupleB.1
labeledTupleB.fun()
//labeledTupleB.0 = 10 // this tuple is a constant, so all of its members are constant


//
// Tuples with members of the same type, but differet labels are not of the same type
//
var labeledTupleC: (c: Int, d: String) = (c: -1, d: "fail")
//labeledTupleC = labeledTupleA
//labeledTupleC = labeledTupleB


//
// Tuples with anonymous members matching the type pattern of a labeled member tuple are of equivalent type
//
var unlabeledTuple: (Int, String) = (0, "good")
unlabeledTuple = labeledTupleA
unlabeledTuple = labeledTupleC


//
// Tuples with closures may not refer to sibling members
//
var labeledTupleD: (de: Int, df: (Int) -> Void) = (de: 0, df: { (num: Int) -> Void in
//de += num
//self.de += num
print(num)
})

labeledTupleD.de
labeledTupleD.df(1)


//
// Tuples allow pattern matching, Structs do not
//
//switch structureA {
//case (let i, let s):
// print(i, s)
//default:
// break
//}

switch labeledTupleD {
case (_, let closure):
closure(123)
default:
break
}

What are the main differences between classes and structs in swift 3?

class Car {
var name: String

init(name:String){
self.name = name
}
}

var carA = Car(name: "BMW")
var carB = carA
//now I will change carB
carB.name = "Nissan"
print(carA.name) //This will print Nissan


struct CarStruct {
var name: String

init(name: String){
self.name = name
}
}

var carC = CarStruct(name: "BMW")
var carD = carC
//now I will change carB
carD.name = "Nissan"
print(carC.name) //This will print BMW

As you can see both CarA and CarB are pointing to the same reference so if one changes the other change because the reference is changing, while in CarC and CarD which are structs they are copies of each other each with its value.

Swift 3 - Pass struct by reference via UnsafeMutableRawPointer?

Your function copies the data into a local struct, but does not
copy the modified data back. So this would be a possible
solution in your special case:

func testUnsafeMutablePointer(data: UnsafeMutableRawPointer?) {
var testStructInFunc = data!.load(as: TestStruct.self)

testStructInFunc.prop1 = 24
testStructInFunc.prop2 = 1.2
testStructInFunc.prop3 = false

data!.storeBytes(of: testStructInFunc, as: TestStruct.self)
}

But note that this works only if the struct contains only "simple"
values likes integers and floating point values. "Complex" types
like arrays or strings contain opaque pointers to the actual storage
and cannot be simply copied like this.

Another option is to modify the pointed-to struct like this:

func testUnsafeMutablePointer(data: UnsafeMutableRawPointer?) {
let testStructPtr = data!.assumingMemoryBound(to: TestStruct.self)

testStructPtr.pointee.prop1 = 24
testStructPtr.pointee.prop2 = 1.2
testStructPtr.pointee.prop3 = false
}

Both solutions assume that the struct still exists when the callback
is called, since passing a pointer around does not ensure the
lifetime of the pointed-to struct.

As an alternative, consider to use an instance of a class instead.
Passing retained or unretained pointers to the instance allows to control
the lifetime of the object while the callback is "active", compare
How to cast self to UnsafeMutablePointer<Void> type in swift.

How can I refer to properties from a struct within a struct/

First of all you are mixing types with objects so you should have a type House

struct House {
let name: String
let characteristic: String
let image: Image
}

And then use that in the Wizard struct

struct Wizard {
let name: String
var house: House
}

And now you create first a House object for the Wizard and then the Wizard object

let gryffindor = House(name: "Gryffindor", characteristic: "Brave", image: Image("Lion"))
let harryPotter = Wizard(name: "Harry", house: gryffindor)

or all in one call

let harryPotter = Wizard(name: "Harry", 
house: House(name: "Gryffindor", characteristic: "Brave", image: Image("Lion")))

How to deal with relationships with structs in Swift?

You were told to use structs instead of classes? You've been had. Or you just didn't understand whatever advice you got properly.

structs are value types. Classes are reference types. That means you can't have references to structs. Two structs = two different objeccts = twice the memory. You can have references to class instances.

Say you have 1000 players all playing the same game. With structs, you have 1000 copies of the game. Worse, the game would have a copy of each player, which each would have a copy of the game, which would have a copy of each player, which each would have a copy of the game, and so on forever.

That's why you make Player and Game classes.



Related Topics



Leave a reply



Submit