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

Swift/iOS: как использовать параметры inout в функциях с AnyObject/Any или Pointers

Я пытаюсь написать функцию, которая принимает указатель переменной и дескриптор/ключ и устанавливает новое значение для переменной. В идеале указатель должен быть либо объектом, либо примитивом, но я также мог бы жить с отдельными функциями (или дополнительным параметром). В моем коде я извлекаю новое значение из базы данных также с помощью ключа, но в следующем примере я упростил его с помощью фиктивных значений, чтобы его можно было легко использовать на игровой площадке:

import UIKit

func setValue(inout object: AnyObject, key: String) {
    switch key {
    case "String":
        object = "A String"
    case "UIColor":
        object = UIColor.whiteColor()
    case "Bool":
        object = true
    default:
        println("Unhandled key: \(key)")
    }
}

var string: String = "Default String"
var color: UIColor = UIColor.blackColor()
var bool: Bool = false

setValue(&string, "String")
setValue(&color, "UIColor")
setValue(&bool, "Bool")

Я получаю следующую ошибку:

"Не удается вызвать setValue со списком аргументов типа "(inout String, key String)""

Я понимаю, что здесь я смешиваю объекты и примитивы. Я также пытался разбить его и разделить на две функции, но даже это не удалось:

func setValue(inout object: AnyObject, key: String) {
    switch key {
    case "UIColor":
        object = UIColor.whiteColor()
    default:
        println("Unhandled key: \(key)")
    }
}

var color: UIColor = UIColor.blackColor()
setValue(&color, "UIColor")

Это также дает ту же ошибку:

"Невозможно вызвать setValue со списком аргументов типа "(inout UIColor, key String)""

Если я изменю «AnyObject» на «UIColor», это сработает, но смысл функции в том, что она принимает любой тип переменной или, по крайней мере, любой тип объекта (тогда я бы написал вторую функцию, используя «Any» для примитивов, или добавил другой параметр)

В Objective-C я использовал указатели, перенос подхода на Swift также не работает, тот же результат:

func setValue(object: UnsafeMutablePointer<AnyObject>, key: String) {
    switch key {
    case "String":
        object.memory = "A String"
    case "UIColor":
        object.memory = UIColor.whiteColor()
    case "Bool":
        object.memory = true
    default:
        println("Unhandled key: \(key)")
    }
}

Кто-нибудь знает, что мне здесь не хватает? Любая помощь высоко ценится!

Спасибо!


Ответы:


1

Лучше вы можете создать общий метод, как показано ниже:

func setValue<T>(inout object:T, key: String) {
    switch key {
    case "String":
        object = ("A String" as? T)!
    case "UIColor":
        object = (UIColor.whiteColor() as? T)!
    case "Bool":
        object = (true as? T)!
    default:
        println("Unhandled key: \(key)")
    }
}

И вызов будет таким:

setValue(&string, key: "String")
setValue(&color, key: "UIColor")
setValue(&bool, key: "Bool")

Надеюсь, поможет!

