Swift 3 中相互引用的结构 [英] Structs that refer to each other in Swift 3

查看:23
本文介绍了Swift 3 中相互引用的结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个 CoreData 实体,它们具有一对一的关系.我想基于这个实体创建结构.我的代码:

I have two CoreData entities which have one to one relationship. I want to create structs based on this entities. My code:

struct DetailedPin {
     var pin: Pin?
}

struct Pin {
    var detailedPin: DetailedPin?  
}

但我收到一个错误:值类型DetailedPin"不能有一个引用自身的存储属性.对于 Pin 结构也有同样的错误.我该如何处理这个问题?谢谢.

But I got an error: Value type 'DetailedPin' cannot have a stored property that references itself. And the same error for Pin struct. How can I handle this issue? Thanks.

推荐答案

问题在于 Optional 内联存储其 Wrapped 值(请参阅 Mike Ash 的精彩博文 了解更多关于这个的信息)——意味着一个 Optional 实例(不管它是否是 nil )将至少占用与你希望存储的类型相同的内存量在它的 .some 情况下(Wrapped 类型).

The problem is that an Optional stores its Wrapped value inline (see Mike Ash's fantastic blog post for more info about this) – meaning that an Optional instance (regardless of whether it is nil or not) will occupy at least the same amount of memory as the type you wish to store in its .some case (the Wrapped type).

因此,由于您的 Pin 结构具有 DetailedPin? 类型的属性,而 DetailedPin 具有 Pin?,需要无限存储才能内联存储这些值.

Thus, as your Pin struct has a property of type DetailedPin?, and DetailedPin has a property of type Pin?, infinite storage would be required in order to store these values inline.

因此,解决方案是简单地添加一个间接层.这样做的一种方法是将 Pin 和/或 DetailedPin 设为引用类型(即 class)作为 @dfri 已建议.

The solution therefore is simply to add a layer of indirection. One way of doing this would be to make Pin and/or DetailedPin a reference type (i.e a class) as @dfri has suggested.

然而,如果您希望保留 PinDetailedPin 的值语义,一种选择是创建一个由类实例支持的包装器类型以提供必要的间接:

However, if you wish to keep the value semantics of Pin and DetailedPin, one option would be to create a wrapper type backed by a class instance to provide the necessary indirection:

/// Provides indirection for a given instance.
/// For value types, value semantics are preserved.
struct Indirect<T> {

  // Class wrapper to provide the actual indirection.
  private final class Wrapper {

    var value: T

    init(_ value: T) {
      self.value = value
    }
  }

  private var wrapper: Wrapper

  init(_ value: T) {
    wrapper = Wrapper(value)
  }

  var value: T {
    get {
      return wrapper.value
    }
    set {
      // Upon mutation of value, if the wrapper class instance is unique,
      // mutate the underlying value directly.
      // Otherwise, create a new instance.
      if isKnownUniquelyReferenced(&wrapper) {
        wrapper.value = newValue
      } else {
        wrapper = Wrapper(newValue)
      }
    }
  }
}

您现在可以只对一个(或两个)结构属性使用 Indirect 包装器:

You can now just use the Indirect wrapper for one (or both) of your structs properties:

struct DetailedPin {
  private var _pin = Indirect<Pin?>(nil)

  // Convenience computed property to avoid having to say ".value" everywhere.
  var pin: Pin? {
    get { return _pin.value }
    set { _pin.value = newValue }
  }
}

struct Pin {
  var detailedPin: DetailedPin?
  var foo: String
}

var d = DetailedPin()
var p = Pin(detailedPin: d, foo: "foo")
d.pin = p

// testing that value semantics are preserved...
var d1 = d
d1.pin?.foo = "bar"

print(d.pin?.foo as Any) // Optional("foo")
print(d1.pin?.foo as Any) // Optional("bar")

这篇关于Swift 3 中相互引用的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