2016-07-03 2 views
7

この問題を示すために、私はバニラのCocoaプロジェクトを作成しました。ここでAppDelegate.swiftです:Xcodeのは、この与え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 
    } 
} 

:私の実際のプロジェクトで

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??'

を、それが(代わりのNSNumberの)MyCustomClassの別のオブジェクトです。エラーは、タイプがMyCustomClass以外は同じです。

宣言からweakまたはlazyを削除しても問題ありません。しかし、MyCustomClassは常にNSViewControllerであるため、参照カウントが+1にならないように保存したかったのです。

弱い怠惰な変数をどのように使用するか考えてみましょうか? Dが初期化されなければならない場合

答えて

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

素晴らしい!これはまさに私が探していたものです。しかし、もし私が過剰工学であると思ったのです。 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) 

...代わりに弱い計算されたプロパティを使用してみてください1回だけ、

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のソリューションを好む。私が探しているものに近い2番目のアプローチでは、 'd0'はまだ"長期的な "参照を保持しています。実際には、それが正しく理解されていれば、 '弱い'なしで '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 
} 

}

関連する問題