source

개체의 고정 크기 배열을 만드는 방법

factcode 2023. 10. 11. 21:02
반응형

개체의 고정 크기 배열을 만드는 방법

Swift에서 64개의 SKSpriteNode 배열을 만들고자 합니다.저는 먼저 빈 초기화를 하고, 처음 16셀과 마지막 16셀에 스프라이트를 넣고 싶습니다(체스 게임 시뮬레이션).

제가 문서에서 이해한 바에 의하면, 저는 다음과 같은 것을 기대할 수 있습니다.

var sprites = SKSpriteNode()[64];

아니면

var sprites4 : SKSpriteNode[64];

하지만 효과가 없습니다.두 번째 경우 "고정 길이 배열은 아직 지원되지 않습니다."라는 오류가 나타납니다.그게 진짜일까요?저에게는 그것이 기본적인 특징으로 들립니다.나는 그들의 색인으로 직접 요소에 접근해야 합니다.

고정 길이 배열은 아직 지원되지 않습니다.그게 실제로 무슨 뜻입니까?다음의 배열을 만들 수 없다는 것은 아닙니다.n많은 것들 – 당연히 당신은 그냥 할 수 있습니다.let a = [ 1, 2, 3 ]3열의 배열을 얻다Ints. 이는 단순히 배열 크기가 유형 정보로 선언할 수 있는 것이 아니라는 것을 의미합니다.

만약 당신이 배열을 원한다면nils, 먼저 옵션 유형의 배열이 필요합니다.[SKSpriteNode?],것은 아니다.[SKSpriteNode]— 배열이든 단일 값이든 선택적이지 않은 유형의 변수를 선언하면 다음과 같이 될 수 없습니다.nil. (참고:[SKSpriteNode?]와는 다릅니다.[SKSpriteNode]?... 옵션 배열이 아닌 옵션 배열을 원합니다.)

스위프트는 초기화되지 않은 참조의 내용에 대한 가정이 C(및 일부 다른 언어)의 프로그램이 버그가 될 수 있는 방법 중 하나이기 때문에 변수를 초기화하도록 요구하는 것에 대해 설계상 매우 명확합니다.그래서, 당신은 명시적으로 요청할 필요가 있습니다.[SKSpriteNode?]64를 포함하는 배열nils:

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

지금은 초기 카운트가 0을 반복하는 배열을 만드는 것이 최선입니다.

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

그런 다음 원하는 값을 입력할 수 있습니다.


In Swift 3.0:

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

이 질문은 이미 답변을 마쳤지만, Swift 4 당시 추가 정보에 대해서는 다음과 같습니다.

성능의 경우 다음과 같은 요소를 추가하는 것과 같이 동적으로 생성하는 경우에는 어레이에 대한 메모리를 예약해야 합니다.Array.append().

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

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

만약 당신이 그것에 추가할 최소 요소의 양을 알고 있지만, 최대 양은 알고 있지 않다면, 당신은 오히려 그것을 사용해야 합니다.array.reserveCapacity(minimumCapacity: 64).

포장을 풀 필요가 없도록 SKSpriteNode가 비어 있음을 선언합니다.

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

현재로서는 의미론적으로 가장 가까운 것은 고정된 수의 요소가 있는 튜플일 것입니다.

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) 메모리 레이아웃이 정의되어 있지 않습니다.(최소한 나에게는 알려지지 않은)

스위프트 4

개체 배열 대 참조 배열로 어느 정도 생각할 수 있습니다.

  • [SKSpriteNode]다를(를) .
  • [SKSpriteNode?]할 수 .nil

  1. 64 기본값으로 배열 만들기 SKSpriteNode:

    var sprites = [SKSpriteNode](repeatElement(SKSpriteNode(texture: nil),
                                               count: 64))
    
  2. 64개의 빈 슬롯이 있는 배열 만들기(: 옵션):

    var optionalSprites = [SKSpriteNode?](repeatElement(nil,
                                          count: 64))
    
  3. (collapsing))[SKSpriteNode?]안으로[SKSpriteNode]):

    let flatSprites = optionalSprites.flatMap { $0 }
    

    countf의flatSprites다의 .optionalSprites: 빈 옵션은 무시됩니다. 즉, 건너뛸 수 있습니다.

하여 초기화합니다.nil값들, 당신은 사용할 수 있습니다.UnsafeMutableBufferPointer64 /)를.를 재할당해야 를 확인하는 것을 수 다.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()

그러나 이것은 그다지 사용자 친화적이지 않습니다.자, 포장지를 만들어 봅시다!

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

에 기준 입니다, . 그래서 여기에 약간의 참조 계산 오버헤드가 발생합니다.로합니다.structd를 할 수 있는 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!)
}

호환성 구현을 위한 프로토콜에 대한 자세한 내용은 배열 설명서(관계로 스크롤)를 참조하십시오.

당신이 할 수 있는 한 가지 일은 사전을 만드는 것입니다.64가지 요소를 찾는다는 것을 고려하면 약간 엉성할 수도 있지만 일은 끝납니다.그것을 하는 것이 "선호되는 방법"인지 확실하지 않지만 여러 구조물을 사용하는 것이 저에게는 효과가 있었습니다.

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

언급URL : https://stackoverflow.com/questions/24395105/how-to-create-a-fixed-size-array-of-objects

반응형