如何创建固定大小的对象数组

Hen*_*rre 87 swift xcode6 ios8

在Swift中,我正在尝试创建一个包含64个SKSpriteNode的数组.我想先初始化它空,然后我会把精灵在第16个单元,最后16个单元(模拟的棋局).

根据我在文档中的理解,我会期待如下:

var sprites = SKSpriteNode()[64];

要么

var sprites4 : SKSpriteNode[64];

但它不起作用.在第二种情况下,我得到一个错误说:"还不支持固定长度数组".这可能是真的吗?对我来说,这听起来像一个基本功能.我需要通过索引直接访问元素.

ric*_*ter 134

目前尚不支持定长数组.这究竟意味着什么?并不是说你不能创建n许多东西的数组- 显然你可以做到let a = [ 1, 2, 3 ]三个数组Int.它意味着数组大小不是您可以声明为类型信息的东西.

如果你想要一个nils 数组,你首先需要一个可选类型的数组 - [SKSpriteNode?]不是[SKSpriteNode]- 如果你声明一个非可选类型的变量,无论是数组还是单个值,它都不能nil.(另请注意,这[SKSpriteNode?][SKSpriteNode]?... 不同,您需要一个可选项数组,而不是可选数组.)

Swift在设计上非常明确地要求对变量进行初始化,因为关于未初始化引用的内容的假设是C(和其他一些语言)中的程序可能变成错误的方式之一.因此,您需要明确要求[SKSpriteNode?]包含64 nils 的数组:

var sprites = [SKSpriteNode?](repeating: nil, count: 64)
Run Code Online (Sandbox Code Playgroud)

这实际上返回一个[SKSpriteNode?]?:可选的精灵数组.(有点奇怪,因为init(count:,repeatedValue:)不应该返回nil.)要使用数组,你需要打开它.有几种方法可以做到这一点,但在这种情况下,我赞成可选的绑定语法:

if var sprites = [SKSpriteNode?](repeating: nil, count: 64){
    sprites[0] = pawnSprite
}
Run Code Online (Sandbox Code Playgroud)


dre*_*wag 58

你现在能做的最好的事情就是创建一个初始计数重复为nil的数组:

var sprites = [SKSpriteNode?](count: 64, repeatedValue: nil)
Run Code Online (Sandbox Code Playgroud)

然后,您可以填写所需的任何值.


Swift 3.0中:

var sprites = [SKSpriteNode?](repeating: nil, count: 64)
Run Code Online (Sandbox Code Playgroud)

  • 有没有办法**声明**一个固定大小的数组? (4认同)
  • @AlexanderSupertramp否,无法为数组声明大小 (2认同)
  • @アレックス 无法为数组声明固定大小,但您当然可以创建自己的结构来包装强制固定大小的数组。 (2认同)

Swi*_*ect 6

斯威夫特 4

您可以将其视为对象数组与引用数组。

  • [SKSpriteNode] 必须包含实际对象
  • [SKSpriteNode?] 可以包含对对象的引用,或者 nil

例子

  1. 创建一个默认 为 64 的数组SKSpriteNode

    var sprites = [SKSpriteNode](repeatElement(SKSpriteNode(texture: nil),
                                               count: 64))
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个有 64 个空槽的数组(又名optionals):

    var optionalSprites = [SKSpriteNode?](repeatElement(nil,
                                          count: 64))
    
    Run Code Online (Sandbox Code Playgroud)
  3. 将可选数组转换为对象数组(折叠[SKSpriteNode?][SKSpriteNode]):

    let flatSprites = optionalSprites.flatMap { $0 }
    
    Run Code Online (Sandbox Code Playgroud)

    count由此而来的flatSprites依赖于对象的个数optionalSprites:空自选项目都将被忽略,即跳过。


And*_*er- 6

