在处理大型对象时,我通常在iOS中使用"faulting"
或lazy initialization
模式。
每当一个类的属性指向" fat"对象,我创建了一个自定义getter,用于检查iVar
是否为nil
。如果是,则创建fat对象并返回它。如果它不是,它只会返回"脂肪"对象
此属性的容器还订阅了内存警告,当收到内存警告时,它会将iVar
设置为nil
,减少内存占用。如您所见,它与Core Data中的错误非常相似。
我试图在Swift中重现这一点,但到目前为止还没有找到一个体面和优雅的解决方案。
a)首次尝试:延迟存储的属性
这不起作用,因为如果我将属性设置为nil,它将永远保持为零。 "魔术"只有在您第一次访问该属性时才会发生:
struct FatThing{
// I represent something big, which might have to be
// "faulted" (set to nil) when a memory warning
// is received
var bigThing = "I'm fat"
}
class Container {
lazy var fat: FatThing? = FatThing()
}
var c = Container()
c.fat
c.fat = nil
c.fat // returns nil
b)第二次尝试:带有观察员的存储属性
由于缺乏获取观察者,这也失败了。我需要willGet
和didGet
,而不仅仅是willSet
和didSet
。
为什么地球上没有任何观察者?这个半支持的东西叫做观察者的用途是什么?
c)第三次尝试:具有存储辅助属性的计算属性
这是我到目前为止发现的唯一可行的选择,但它像狒狒的后端一样难看!
struct FatThing{
// I represent something big, which might have to be
// "faulted" (set to nil) when a memory warning
// is received
var bigThing = "I'm fat"
}
class Container {
private var _fat : FatThing? // having this extra and exposed var kills my inner child
var fat: FatThing? {
get{
if _fat == nil {
_fat = FatThing()
}
return _fat
}
set{
_fat = newValue
}
}
}
var c = Container()
c.fat
c.fat = nil
c.fat // returns FatThing
使我的代码看起来更简单,更短......
有没有一种简单而优雅的方式来实现它?在像iOS这样的内存不足的环境中,这不是异国情调!
答案 0 :(得分:3)
单独覆盖getter或setter的能力是客观C的特性,在swift中没有对应物。
您可以使用的正确选择是否定的。 3,使用backing属性存储fat数据和计算属性以使其可访问。我同意有一些样板代码,但这是你需要的权衡。
但是,如果经常使用该模式,则可以创建协议:
protocol Instantiable {
init()
}
并在FatThing
struct / class中实现它。接下来,创建一个包含样板代码的通用函数:
func lazyInitializer<T: Instantiable>(inout property: T?) -> T {
if property == nil {
property = T()
}
return property!
}
请注意T
必须实现Instantiable
- 这允许您使用无参数构造函数创建实例。
最后,使用如下:
private var _fat : FatThing? // having this extra and exposed var kills my inner child
var fat: FatThing? {
get { return lazyInitializer(&self._fat) }
set { _fat = newValue }
}
请注意,在您的代码中,您不必将fat
计算机属性声明为可选 - 您在get
实现中确保它始终不是nil,因此更好的实现是:
var fat: FatThing {
get{
if _fat == nil {
_fat = FatThing()
}
return _fat!
}
set{
_fat = newValue
}
}