Swift SpriteKit使用结构而不是类来渲染精灵

Swift SpriteKit使用结构而不是类来渲染精灵,swift,struct,skspritenode,Swift,Struct,Skspritenode,我最近一直在更新我的游戏,以使用更多的值类型。在某些情况下,我对弱引用和无主引用仍然没有100%的信心,所以我选择了struct方法来避免强引用循环。根据苹果公司最新的基调,价值类型似乎在很大程度上是可行的 我从未见过在spriteKit游戏中使用结构渲染精灵的例子,所以我想知道它的缺点是什么。 我知道它们是复制的,没有被引用,但对于我的使用来说,它似乎是有效的 所以,基本上我在做这件事的时候需要注意些什么吗 struct Flag { let post: SKSpriteNode

我最近一直在更新我的游戏,以使用更多的值类型。在某些情况下,我对弱引用和无主引用仍然没有100%的信心,所以我选择了struct方法来避免强引用循环。根据苹果公司最新的基调,价值类型似乎在很大程度上是可行的

我从未见过在spriteKit游戏中使用结构渲染精灵的例子,所以我想知道它的缺点是什么。 我知道它们是复制的,没有被引用,但对于我的使用来说,它似乎是有效的

所以,基本上我在做这件事的时候需要注意些什么吗

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
   }
}
而在我的场景中,我只是像往常一样添加它们

 let flag = Flag(postImage: "FlagPostImage", flagImage: "FlagImage")
 flag.post.position = ...
 addChild(flag.post)
 flag.animate()
现在,即使我在同一个场景中创建了多个标志,我似乎也没有问题。 我只是好奇,因为我从来没有真正看到过这样的例子,所以我想知道我是否遗漏了一些东西,比如性能缺陷等


谢谢您的帮助。

我个人避免创建包含
类的
结构。因为
Structs
copy,在应用程序中传递的每个副本都会增加
类的引用计数。这使得管理它们变得更加困难,而不是更容易

了解
UIKit
如何使用
Structs
,也很有用。
UIView
是一个对象,但有许多定义属性是
Structs
。例如,它是

把下面的代码放到操场上,看看这种行为的效果。
协议
只是为了从操场上获得一些有意义的反馈

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()

值类型
中使用
引用类型
非常容易的一种模式是将它们作为
弱选项
存储在
值类型
中。这意味着某些东西需要有一个
强引用
,但很可能一些
将负责创建
结构
,这是一个保存
强引用
的好地方

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()

其中一个缺点是它会降低代码的可读性。仅将位于结构内部的post对象添加到场景中,然后对整个flag对象设置动画。如果你的flag结构是黑框的,人们会问“为什么我只在场景中添加post而不添加flag?”。另一个缺点是有时您希望多个引用挂起,特别是如果您正在进行测试,如
if isKindOf skphysiccontact
,以确定您是否正在处理
skphysiccontact
,那么您可以使用一个函数来处理skphysiccontact,而无需创建新对象,就我个人而言,我避免创建包含类的结构。因为
Structs
copy,在应用程序中传递的每个副本都会增加
类的引用计数。这使得管理它们变得更难,而不是更容易。谢谢你R Menke,你的回答完全有道理,我以后将避免使用包含类的结构。我知道这不可能那么容易,我很高兴你的回答,因为我会让我的生活更加艰难。我仍然是一个新手,有时只是想到我自己创建的类,忘记了像SKSpriteNode这样的东西也被视为引用计数类等。如果你愿意,你可以将你的评论复制到一个答案中,我会将其标记为正确。再次感谢您的回答,非常详细。非常感谢你