Ios 断层或;“惰性初始化”;雨燕图案

Ios 断层或;“惰性初始化”;雨燕图案,ios,swift,instance-variables,lazy-initialization,Ios,Swift,Instance Variables,Lazy Initialization,在处理大型对象时,我通常在iOS中使用“faulting”或惰性初始化模式 每当一个类有一个指向“fat”对象的属性时,我都会创建一个自定义getter来检查iVar是否为nil。如果是,它将创建fat对象并返回它。如果不是,它只返回“fat”对象 此属性的容器还订阅内存警告,当收到警告时,它会将iVar设置为nil,从而减少内存占用。正如您所看到的,这与核心数据中的错误非常相似 我试图在Swift中重现这一点,但到目前为止还没有找到一个像样而优雅的解决方案 a)第一次尝试:延迟存储属性 这不起

在处理大型对象时,我通常在iOS中使用
“faulting”
惰性初始化
模式

每当一个类有一个指向“fat”对象的属性时,我都会创建一个自定义getter来检查
iVar
是否为
nil
。如果是,它将创建fat对象并返回它。如果不是,它只返回“fat”对象

此属性的容器还订阅内存警告,当收到警告时,它会将
iVar
设置为
nil
,从而减少内存占用。正如您所看到的,这与核心数据中的错误非常相似

我试图在Swift中重现这一点,但到目前为止还没有找到一个像样而优雅的解决方案

a)第一次尝试:延迟存储属性

这不起作用,因为如果我将属性设置为nil,它将永远保持为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)第二次尝试:具有观察者的存储属性

这也失败了,因为缺少get观察员。我需要一个
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这样的内存不足的环境中,这并不是什么异国情调

单独重写getter或setter的能力是objective C的一个特性,在swift中没有对应项

您可以选择的正确选项是3,使用backing属性存储fat数据,使用computed属性使其可访问。我同意有一些样板代码,但这是获得您需要的东西的权衡

但是,如果您经常使用该模式,则可以创建协议:

protocol Instantiable {
    init()
}
并在
FatThing
struct/class中实现它。接下来,创建一个包含样板代码的通用函数:

func lazyInitializer<T: Instantiable>(inout property: T?) -> T {
    if property == nil {
        property = T()
    }

    return property!
}

请注意,在您的代码中,您不必将
fat
计算机属性声明为可选-您可以在
get
实现中确保它始终不是零,因此更好的实现是:

var fat: FatThing {
    get{
        if _fat == nil {
            _fat = FatThing()
        }
        return _fat!
    }
    set{
        _fat = newValue
    }
}
var fat: FatThing {
    get{
        if _fat == nil {
            _fat = FatThing()
        }
        return _fat!
    }
    set{
        _fat = newValue
    }
}