Swift SpriteKit 使用 struct 而不是 class 来渲染精灵
Swift SpriteKit use struct instead of class to render sprites
我最近一直在更新我的游戏以使用更多的值类型。在某些情况下,我对 weak 和 unowned 仍然不是 100% 有信心,所以我采用结构方式来避免强引用循环。根据 apples 较新的主题演讲,值类型似乎是大多数情况下的方法。
我从未见过在 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()
现在即使我在同一个场景中创建多个标志,我似乎也没有问题。
我只是好奇,因为我从来没有真正见过这样的例子,所以我想知道我是否遗漏了什么,比如性能缺陷等。
感谢您的帮助。
我个人避免创建包含 Classes
的 Structs
。因为 Structs
副本,每个在您的应用中传递的副本都会增加 Classes
的引用计数。这使得管理它们变得更难而不是更容易。
看看 UIKit
如何使用 Structs
也很有用。 UIView
是一个对象,但具有许多 Structs
的定义属性。例如 frame
.
将下面的代码放在 playground 中以查看此行为的一些效果。
protocol
只是为了从 playground 获得一些有意义的反馈。
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 optionals
在 Value 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()
我最近一直在更新我的游戏以使用更多的值类型。在某些情况下,我对 weak 和 unowned 仍然不是 100% 有信心,所以我采用结构方式来避免强引用循环。根据 apples 较新的主题演讲,值类型似乎是大多数情况下的方法。
我从未见过在 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()
现在即使我在同一个场景中创建多个标志,我似乎也没有问题。 我只是好奇,因为我从来没有真正见过这样的例子,所以我想知道我是否遗漏了什么,比如性能缺陷等。
感谢您的帮助。
我个人避免创建包含 Classes
的 Structs
。因为 Structs
副本,每个在您的应用中传递的副本都会增加 Classes
的引用计数。这使得管理它们变得更难而不是更容易。
看看 UIKit
如何使用 Structs
也很有用。 UIView
是一个对象,但具有许多 Structs
的定义属性。例如 frame
.
将下面的代码放在 playground 中以查看此行为的一些效果。
protocol
只是为了从 playground 获得一些有意义的反馈。
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 optionals
在 Value 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()