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

s1ag04yj  于 2023-03-11  发布在  Swift
关注(0)|答案(8)|浏览(222)

在Swift中,我尝试创建一个64个SKSpriteNode的数组。我想首先将其初始化为空,然后将Sprites放入前16个单元格和后16个单元格(模拟一场国际象棋比赛)。
从我对该文档的理解来看,我会预期如下内容:
var sprites = SKSpriteNode()[64];

var sprites4 : SKSpriteNode[64];
但它不起作用。在第二种情况下,我得到一个错误消息:“还不支持定长数组”。这是真实的的吗?对我来说,这听起来像是一个基本特性。我需要通过索引直接访问元素。

fhg3lkii

fhg3lkii1#

固定长度的数组还没有被支持,这到底意味着什么?并不是说你不能创建一个n的数组,很多东西-显然你可以只做let a = [ 1, 2, 3 ]来得到一个三个Int的数组。这仅仅意味着数组大小不是你可以声明 * 作为类型信息 * 的东西。
如果你想要一个nil的数组,你首先需要一个可选类型的数组--[SKSpriteNode?],而不是[SKSpriteNode]--如果你声明了一个非可选类型的变量,不管它是一个数组还是一个单值,它都不能是nil。(还要注意,[SKSpriteNode?][SKSpriteNode]?不同......您需要的是可选数组,而不是可选数组。)
Swift在设计上非常明确地要求初始化变量,因为对未初始化引用内容的假设是C(和其他一些语言)程序出错的原因之一,所以,你需要明确地要求一个包含64个nil[SKSpriteNode?]数组:

var sprites = [SKSpriteNode?](repeating: nil, count: 64)
tkqqtvp1

tkqqtvp12#

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

var sprites = [SKSpriteNode?](count: 64, repeatedValue: nil)

然后,您可以填充所需的任何值。
Swift 3.0中:

var sprites = [SKSpriteNode?](repeating: nil, count: 64)
wh6knrhe

wh6knrhe3#

这个问题已经得到了回答,但在Swift 4发布时需要一些额外的信息:
考虑到性能,您应该为数组保留内存,以便动态创建数组,例如使用Array.append()添加元素。

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

for _ in 0..<64 {
    array.append(SKSpriteNode())
}

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

ugmeyewa

ugmeyewa4#

声明一个空的SKSpriteNode,这样就不需要展开

var sprites = [SKSpriteNode](count: 64, repeatedValue: SKSpriteNode())
mccptt67

mccptt675#

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

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)

但这(1)使用起来非常不舒服,(2)内存布局没有定义。(至少我不知道)

bqucvtff

bqucvtff6#

雨燕4

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

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

1.创建一个具有64 defaultSKSpriteNode的数组:

var sprites = [SKSpriteNode](repeatElement(SKSpriteNode(texture: nil),
                                           count: 64))

1.创建具有64个空插槽的阵列(也称为 * 可选 *):

var optionalSprites = [SKSpriteNode?](repeatElement(nil,
                                      count: 64))

1.将可选数组转换为对象数组(将[SKSpriteNode?]折叠为[SKSpriteNode]):

let flatSprites = optionalSprites.flatMap { $0 }

结果flatSpritescount取决于optionalSprites中的对象数:空的选项将被忽略,即跳过。

fgw7neuy

fgw7neuy7#

如果你需要一个固定大小的数组,并且用nil值初始化它,你可以使用一个UnsafeMutableBufferPointer,用它为64个节点分配内存,然后通过下标指针类型示例从内存中读取/写入内存。然而,如果编译器没有为那些除了在创建位置之外不再调用可能需要调整大小的方法的数组进行优化,我会感到惊讶。

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

但是这对用户来说不是很友好。所以,让我们做一个 Package 器吧!

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;
    }
}

现在,这是一个类,而不是一个结构,所以这里会产生一些引用计数开销,你可以把它改为struct,但是因为Swift没有提供在结构上使用复制初始化器和deinit的能力,所以你需要一个deallocation方法(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!)
}

有关实现一致性的更多协议,请参见Array documentation(滚动到 * 关系 *)。

cotxawn7

cotxawn78#

你可以做的一件事就是创建一个字典。考虑到你要寻找64个元素,这可能有点草率,但它完成了任务。我不确定这是否是“首选的方式”,但它对我使用结构体数组很有效。

var tasks = [0:[forTasks](),1:[forTasks](),2:[forTasks](),3:[forTasks](),4:[forTasks](),5:[forTasks](),6:[forTasks]()]

相关问题