2016-07-03 44 views
7

为了演示这个问题,我做了一个香草Cocoa项目。这里是AppDelegate.swiftSwift弱懒惰变量不会编译

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

如果我从声明中删除weaklazy,那没关系。但我想将参考计数保存为+1,因为MyCustomClass是一个NSViewController,它肯定会始终存在。

任何想法如何使用弱懒惰变量?

回答

17

弱和懒惰混合不好。该错误信息是完全无用的解释是怎么回事,但实质上lazyweak是有分歧与对方:

  • lazy告诉你不希望你的变量创建的第一次访问,直到斯威夫特,但是一旦创建了它,你就想保留它以便将来参考,而
  • weak告诉Swift你不希望你的变量成为最终的链接,让你的变量不被释放,这对于“无限期保留“目标lazy变量。

您可以通过模拟lazy,这样解决这个问题:

class Foo { 

    weak var isGoodCache : NSNumber? 

    private var makeIsGood : NSNumber { 
     isGoodCache = true 
     return isGoodCache! 
    } 

    var isGood:NSNumber? { 
     return isGoodCache ?? makeIsGood 
    } 
} 
+1

太棒了!这正是我所期待的。但我开始考虑如果我是过度工程。一个保留不会伤害,对吧?这里唯一的好处是可以防止未来可能的参考周期。 – LShi

0

尽量使用弱计算的属性,而不是...

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) 
+0

感谢。我更喜欢@ dasblinkenlight的解决方案。在第二种方法中,这与我所寻找的接近,“d0”仍然是“长期”参考。实际上,如果我理解正确的话,它类似于使用没有'weak'的'lazy'。 – LShi

3

之所以懒惰和软弱是不兼容的,除非你有拥有很强的另一个地方,每次使用将创造一个新的实例参考。如果你有另一个地方来保存强大的引用,那么你不需要你的类成员是创建实例的人。

让我们假设我们有:

weak lazy var myVariable: MyClass? 

当你使用它的第一次,可以说你只是引用它在函数调用的地方......

myFunction(myVariable) 
就非常下一行

,myVariable又是空的。

这是为什么?因为一旦myFunction完成后,就不再有对myVariable的引用,并且由于它很弱,相应的对象将超出范围并消失。

这个惰性弱变量和任何函数调用结果之间没有区别。所以,你的变量也可能是一个函数或一个计算变量(它会让任何人看你的代码更清晰)。

+0

您如何看待@dasblinkenlight的方法?优点是计算结果被缓存。我确实认为使用简单的计算变量是清楚的。性能也不会成为问题。 – LShi

+0

据我所知,除非返回的值保留在其他地方,否则该变量将被重新分配并重新分配给isGood。对于一个简单的NSNumber来说,这可能不是一个问题,但是如果你使用一个更复杂的内部状态的类,那么你将不会在每个引用上获得相同的实例,并且内部状态将会丢失。 –

0

引用的创建者不必是负责保留引用的人。我有一些课堂保留自己的意图,并决定自己何时应该通过释放他们强烈的自我意识来回收。

我使用另一个类作为这样的工厂。有时我必须调整构造函数的参数,所以这个泛型类更多的是模板而不是实际的实现。但是,当它们存在时,工厂被设计为返回已经存在的实例。

class Factory<T> { 
private weak var refI: T? 
var ref: T { 
    if refI != nil { 
     return refI 
    } 
    let r = T() 
    refI = r 
    return r 
} 

}