如果你想要的是一个固定大小的数组,并用nil值初始化它,你可以使用 an UnsafeMutableBufferPointer,用它为 64 个节点分配内存,然后通过下标指针类型实例从内存中读取/写入内存。这还有一个好处是可以避免检查内存是否必须重新分配,而事实Array确实如此。然而,如果编译器没有针对除了创建站点之外不再调用可能需要调整大小的方法的数组进行优化,我会感到惊讶。

let count = 64
let sprites = UnsafeMutableBufferPointer<SKSpriteNode>.allocate(capacity: count)

for i in 0..<count {
    sprites[i] = ...
}

for sprite in sprites {
    print(sprite!)
}

sprites.deallocate()
Run Code Online (Sandbox Code Playgroud)

然而,这对于用户来说不是很友好。那么,我们来制作一个包装纸吧!

class ConstantSizeArray<T>: ExpressibleByArrayLiteral {
    
    typealias ArrayLiteralElement = T
    
    private let memory: UnsafeMutableBufferPointer<T>
    
    public var count: Int {
        get {
            return memory.count
        }
    }
    
    private init(_ count: Int) {
        memory = UnsafeMutableBufferPointer.allocate(capacity: count)
    }
    
    public convenience init(count: Int, repeating value: T) {
        self.init(count)
        
        memory.initialize(repeating: value)
    }
    
    public required convenience init(arrayLiteral: ArrayLiteralElement...) {
        self.init(arrayLiteral.count)
        
        memory.initialize(from: arrayLiteral)
    }
    
    deinit {
        memory.deallocate()
    }
    
    public subscript(index: Int) -> T {
        set(value) {
            precondition((0...endIndex).contains(index))
            
            memory[index] = value;
        }
        get {
            precondition((0...endIndex).contains(index))
            
            return memory[index]
        }
    }
}

extension ConstantSizeArray: MutableCollection {
    public var startIndex: Int {
        return 0
    }
    
    public var endIndex: Int {
        return count - 1
    }
    
    func index(after i: Int) -> Int {
        return i + 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,这是一个类,而不是一个结构,因此这里会产生一些引用计数开销。您可以将其更改为 a struct,但由于 Swift 不提供使用复制初始值设定项和deinit结构体的功能,因此您需要一个释放方法 ( func release() { memory.deallocate() }),并且该结构体的所有复制实例都将引用相同的内存。

现在,这门课可能已经足够好了。它的使用很简单:

let sprites = ConstantSizeArray<SKSpriteNode?>(count: 64, repeating: nil)

for i in 0..<sprites.count {
    sprite[i] = ...
}

for sprite in sprites {
    print(sprite!)
}
Run Code Online (Sandbox Code Playgroud)

有关实现一致性的更多协议,请参阅数组文档(滚动到关系)。


Car*_*s.V 5

声明一个空的SKSpriteNode,因此不需要拆包

var sprites = [SKSpriteNode](count: 64, repeatedValue: SKSpriteNode())
Run Code Online (Sandbox Code Playgroud)

  • 请注意这一点。它将用该对象的相同实例填充数组(可能需要不同的实例) (6认同)

Eon*_*nil 5

就目前而言,在语义上最接近的一个将是具有固定数量元素的元组。

typealias buffer = (
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode,
    SKSpriteNode, SKSpriteNode, SKSpriteNode, SKSpriteNode)
Run Code Online (Sandbox Code Playgroud)

但是,这(1)使用起来非常不舒服,并且(2)内存布局未定义。(至少对我来说是未知的)


And*_*er- 5

这个问题已经得到解答,但是在Swift 4发行时,还有一些其他信息:

为了提高性能,您应该为数组保留内存,以动态创建它,例如使用添加元素Array.append()

var array = [SKSpriteNode]()
array.reserveCapacity(64)

for _ in 0..<64 {
    array.append(SKSpriteNode())
}
Run Code Online (Sandbox Code Playgroud)

如果您知道要添加的最小元素数量,但不知道最大数量,则应该使用array.reserveCapacity(minimumCapacity: 64)