【问题标题】:Swift SpriteKit use struct instead of class to render spritesSwift SpriteKit 使用 struct 而不是 class 来渲染精灵
【发布时间】:2016-03-03 13:53:12
【问题描述】:

我最近一直在更新我的游戏以使用更多的值类型。在某些情况下,我对弱和无主仍然不是 100% 有信心,所以我采用了结构方式来避免强引用循环。根据苹果较新的主题演讲,无论如何,价值类型似乎是它们的主要方式。

我从未见过在 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
   }
}

与我的 SKScenes 相比,我只是像往常一样添加它们

 let flag = Flag(postImage: "FlagPostImage", flagImage: "FlagImage")
 flag.post.position = ...
 addChild(flag.post)
 flag.animate()

现在,即使我在同一个场景中创建多个标志,这种方式似乎也没有问题。 我只是好奇,因为我从来没有真正见过这样的例子,所以我想知道我是否遗漏了一些东西,比如性能缺陷等。

感谢您的帮助。

【问题讨论】:

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

标签: swift struct skspritenode


【解决方案1】:

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

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

将下面的代码放在游乐场中,以查看此行为的一些效果。 protocol 只是为了从操场上获得一些有意义的反馈。

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

Value Types 中使用Reference Types 很容易的一种模式是将它们存储为weak optionalsValue Types 中。这意味着某些东西需要有strong reference,但很可能一些Class 将负责创建Structs,这是保留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()

【讨论】:

  • 很棒的答案,非常详细。非常感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多