在Swift中实现一个惰性属性并将其设置为nil

时间:2015-01-02 21:42:57

标签: ios swift lazy-initialization

我想实现一个惰性属性,以便在第一次访问它之前它不会有值。但后来我想将其设置为nil以释放内存资源。然后,当应用程序再次尝试访问它时,它将被重新创建,因此当它即将被访问时,它不应该是nil

我查看了Swift Programming书并阅读了懒惰属性,但是信息很少,没有这个用例的例子。

我看到this answer by Rudolf Adamkovic并实现了该格式,但该项目无法在Xcode 6.2 beta 3中编译:{{1​​}}

Use of undeclared type 'String'

我也尝试过这种格式,但它也无法使用相同的编译时错误进行编译。

let model = MyModelClass()
lazy var recentlyAdded: [​String] = self.recents() //error here

func recents() -> [String] {
    return self.model.recentlyAdded()
}

实现这种类型的惰性属性的正确方法是什么?

4 个答案:

答案 0 :(得分:2)

这样的东西?

struct S {
    var _actualVar: String? = nil
    var lazyVar: String? {
        mutating get {
            if _actualVar == nil {
                _actualVar = someCalc()
            }
            return _actualVar
        }
        set(newVar) {
            _actualVar = newVar
        }
    }
}
var s = S()
s.lazyVar  // someCalc will be called
s.lazyVar  // but not here
s.lazyVar = nil
s.lazyVar  // but it'll be called again here

请注意,与惰性属性一样,这需要使用get lazyVars,您的var变量仍然需要使用{{1}}声明可能有点令人惊讶。

答案 1 :(得分:2)

我找到了解决方案。您不能像在Objective-C中那样使用Swift中的lazy属性来执行延迟实例化,至少不能使用Swift 1-3。如果您尝试,它将在第一次访问之前不会被实例化,但如果您稍后将其设置为nil,当您再次访问它时,它仍将是nil。它只会被懒惰地实例化一次,这不是我想要的。

要实现'true'延迟实例化,您需要一个计算属性以及一个常规属性,var。我将常规属性称为“支持”属性。基本上,如果支持属性为nil,则检入computed属性,如果是,则创建它,然后返回该支持属性。这是一个计算属性,因此它不会在内存中存储值,而后备属性则会。当您希望获取其值时,请访问计算属性。如果要将其值设置为nil,请设置后备属性。

Apple在其核心数据模板中使用此技术。它们对两者使用相同的属性名称,但在backing属性之前放置一个下划线,后者属性模仿来自Objective-C的iVar。

这样的事情可以解决问题:

var fetchedResultsController: NSFetchedResultsController {
    get {
        if _fetchedResultsController != nil {
            return _fetchedResultsController!
        }
        _fetchedResultsController = NSFetchedResultsController(fetchRequest: ...)
        return _fetchedResultsController!
    }
    set {
        _fetchedResultsController = newValue
    }
}
var _fetchedResultsController: NSFetchedResultsController? = nil

使用它:

_fetchResultsController = nil
self.fetchResultsController.performFetch()

答案 2 :(得分:1)

我无法弄清楚这个问题。但我解决了。

当我复制你的代码并粘贴时,我得到了同样的错误:

Use of undeclared type 'String'

我删除了它并重新输入(没有自动完成),它对我有用。

看起来像是XCode中的一个错误。

答案 3 :(得分:0)

我只是使用可选符号 - 即一个问号表示它可以是零。例如

var myVar:String?