mercredi 27 décembre 2017

Flyweight design pattern with Swift SceneKit. Object-reuse

I'm building an augmented-reality iPhone application, and it will require a large amount of SceneKit nodes to be rendered. I want to integrate the Flyweight design pattern described in Design Patterns by Gamma, Helm, Johnson, and Vlissides. Also tutorial here Flyweight Design Pattern However, I'm running into issues with the implementation and how Swift handles objects.

TL;DR: Is there a way in Swift where I can add the same SCNNode to a ARSCNView more than once and have it be displayed in different positions?

I have a class called Box which builds SCNBoxs which I want to leverage Flyweight on; the intrinsic state of a Box is the dimensions. The extrinsic state is its color and position.

Box Class

class Box {
    var size:CGFloat
    var position:(Float, Float, Float)
    var color:UIColor
    var node:SCNNode!

    init(color:UIColor){
        self.color = color
        /*Set the following below as default values*/
        self.size = CGFloat(0.05) //Side length
        self.position = (0,0,0)
        self.createBox()
    }

    private func createBox() -> Void {
        /*Creating box and setting its color*/
        self.node = SCNNode(geometry: SCNBox(width: size, height: size, length: size, chamferRadius: 0))
        self.node.geometry?.firstMaterial?.diffuse.contents = self.color
    }

    func draw(sceneView: ARSCNView) -> Void {
        sceneView.scene.rootNode.addChildNode(self.node)
    }
}

I have a factory class which implements the design with a dictionary checking if previous objects of the same color, if so reuse the object, else create a new one.

Factory Class

class BoxFactory{
    var hash:[UIColor:Box] = [UIColor:Box]()
    func getBox(color c:UIColor) -> Box {
        /*Check if box of color c already exists*/
        if(self.hash[c] != nil){
            return self.hash[c]!
        }
        /*Create a new box if it does not*/
        let b:Box = Box(color: c)
        self.hash[c] = b
        return b
    }
}

And some view controller which hold an ARSCNView object to display the boxes.

let factory:BoxFactory = BoxFactory()

/*Create two boxes of same color. One on the left and on the right*/
let leftBox:Box = factory.getBox(color: UIColor.green)
leftBox.position = (-0.1,0,0)
leftBox.draw(sceneView: self.sceneView)

let rightBox:Box = factory.getBox(color: UIColor.green)
rightBox.position = (0.1,0,0)
rightBox.draw(sceneView: self.sceneView)

However, this only produces one green box; the right one. The second getBox() call overrides the first's position Image below. Does anyone have any advice, for the implementation of this pattern, or Swift, that can help achieve this pattern of object reuse?

*Side Note: I don't necessary want to hash the object's position along with its color. Being that I'll have many Boxes of different color and position, it'll defeat the whole idea of reusing the same object.

Only one green box

Aucun commentaire:

Enregistrer un commentaire