Nano Hash - криптовалюты, майнинг, программирование

Возможная ошибка в Swift 3 с неявным мостом многомерных массивов?

В настоящее время я работаю над игрой SpriteKit, написанной на Swift 3.

Когда я пытался сгенерировать SKShapeNodes из точек, хранящихся в многомерном массиве, с помощью init (splinePoints: UnsafeMutablePointer, count: Int) инициализатор, я обнаружил, что просто не удалось использовать функцию неявного моста Swift, а именно путем добавления «&» перед рассматриваемой переменной, чтобы передать ее функции как UnsafeMutablePointer.

Вот изображение воспроизведения ошибки, включая ошибку, в Xcode Playgrounds:

Воспроизведение ошибки на игровой площадке

Ошибка гласит

Невозможно преобразовать значение типа «[CGPoint]» в ожидаемый тип аргумента «CGPoint»

, хотя ссылка на инициализатор явно указывает, что ему нужен указатель на массив CGPoint. Даже в разделе пример, приведенный Apple

Создание узлов формы из точек, это делается именно так:

var points = [CGPoint(x: 0, y: 0),               
              CGPoint(x: 100, y: 100),               
              CGPoint(x: 200, y: -50),               
              CGPoint(x: 300, y: 30),               
              CGPoint(x: 400, y: 20)]         
let linearShapeNode = SKShapeNode(points: &points,                                   
                                  count: points.count)          
let splineShapeNode = SKShapeNode(splinePoints: &points,                                   
                                  count: points.count)

Итак, мой вопрос: почему он не работает, является ли это ошибкой компилятора, а если нет, то как я могу ее исправить.

Обратите внимание, однако, что создание копии массива внутри функции, как это ...

func createPressurePointShape(arm: Int, finger: Int) {
    var tempPoints = pointsArray[arm][finger]
    let shapeNode = SKShapeNode.init(splinePoints: &tempPoints, count: pointsArray[arm][finger].count)
}

... не является решением для меня, потому что в моем реальном приложении переменная будет существовать только для 1 кадра и либо исчезнет, ​​либо впоследствии создаст утечку памяти. Просто тот факт, что это позволяет устранить ошибку, хотя и намекает на ошибку в Swift или Xcode, а не в моем приложении, но я не уверен в этом.

Заранее благодарю за вашу помощь. Вот пример кода, если кто-то захочет поиграть с ним:

//: Playground - noun: a place where people can play

import UIKit
import SpriteKit

let armCount = 4
let fingersPerArm = 4
let pressurePointsPerFinger = 3

private var pointsArray = [[[CGPoint]]](repeating: [], count: Int(armCount))

for armIndex in 0...Int(armCount - 1) {

    for fingerIndex in 0...(fingersPerArm - 1) {

        pointsArray[armIndex].append([])
        for innerIndex in 0..<pressurePointsPerFinger {
            pointsArray[armIndex][fingerIndex].append(CGPoint(x: 0.5, y: 0.5))
        }
    }
}

let exampleArm = 1
let exampleFinger = 1

func createPressurePointShape(arm: Int, finger: Int) {
    let shapeNode = SKShapeNode.init(splinePoints: &pointsArray[arm][finger], count: pointsArray[arm][finger].count)
}

createPressurePointShape(arm: exampleArm, finger: exampleFinger)

Ответы:


1

Вы совершенно правы, это действительно похоже на ошибку. Я отправил здесь отчет. Более минимальный пример:

func foo(_ ptr: UnsafeMutablePointer<Int>) {}

var arr = Array(repeating: Array(0 ..< 5), count: 5)

let i = 0
foo(&arr[i]) // Cannot convert value of type '[Int]' to expected argument type 'Int'

Однако я бы с осторожностью отнесся к предложению передать &pointsArray[arm][finger][0] инициализатору SKShapeNode - это происходит, потому что компилятор просто передает адрес первого элемента в массиве, но я не верю, что это гарантировано . В равной степени компилятор может скопировать первый элемент во временный, передать адрес этого временного элемента, а затем выполнить обратную запись в массив. Это вызовет неопределенное поведение в инициализаторе.

Вместо этого я бы просто создал удобный инициализатор на SKShapeNode, чтобы в первую очередь устранить ошибку и работать с более приятным API:

extension SKShapeNode {

    convenience init(splinePoints: inout [CGPoint]) {
        self.init(splinePoints: &splinePoints, count: splinePoints.count)
    }
}

func createPressurePointShape(arm: Int, finger: Int) {
    let shapeNode = SKShapeNode(splinePoints: &pointsArray[arm][finger])
}

inout по-прежнему не полностью удовлетворителен, поскольку я не верю, что передаваемая память когда-либо видоизменялась (на самом деле это ошибка API SKShapeNode). Однако, если inout был удален, а временная изменяемая переменная была передана вместо init(splinePoints:count:), буфер массива всегда будет скопирован первым (поскольку на него должна быть указана уникальная ссылка), что может быть нежелательно.

08.10.2017

2

Попробуйте указать на первый элемент массива вот так.

var finger = [CGPoint(x: 0.5, y: 0.5), CGPoint(x: 0.5, y: 0.5), CGPoint(x: 0.5, y: 0.5)]
var arm = [finger, finger, finger, finger]
var pointsArray = [arm, arm, arm, arm]

let exampleArm = 1
let exampleFinger = 1

func createPressurePointShape(arm: Int, finger: Int) {
  let shapeNode = SKShapeNode.init(splinePoints: &pointsArray[arm][finger][0], count: pointsArray[arm][finger].count)
}

createPressurePointShape(arm: exampleArm, finger: exampleFinger)
08.10.2017
  • Это происходит, потому что компилятор просто передает адрес первого элемента в массиве, но я не верю, что это гарантировано. В равной степени компилятор может скопировать первый элемент во временный, передать адрес этого временного элемента, а затем выполнить обратную запись в массив. 09.10.2017

  • 3

    Вероятно, вам не хватает количества нажатий (на палец), вот псевдокод:

    let examplePressuePointsPerFinger = 1
    
    func createPressurePointShape(arm: Int, finger: Int, pressurePoint: Int) {
        let shapeNode = SKShapeNode.init(splinePoints: &pointsArray[arm][finger][pressurePoint], count: pointsArray[arm][finger].count)
    }
    
    createPressurePointShape(arm: exampleArm, finger: exampleFinger, pressurePoint: examplePressuePointsPerFinger)
    
    08.10.2017
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..