Не спорт, совместное использование типов значений в качестве ссылочных типов

Как всегда с более продвинутыми функциями Swift, необходимо подумать, подходит ли эта функция для ситуации, которую вы сейчас видите.

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

Добро пожаловать в бокс!

Сложность: Новичок | Легко| Нормальный | Сложно

Предпосылки:

  • Уметь создавать Hello, World! iOS-приложение (гид ЗДЕСЬ)
  • Знайте, когда использовать класс или структуру в конкретных ситуациях (руководство ЗДЕСЬ)

Терминология

Бокс: процесс преобразования типа значения в ссылочный тип

Класс: объект, который определяет общие свойства и методы, используя семантику передачи по ссылке.

Ссылка: указатель на переменную или объект

Ссылочный тип: тип, который означает, что экземпляры имеют единственную копию данных.

Struct: объект, определенный в Swift, с использованием семантики передачи по значению.

Значение: то, что будет храниться в переменной

Тип значения: тип, означающий, что каждый экземпляр имеет копию данных.

Простые структуры

Structs являются value types, что означает, что они обычно выбираются вместо классов (которые являются reference types), поскольку их использование означает, что код, вероятно, будет легче поддерживать, а также легче отлаживать.

Value types не используются в нескольких местах вашего приложения, а копируются. Следующая демонстрация объясняет, как можно скопировать struct.

Использование структуры

Одним из возможных value type является struct, и мы можем хранить данные в свойствах этого data type.

struct Person {
    var name: String
    var age: Int
}

и мы можем объявить отдельного человека, что

let steve = Person(name: "Steve", age: 22)

теперь это, как упоминалось выше, value type.

Поэтому мы можем создать копию struct, а затем изменить этот struct, не изменяя исходный экземпляр. Это выглядит примерно так:

var secondSteve = steve
secondSteve.age = 33

Когда мы печатаем, два экземпляра (steve и secondSteve) действительно имеют разный возраст — 22 и 33 года соответственно.

print (steve) // Person(name: "Steve", age: 22)
print (secondSteve) // Person(name: "Steve", age: 33)

Мини-вывод из этого состоит в том, что когда мы передаем value type (контроллерам представления или где-либо еще), создается копия — и мы можем не захотеть, чтобы наша структура имела свойства value type — временно и в ситуации, когда мы хотим поделиться Struct в приложении для iOS.

Использование контейнера класса

Заключение Person в Class будет означать, что вы можете поделиться Class (называемым ниже PersonBoxed), и он будет рассматриваться как class (и под этим, в частности, мы подразумеваем это будет рассматриваться как reference type)

class PersonBoxed {
    var person: Person
    init(person: Person) {
        self.person = person
    }
}

Создание экземпляра PersonBoxed может быть затем создано и создано с помощью Person Struct:

let personBoxed = PersonBoxed(person: steve)

Итак, как и прежде, мы создаем второй экземпляр personBoxed и выбираем другой возраст для этого человека. Сложно получить доступ к человеку в поле, а затем к возрасту в этом поле, но синтаксис должен быть достаточно ясным:

var secondPersonBoxed = personBoxed
secondPersonBoxed.person.age = 33

Поскольку мы используем семантику reference, этот secondPersonBoxed фактически указывает на один и тот же экземпляр

print (personBoxed.person) // Person(name: "Steve", age: 33)
print (secondPersonBoxed.person) // Person(name: "Steve", age: 33)

Так что действительно, наш Struct теперь преподносится как Class, чего можно было ожидать, когда мы завернули наш Struct в Class. С точки зрения справочной семантики, соблюдается именно этот набор правил.

Вывод

Бокс позволяет нам рассматривать value types как reference types. Разница может показаться довольно технической и неактуальной для многих программистов.

Однако, если вы хотите использовать семантику reference, и вы можете захотеть сделать это для модели в вашем приложении (например, создание копии модели для каждого контроллера представления было бы катастрофой), представьте, что у вас есть простой переключатель это может включить семантику reference.

Это точно. Мы включаем семантику reference для тех value types, которые мы выбираем; когда и где мы решим это сделать.

Фантастико.

Код

Это довольно коротко, так что вот вся копи-паста для этой статьи в виде GIST:

Расширьте свои знания

  • Предложения Swift Evolution для данных предлагаются ЗДЕСЬ

Контакт в Твиттере:

Любые вопросы? Связаться со мной можно здесь