Swift 弱惰性变量无法编译
Swift weak lazy variable won't compile
为了演示这个问题,我做了一个普通的 Cocoa 项目。这是 AppDelegate.swift
:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
weak lazy var isGood : NSNumber? = {
return true
}()
func doSomething() {
let result = isGood!
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
Xcode 给出这个:
unkown :0: error: cannot convert return expression of type 'NSNumber?' (aka 'Optional') to return type 'NSNumber?'
unkown :0: cannot assign value of type 'NSNumber?' to type 'NSNumber??'
unkown :0: cannot assign value of type 'NSNumber?' to type 'NSNumber??'
在我的实际项目中,它是MyCustomClass
的另一个对象(而不是NSNumber)。除了类型是 MyCustomClass
.
之外,错误是相同的
如果我从声明中删除 weak
或 lazy
,就没问题了。但是我想避免引用计数为 +1,因为 MyCustomClass
是一个 NSViewController
,它肯定会一直存在。
知道如何使用弱惰性变量吗?
尝试使用弱计算属性代替...
import Foundation
class C {
weak var d : NSDate? {
return NSDate()
}
}
let c = C()
print(NSDate())
sleep(1)
print(c.d)
这会给你想要的行为(如果我理解你的问题:-))
2016-07-03 16:49:04 +0000
Optional(2016-07-03 16:49:05 +0000)
如果 d 必须只初始化一次,那么
import Foundation
class C {
weak var d : NSDate? {
return d0
}
lazy var d0: NSDate? = {
return NSDate()
}()
}
let c = C()
print(NSDate())
sleep(1)
print(c.d)
sleep(1)
print(c.d)
这正是您所需要的
2016-07-03 16:57:24 +0000
Optional(2016-07-03 16:57:25 +0000)
Optional(2016-07-03 16:57:25 +0000)
软弱和懒惰混在一起不好。错误消息在解释发生了什么方面完全没有用,但本质上 lazy
和 weak
彼此不一致:
lazy
告诉 Swift 您不想在第一次访问变量之前创建它,但是一旦创建,您希望无限期地保留它以供将来参考,而
weak
告诉 Swift 你不希望你的变量成为最后一个 link 来阻止你的变量被释放,这对 "keep indefinitely" lazy
个变量的目标。
你可以通过模拟 lazy
来解决这个问题,像这样:
class Foo {
weak var isGoodCache : NSNumber?
private var makeIsGood : NSNumber {
isGoodCache = true
return isGoodCache!
}
var isGood:NSNumber? {
return isGoodCache ?? makeIsGood
}
}
lazy 和 weak 不兼容的原因是每次使用都会创建一个新实例,除非你有另一个地方持有强引用。如果您有另一个地方可以保存强引用,那么您不需要 class 成员成为创建实例的成员。
假设我们有:
weak lazy var myVariable: MyClass? = createMyClassInstance()
当您第一次使用它时,假设您只是在某处的函数调用中引用它...
myFunction(myVariable)
在下一行,myVariable 再次为空。
这是为什么?因为,一旦 myFunction 完成,就不再有对 myVariable 的引用,并且由于它很弱,相应的对象超出范围并消失。
惰性弱变量和任何函数调用结果之间没有区别。因此,您的变量也可能是一个函数或一个计算变量(这会使查看您的代码的任何人都更清楚)。
引用的创建者不必是负责保留它的人。我有一些 classes 有意保留自己,并自己决定何时应该通过释放对自己的强烈引用来回收它们。
我用另一个class作为这样的工厂。有时我必须调整构造函数的参数,使这个泛型 class 更像是一个模板,而不是实际的实现。但是,虽然它们存在,但工厂被设计为 return 已经存在的实例。
class Factory<T> {
private weak var refI: T?
var ref: T {
if refI != nil {
return refI
}
let r = T()
refI = r
return r
}
}
为了演示这个问题,我做了一个普通的 Cocoa 项目。这是 AppDelegate.swift
:
import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
weak lazy var isGood : NSNumber? = {
return true
}()
func doSomething() {
let result = isGood!
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
Xcode 给出这个:
unkown :0: error: cannot convert return expression of type 'NSNumber?' (aka 'Optional') to return type 'NSNumber?'
unkown :0: cannot assign value of type 'NSNumber?' to type 'NSNumber??'
unkown :0: cannot assign value of type 'NSNumber?' to type 'NSNumber??'
在我的实际项目中,它是MyCustomClass
的另一个对象(而不是NSNumber)。除了类型是 MyCustomClass
.
如果我从声明中删除 weak
或 lazy
,就没问题了。但是我想避免引用计数为 +1,因为 MyCustomClass
是一个 NSViewController
,它肯定会一直存在。
知道如何使用弱惰性变量吗?
尝试使用弱计算属性代替...
import Foundation
class C {
weak var d : NSDate? {
return NSDate()
}
}
let c = C()
print(NSDate())
sleep(1)
print(c.d)
这会给你想要的行为(如果我理解你的问题:-))
2016-07-03 16:49:04 +0000
Optional(2016-07-03 16:49:05 +0000)
如果 d 必须只初始化一次,那么
import Foundation
class C {
weak var d : NSDate? {
return d0
}
lazy var d0: NSDate? = {
return NSDate()
}()
}
let c = C()
print(NSDate())
sleep(1)
print(c.d)
sleep(1)
print(c.d)
这正是您所需要的
2016-07-03 16:57:24 +0000
Optional(2016-07-03 16:57:25 +0000)
Optional(2016-07-03 16:57:25 +0000)
软弱和懒惰混在一起不好。错误消息在解释发生了什么方面完全没有用,但本质上 lazy
和 weak
彼此不一致:
lazy
告诉 Swift 您不想在第一次访问变量之前创建它,但是一旦创建,您希望无限期地保留它以供将来参考,而weak
告诉 Swift 你不希望你的变量成为最后一个 link 来阻止你的变量被释放,这对 "keep indefinitely"lazy
个变量的目标。
你可以通过模拟 lazy
来解决这个问题,像这样:
class Foo {
weak var isGoodCache : NSNumber?
private var makeIsGood : NSNumber {
isGoodCache = true
return isGoodCache!
}
var isGood:NSNumber? {
return isGoodCache ?? makeIsGood
}
}
lazy 和 weak 不兼容的原因是每次使用都会创建一个新实例,除非你有另一个地方持有强引用。如果您有另一个地方可以保存强引用,那么您不需要 class 成员成为创建实例的成员。
假设我们有:
weak lazy var myVariable: MyClass? = createMyClassInstance()
当您第一次使用它时,假设您只是在某处的函数调用中引用它...
myFunction(myVariable)
在下一行,myVariable 再次为空。
这是为什么?因为,一旦 myFunction 完成,就不再有对 myVariable 的引用,并且由于它很弱,相应的对象超出范围并消失。
惰性弱变量和任何函数调用结果之间没有区别。因此,您的变量也可能是一个函数或一个计算变量(这会使查看您的代码的任何人都更清楚)。
引用的创建者不必是负责保留它的人。我有一些 classes 有意保留自己,并自己决定何时应该通过释放对自己的强烈引用来回收它们。
我用另一个class作为这样的工厂。有时我必须调整构造函数的参数,使这个泛型 class 更像是一个模板,而不是实际的实现。但是,虽然它们存在,但工厂被设计为 return 已经存在的实例。
class Factory<T> {
private weak var refI: T?
var ref: T {
if refI != nil {
return refI
}
let r = T()
refI = r
return r
}
}