30.04.2015
  • Если вы собираетесь использовать принудительное приведение (и, пожалуйста, не делайте этого, есть решения получше), вы можете сделать value as! Thing, а не (value as? Thing)!. 30.04.2015
  • Это то, что я искал! Большое спасибо! 30.04.2015
  • Я боролся с тем же сообщением об ошибке, что и ОП, поэтому спасибо за этот ответ! Я до сих пор не совсем понимаю, зачем нам нужно использовать универсальную функцию, если мы просто пытаемся привести подкласс к его суперклассу. 01.10.2015

  • 2

    Правильный способ сделать это — использовать перегрузку и позволить компилятору выбрать соответствующий фрагмент кода во время компиляции вместо отключения строки во время выполнения:

    func setValue(inout object: String) {
        object = "A String"
    }
    
    func setValue(inout object: UIColor) {
        object = UIColor.whiteColor()
    }
    
    func setValue(inout object: Bool) {
        object = true
    }
    
    func setValue(inout object: Any) {
        println("Unhandled key: \(key)")
    }
    

    Этот подход не сработает, если у вас есть Any и вы хотите указать функции, какой тип содержится в Any… но в этом случае у вас возникают проблемы из-за того, что компилятор действительно знает каковы типы, так что вы можете воспользоваться этим.

    30.04.2015
  • Большое спасибо! Для простого примера отличное решение. В моем коде я бы предпочел использовать его в одном методе, так как есть также код для извлечения значения из БД. 30.04.2015
  • Вынесите этот код в отдельную функцию, а затем вызовите его из перегруженных вызовов… 30.04.2015

  • 3

    -Используйте Any вместо AnyObject для охвата типов значений и структур.

    -Возможно, вам потребуется выполнить приведение к Any перед вызовом вашего метода.

    Пример:

    func swapAny( inout obj1: Any, inout obj2: Any )
    {
        let temp = obj1
        obj1 = obj2
        obj2 = temp
    }
    

    использовать:

    var fooString: Any = "Foo"
    var barString: Any = "Bar"
    
    swapAny(&fooString, obj2: &barString)
    println(fooString)//prints "Bar"
    
    30.04.2015
  • Это не будет работать в сочетании с inout (ну, это может скомпилироваться… но, вероятно, не будет иметь желаемого эффекта) 30.04.2015
  • Добавлен пример, который компилируется и ведет себя так, как ожидалось. Что вы подразумеваете под "не будет иметь желаемого эффекта"? 30.04.2015
  • Это не приведение (т.е. someVar as Any), это объявление самих значений типа Any. Однако, предположительно, у спрашивающего есть значения типа String, и он хочет манипулировать этой строкой на месте. Ваше предложение требует, чтобы они объявили этот тип как Any. В большинстве случаев есть лучшие способы (например, перегрузка или дженерики). Any редко бывает хорошим выбором. 30.04.2015
  • Спасибо за отзыв. У меня такое ощущение, что шаблон, который реализует ОП, сам по себе может быть не самым подходящим... 30.04.2015

  • 4

    Поддержка протокола для inout

    Когда вы приводите класс к протоколу, вы получаете неизменяемую ссылку, которую нельзя использовать в параметрах функции inout. Так что вы можете:

    1. Используйте перегрузку методов (которая может дублировать ваш код и затруднить его чтение, даже если вы проводите рефакторинг).
    2. Не используйте inout (это то, что вы должны сделать)
    3. Или вы можете сделать это:

    -

    protocol IPositional{
        func setPosition(position:CGPoint)
    }
    extension IPositional{
        var positional:IPositional {get{return self as IPositional}set{}}
    }
    class A:IPositional{
        var position:CGPoint = CGPoint()
        func setPosition(position:CGPoint){
            self.position = position
        }
    }
    func test(inout positional:IPositional){
        positional.setPosition(CGPointMake(10,10))
    }
    var a = A()
    test(&a.positional)
    a.position//output: (10.0, 10.0)
    

    Вывод:
    Преимущество этого способа: теперь у вас может быть один "inout-метод" для всех классов, реализующих IPositional. Но я рекомендую использовать вариант 2. (Не использовать inout)

    30.11.2015

    5

    Тип объекта должен соответствовать типу параметра, включая AnyObject:

    func setValue(inout object: AnyObject, key: String) {
        switch key {
        case "String":
            object = "A String"
        case "UIColor":
            object = UIColor.whiteColor()
        case "Bool":
            object = true
        default:
            print("Unhandled key: \(key)")
        }
    }
    
    var string: AnyObject = "Default String"
    var color: AnyObject = UIColor.blackColor()
    var bool: AnyObject = false
    
    setValue(&string, key: "String")
    setValue(&color, key: "UIColor")
    setValue(&bool, key: "Bool")
    
    20.12.2015
    Новые материалы

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

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

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

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

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

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

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