2016-07-03 52 views
7

Per dimostrare questo problema, ho realizzato un progetto Cocoa alla vaniglia. Ecco l'AppDelegate.swift:La variabile debole debole di Swift non verrà compilata

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 dà questo:

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

Nel mio progetto attuale, è un altro oggetto di MyCustomClass (invece di NSNumber). L'errore è lo stesso eccetto il tipo è MyCustomClass.

Se rimuovo weak o lazy dalla dichiarazione, è tutto a posto. Ma volevo salvare il conteggio dei riferimenti da +1, dal momento che il MyCustomClass è un NSViewController che è sicuro di essere sempre lì.

Qualche idea su come utilizzare la variabile debole pigra?

risposta

17

Debole e pigro non mescolare bene. Il messaggio di errore è del tutto inutile a spiegare cosa sta succedendo, ma essenzialmente lazy e weak sono in contrasto tra loro:

  • lazy dice Swift che non si desidera la variabile creato fino a quando la prima volta che si accede , ma una volta creato, si desidera mantenerlo per un tempo indefinito per riferimento futuro, mentre
  • weak dice a Swift che non si desidera che la variabile sia l'ultimo collegamento che mantiene la variabile da essere deallocata, che funziona contro " mantenere indefinitamente "l'obiettivo delle variabili lazy.

È possibile risolvere questo emulando lazy, in questo modo:

class Foo { 

    weak var isGoodCache : NSNumber? 

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

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

Fantastico! Questo e 'esattamente quello che stavo cercando. Ma ho iniziato a pensare se sono troppo ingegnerizzato. Uno che conserva non farà male, giusto? L'unico vantaggio qui può essere che previene il possibile futuro ciclo di riferimento. – LShi

0

tenta di utilizzare una proprietà calcolata debole invece ...

import Foundation 

class C { 
    weak var d : NSDate? { 
     return NSDate() 
    } 
} 

let c = C() 
print(NSDate()) 
sleep(1) 
print(c.d) 

che vi danno il comportamento desiderato (se ho ben capito si domanda :-))

2016-07-03 16:49:04 +0000 
Optional(2016-07-03 16:49:05 +0000) 

se D deve essere inizializzato solo una volta, poi

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) 

che ti dà esattamente ciò che serve

012.351.
2016-07-03 16:57:24 +0000 
Optional(2016-07-03 16:57:25 +0000) 
Optional(2016-07-03 16:57:25 +0000) 
+0

Grazie. Preferisco la soluzione di @ dasblinkenlight. Nel tuo secondo approccio, che è vicino a quello che sto cercando, 'd0' detiene ancora un riferimento" a lungo termine ". In effetti è simile all'utilizzo di 'pigro' senza' debole', se ho capito bene. – LShi

3

Il motivo per cui pigri e deboli sono incompatibili è che ogni uso sarebbe creare una nuova istanza se non si ha un altro posto che detiene una forte riferimento. Se hai un altro posto in cui tenere un riferimento forte, non hai bisogno che il tuo membro di classe sia quello che crea l'istanza.

lascia supporre che abbiamo:

weak lazy var myVariable: MyClass? 

Quando si utilizza per la prima volta, permette di dire che solo riferimento in una chiamata di funzione da qualche parte ...

myFunction(myVariable) 

sulla riga successiva , myVariable è di nuovo vuoto.

Perché è quello? perché, una volta terminata myFunction, non ci sono più riferimenti a myVariable, e poiché è debole, l'oggetto corrispondente esce dall'ambito e scompare.

Non ci sarebbe differenza tra quella variabile debole e qualsiasi risultato di chiamata di funzione. Quindi, la tua variabile potrebbe essere una funzione o una variabile calcolata (renderebbe le cose più chiare per chiunque guardasse il tuo codice).

+0

Come pensi all'approccio di @dasblinkenlight? Il vantaggio è che il risultato calcolato è memorizzato nella cache. Penso che l'uso di una semplice variabile calcolata sia chiaro. Anche le prestazioni non saranno un problema. – LShi

+0

Per quanto posso dire, la variabile sarà deallocata e riallocata in ogni riferimento a isGood a meno che il valore restituito non venga mantenuto altrove. Per un NSNumber semplice che potrebbe non essere un problema ma, se si utilizza una classe più complessa con stati interni, non si otterrà la stessa istanza su ogni riferimento e gli stati interni andranno persi. –

0

Il creatore di un riferimento non deve essere il responsabile del suo mantenimento. Ho alcune lezioni che si mantengono intenzionalmente e decidono da sole quando dovrebbero essere reclamate rilasciando il loro forte riferimento al sé.

Io uso un'altra classe come una fabbrica come questa. A volte devo modificare gli argomenti per il costruttore, quindi questa classe generica è più di un modello che una vera e propria implementazione. Ma mentre esistono, la fabbrica è progettata per restituire l'istanza già esistente.

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

}