Swift에서 64 SKSpriteNode 배열을 만들려고합니다. 먼저 비워두고 초기화 한 다음 처음 16 개 셀에 스프라이트를, 마지막 16 개 셀 (체스 게임 시뮬레이션)에 넣습니다.
내가 문서에서 이해 한 바에 따르면 다음과 같은 것을 기대했을 것입니다.
var sprites = SKSpriteNode()[64];
또는
var sprites4 : SKSpriteNode[64];
하지만 작동하지 않습니다. 두 번째 경우 “고정 길이 배열은 아직 지원되지 않습니다.”라는 오류가 발생합니다. 그게 진짜일까요? 나에게 그것은 기본 기능처럼 들립니다. 색인으로 직접 요소에 액세스해야합니다.
답변
고정 길이 배열은 아직 지원되지 않습니다. 이것은 실제로 무엇을 의미합니까? n
많은 것의 배열을 만들 수 없다는 것이 아닙니다. 분명히 let a = [ 1, 2, 3 ]
3 개의 배열을 얻기 위해 할 수 있습니다 Int
. 이는 단순히 배열 크기가 유형 정보로 선언 할 수있는 것이 아님을 의미합니다 .
당신의 배열하려면 nil
– S를 먼저 선택 유형의 배열을해야 [SKSpriteNode?]
하지 [SKSpriteNode]
– 당신이 배열 또는 단일 값인지, 비 선택적인 유형의 변수를 선언하는 경우, 그것은 될 수 없습니다 nil
. (또한 옵션 배열이 아닌 옵션 배열을 원하는 [SKSpriteNode?]
것과는 다릅니다 [SKSpriteNode]?
.)
Swift는 초기화되지 않은 참조의 내용에 대한 가정이 C (및 일부 다른 언어)의 프로그램이 버그가 될 수있는 방법 중 하나이기 때문에 변수를 초기화하도록 요구하는 설계 상 매우 명시 적입니다. 따라서 [SKSpriteNode?]
64를 포함 하는 배열 을 명시 적으로 요청해야합니다 nil
.
var sprites = [SKSpriteNode?](repeating: nil, count: 64)
이것은 실제로 [SKSpriteNode?]?
, 선택적 스프라이트의 선택적 배열을 반환합니다 . (조금 이상 init(count:,repeatedValue:)
합니다. nil을 반환 할 수 없어야하기 때문입니다.) 배열을 사용하려면 배열을 풀어야합니다. 이를 수행하는 몇 가지 방법이 있지만이 경우 선택적 바인딩 구문을 선호합니다.
if var sprites = [SKSpriteNode?](repeating: nil, count: 64){
sprites[0] = pawnSprite
}
답변
지금 할 수있는 최선의 방법은 초기 횟수가 nil을 반복하는 배열을 만드는 것입니다.
var sprites = [SKSpriteNode?](count: 64, repeatedValue: nil)
그런 다음 원하는 값을 입력 할 수 있습니다.
에서 스위프트 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
예
-
64 기본값으로 배열 만들기
SKSpriteNode
:var sprites = [SKSpriteNode](repeatElement(SKSpriteNode(texture: nil), count: 64))
-
64 개의 빈 슬롯이있는 어레이 만들기 ( 선택 사항 ) :
var optionalSprites = [SKSpriteNode?](repeatElement(nil, count: 64))
-
오브젝트 (붕괴의 배열로 선택적 항목의 배열을 변환
[SKSpriteNode?]
으로[SKSpriteNode]
)let flatSprites = optionalSprites.flatMap { $0 }
count
결과의가flatSprites
에있는 객체의 수에 따라 달라집니다optionalSprites
: 무시됩니다 빈 선택적 항목, 즉 건너 뜁니다.
답변
원하는 것이 고정 크기 배열이고 nil
값으로 초기화하는 경우을 사용하고 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()
그러나 이것은 매우 사용자 친화적이지 않습니다. 자, 래퍼를 만들어 봅시다!
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
대신 a로 변경할 수 있지만 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!)
}
준수를 구현하는 더 많은 프로토콜은 배열 문서를 참조하십시오 ( 관계로 스크롤 ).
