2016-07-25 5 views
6

Мой случай использования основан на следующей модели:Возможно ли реализовать двунаправленное отношение между двумя структурами, используя только постоянные свойства?

struct Person { 
    let name: String 
    let houses: [House] 
} 

struct House { 
    let owner: Person 
} 

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

Используя приведенные выше структуры данных, можно ли создавать экземпляры House и Person так, чтобы существовала взаимосвязь между ними, и объекты по существу указывали друг на друга?

Я предполагаю, что формулировка этого уже несколько вводит в заблуждение, потому что из-за семантики значения struct s они на самом деле не указывают нигде, а содержат только копии значений. Похоже, должно быть очевидно, что невозможно создать эти два объекта с двунаправленными отношениями, но я все еще хотел быть уверенным и задавать здесь эти вопросы!

Очевидным решением было бы также сделать houses и owner переменные, используя var вместо let при объявлении их, то отношения могут быть сохранены в инициализаторе каждого struct:

struct Person { 
    let name: String 
    var houses: [House] 

    init(name: String, houses: [House]) { 
    self.name = name 
    self.houses = houses 
    self.houses = houses.map { (house: House) in 
     var newHouse = house 
     newHouse.owner = self 
     return newHouse 
    } 
    } 
} 


struct House { 
    var owner: Person 

    init(owner: Person) { 
    self.owner = owner 
    var newHouses = self.owner.houses 
    newHouses.append(self) 
    self.owner = Person(name: owner.name, houses: newHouses) 
    } 
} 

Однако, что если я хотите сохранить houses и owner постоянной? Как я уже сказал, кажется очевидным, что это невозможно, но мне интересно, есть ли какой-то фантастический (возможно, функциональный) способ достичь этого? Я думал о lenses, который может использоваться как геттеры и сеттеры при работе с неизменяемыми моделями.

+1

Я бы категорически отказался от создания каких-либо * действительно самореферентных * структур данных в памяти ... в Swift или на любом другом языке программирования. Зачем? Потому что это затрудняет работу менеджера памяти: это может привести к «утечке памяти» из-за циклических ссылок. Также: не делайте эти «справедливые структуры». Пусть они будут «объектами», которыми они, естественно, являются. –

ответ

4

То, что вы описываете, больше похоже на ORM, чем на язык, а также не подходит для обработки типов значений, таких как structs. Как вы ожидаете, что язык узнает, что owner - свойство обратной зависимости от houses и должно поддерживаться соответствующим образом? Это то, что необходимо выполнить с помощью кода, невозможно с помощью языка Swift.

Похоже, вы пытаетесь сохранить какой-то график объектов модели, что является проблемой, которая была решена много раз. Вы должны взглянуть на Realm DB и Core Data, оба из которых предлагают управляемые двунаправленные отношения. Однако вы обнаружите, что ни одна из них не реализована с помощью структур. Проблема с использованием типов значений заключается в том, что они копируются на запись. Как только вы мутируете одну структуру в графе объектов, вам нужно переназначить все связанные вещи с новой, мутированной копией, которая затем в свою очередь мутируется, и ей необходимо будет обновить все связанные структуры . Ссылочная семантика (классы) упрощает сохранение графика объекта, поскольку мутации не создают новые экземпляры.

+0

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

+0

спасибо за редактирование, что делает его еще более ясным! – nburk

+0

@nburk Рад помочь. Основные данные также можно использовать в виде графика памяти с именем «NSInMemoryStoreType». Они оба по-прежнему сильны в качестве диспетчеров графических объектов, упорство в стороне. –

2

То, что вы хотите, невозможно с помощью structs. Ваше текущее решение (с var) работает не так, как вы думаете: все значения являются независимыми копиями. Рассмотрим следующий пример:

let p = Person(name: "Nick", houses: []) 
let h = House(owner: p) 
h.owner.houses 
p.houses 

Поскольку каждая копия является независимым, это означает, что p не то же самое, как h.owner.

Если вам нужна двунаправленная связь, вы должны использовать объекты с указателями weak (чтобы разбить опорный цикл). Кроме того, вы можете подумать, нужно ли вам использовать двунаправленные отношения.

+0

Я решил снять требование о взаимном соединении между объектами, так как я действительно хочу только поэкспериментировать и максимизировать использование типов значений в моем коде, чтобы увидеть, где я сталкиваюсь с проблемами с этим подходом. Спасибо, что помогли! – nburk