1

I have two block of codes

func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
  // BLOCK 1 Which is not working 
    guard let planeAnchor = anchor as? ARPlaneAnchor else { return }

    var plane = Plane(with: planeAnchor) //IT IS SUBCLASS OF SCNNode
    var geo = plane.geometry
    plane.transform = SCNMatrix4MakeRotation(-.pi / 2, 1, 0, 0)

    update(&plane, withGeometry: plane.geo, type: .static)

   //Up here Cannot pass immutable value as inout argument: implicit conversion from 'Plane' to 'SCNNode' requires a temporary

    node.addChildNode(plane)

   // BLOCK 2 Which is working 


    let width = CGFloat(planeAnchor.extent.x)
    let height = CGFloat(planeAnchor.extent.z)
    let plane1 = SCNPlane(width: width, height: height)

    plane1.materials.first?.diffuse.contents = UIColor.white.withAlphaComponent(0.5)

    var planeNode = SCNNode(geometry: plane1)

    let x = CGFloat(planeAnchor.center.x)
    let y = CGFloat(planeAnchor.center.y)
    let z = CGFloat(planeAnchor.center.z)
    planeNode.position = SCNVector3(x,y,z)
    planeNode.eulerAngles.x = -.pi / 2

    update(&planeNode, withGeometry: plane1, type: .static)
    // WORKING FINE

    node.addChildNode(planeNode)

    self.planes[anchor.identifier] = plane

}

BLOCK1

I have subclass class Plane: SCNNode when I try to pass it's object to function which required inout it shows me error

Cannot pass immutable value as inout argument: implicit conversion from 'Plane' to 'SCNNode' requires a temporary

While if I remove subclass then it is working fine

Why this is it swift bug or I am missing anything?

Prashant Tukadiya
  • 15,838
  • 4
  • 62
  • 98

2 Answers2

1

Inout will not work with Subclass

Here is example

class SuperClass {
    var name = "Prashant"

}

class TestObject:SuperClass {
}


func updateTemp ( object:inout SuperClass) {
    object.name = "P.T"
}

Now when you create TestObject object which is subclass of SuperClass it will not allow to do so.

var obj  = TestObject()
self.updateTemp(object: &obj) // Cannot pass immutable value as inout argument: implicit conversion from 'TestObject' to 'SuperClass' requires a temporary
print(obj.name)

How to fix this

Three ways

1) create object with var obj:SuperClass = TestObject()

2) This actually don't required to be inout as class is reference type

3) Create Generic function like it (Generic is great !! )

func updateTemp<T:SuperClass> ( object:inout T) {
    object.name = "P.T"
} 

Hope it is helpful to someone

Prashant Tukadiya
  • 15,838
  • 4
  • 62
  • 98
0

Since the Plane class is initialized with "init(_ anchor: ARPlaneAnchor)" even it is declared as SCNNode class it returns a different instance than a pure SCNNode as in the Block 2.

I'm not an expert on the mutation subject but think there is an interesting document in Apple blogs The Role of Mutation in Safety

Not really sure but since a class is by nature mutable you probably can move the update function to the Plane class as a (test) solution

Jose Paredes
  • 329
  • 1
  • 8
  • Thanks for answer but Not This is not true !! – Prashant Tukadiya Jun 29 '18 at 04:54
  • Thanks, as I said I’m not an expert so I should find time to try myself. But what part is not true? Have you read the link? – Jose Paredes Jun 29 '18 at 05:00
  • **Since the Plane class is initialized with "init(_ anchor: ARPlaneAnchor)" even it is declared as SCNNode class it returns a different instance than a pure SCNNode as in the Block 2.** both is same , if you create subclass of some other class it will never change in behaviour it will be same like create super class instance – Prashant Tukadiya Jun 29 '18 at 05:05
  • 1
    Hey Jose I apologies , Yes You are right for `inout` It requires the same class object that has been defined. – Prashant Tukadiya Jun 29 '18 at 06:12