2016-07-03 43 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 
} 

}