2014-06-08 17 views
5

Come implementeresti il ​​seguente schema in Swift?Inizializzazione di proprietà Lazy in Swift

La classe Container è inizializzata con un array JSON che contiene dizionari. Questi dizionari vengono utilizzati per inizializzare le classi Entry. Tuttavia, l'inizializzazione degli oggetti Entry si verifica pigramente quando si accede alla proprietà entries o searchEntries.

@interface Container 

@property (readonly, nonatomic) NSArray *entryDicts; 

@property (readonly, nonatomic) NSArray* entries; 
@property (readonly, nonatomic) NSDictionary *searchEntries; 

@end 



@implementation Container 

- (instancetype)initWithArray:(NSArray *)array 
{ 
    self = [super init]; 
    if (self) { 
     _entryDicts = array; 
    } 
    return self; 
} 

@synthesize entries = _entries; 
- (NSArray *)entries 
{ 
    [self loadEntriesIfNeeded]; 
    return _entries; 
} 

@synthesize entriesByNumber = _entriesByNumber; 
- (NSDictionary *)entriesByNumber 
{ 
    [self loadEntriesIfNeeded]; 
    return _entriesByNumber; 
} 

- (void)loadEntriesIfNeeded 
{ 
    if (_entries == nil) { 
     // Load entries 
     NSMutableArray *entries = [NSMutableArray arrayWithCapacity:[self.entriesDict count]]; 
     NSMutableDictionary *entriesByNumber = [NSMutableDictionary dictionaryWithCapacity:[self.entriesDict count]]; 

     [self.entriesDict enumerateKeysAndObjectsUsingBlock:^(NSString *number, NSDictionary *entryDict, BOOL *stop) { 
      Entry *entry = [[Entry alloc] initWithDictionary:entryDict container:self]; 
      [entries addObject:entry]; 
      entriesByNumber[number] = entry; 
     }]; 

     _entries = [entries copy]; 
     _entriesByNumber = [entriesByNumber copy]; 

     // Delete dictionaries 
     _entriesDict = nil; 
    } 
} 

@end 

risposta

6

sembra che questa questione è stata in gran parte risposto, ma a cerchio di nuovo al post originale, qui è (IMHO) traduzione relativamente succinta a Swift. La chiave è che puoi concatenare le proprietà pigri. Nota che ho usato sia una funzione di classe che una chiusura: o va bene.

import Swift 

println("begin") 

class ClassWithLazyProperties { 

    lazy var entries:[String] = ClassWithLazyProperties.loadStuff() 
    lazy var entriesByNumber:Dictionary<Int, String> = { 

     var d = Dictionary<Int, String>() 
     for i in 0..<self.entries.count { 
      d[i] = self.entries[i] 
     } 
     return d 
    }() 

    private class func loadStuff() -> [String] { 
     return ["Acai", "Apples", "Apricots", "Avocado", "Ackee", "Bananas", "Bilberries"] 
    } 

} 

let c = ClassWithLazyProperties() 
c.entriesByNumber 
    // 0: "Acai", 1: "Apples", 2: "Apricots", 3: "Avocado", 4: "Ackee", 5: "Bananas", 6: "Bilberries"] 


println("end") 
5

È possibile utilizzare un opzionale come variabile di istanza. Quindi crea una funzione che restituisce l'opzionale se esiste e un nuovo oggetto se non simula il caricamento pigro.

class Lazy { 
    var lazyVariable:String? 

    func lazilyGetEntries() -> String { 
     if let possibleVariable = self.lazyVariable { // optional already exists 
      return possibleVariable 
     } 
     else {          // optional does not exist, create it 
      self.lazyVariable = String() 
      return self.lazyVariable! 
     } 
    } 
} 
0

si indica una proprietà pigro memorizzato scrivendo l'attributo @lazy prima della sua dichiarazione.”

@lazy var lazyVariable:String? = "" 

Si prega di tenere a mente, proprietà pigri deve avere un initialiser.

+1

Purtroppo, @lazy non funziona Qui. Controlla il mio codice. – Florian

0

C'è un attributo @lazy in Swift. Ho trovato un piccolo post here e consiglio di guardare i tre video Swift di Apple here (Introduzione a Swift, Intermediate Swift, Advanced Swift). Questi video mostrano molte cose e quello avanzato è davvero avanzato ...

+0

Ho già guardato tutti i video. Sfortunatamente, @lazy non funziona qui. Controlla il mio codice. – Florian

+0

@Florian Sfortunatamente il mio programma di sviluppo non è ancora attivo, quindi non posso eseguire il codice :( – Kametrixom

1

È possibile utilizzare Proprietà memorizzate pigro in Swift per implementare il modello Lazy Instantiation. Questo viene fatto aggiungendo l'attributo @lazy prima della dichiarazione della proprietà memorizzata.

Ci sono due cose da tenere a mente:

  • proprietà pigri devono essere inizializzati quando dichiarate
  • proprietà pigri possono essere utilizzati solo su membri di una struttura o di una classe (da qui il motivo per cui abbiamo bisogno di usare un DataManager)

Ecco un po 'di codice si può buttare in un parco giochi per vedere come funziona l'attributo @lazy

// initialize your lazily instantiated data 
func initLazyData() -> String[] { 
    return ["lazy data"] 
} 

// a class to manage the lazy data (along with any other data you want) 
class DataManager { 
    @lazy var lazyData = initLazyData() 

    var otherData = "Other data" 
} 

// when we create this object, the "lazy data" array is not initialized 
let manager = DataManager() 

// even if we access another property, the "lazy data" array stays nil 
manager.otherData += ", more data" 
manager 

// as soon as we access the "lazy data" array, it gets created 
manager.lazyData 
manager 

Per ulteriori informazioni, è possibile controllare la sezione Lazy Stored Properties nella pagina Proprietà della Swift istruzioni di programmazione della lingua. Si noti che quel collegamento è per la documentazione pre-rilascio.

0

ho trovato questo in PageBaseApplication

var modelController: ModelController { 
    // Return the model controller object, creating it if necessary. 
    // In more complex implementations, the model controller may be passed to the view controller. 
    if !_modelController { 
     _modelController = ModelController() 
    } 
    return _modelController! 
} 

var _modelController: ModelController? = nil 

simile a quello che @ Brian Tracy menzionato ma ussing variabili al posto di un func

3

Il modo in cui funziona pigri è che l'inizializzatore (o il metodo init) viene eseguito solo quando prima si accede alla variabile o alla proprietà. Vedo un motivo principale per cui non funzionerà (almeno immediatamente) nel tuo codice, ed è perché hai inserito due codici di istanza pigri in un unico metodo (loadEntriesIfNeeded).

Per utilizzare l'istanza lazy, potrebbe essere necessario estendere NSMutableArray e NSDictionary e sovrascrivere o creare un inizializzatore personalizzato per l'istanziazione lazy. Quindi, distribuire il codice all'interno di loadEntriesIfNeeded nei rispettivi inizializzatori.

In voci initializer:

NSMutableArray *entries = [NSMutableArray arrayWithCapacity:[self.entriesDict count]]; 
[self.entriesDict enumerateKeysAndObjectsUsingBlock:^(NSString *number, NSDictionary *entryDict, BOOL *stop) { 
      Entry *entry = [[Entry alloc] initWithDictionary:entryDict container:self]; 
      [entries addObject:entry];}]; 
_entries = [entries copy]; 

Poi nel entriesByNumber initializer:

NSMutableDictionary *entriesByNumber = [NSMutableDictionary dictionaryWithCapacity:[self.entriesDict count]]; 
// Then do fast enumeration accessing self.entries to assign values to entriesByNumber. 
// If self.entries is null, the lazy instantiation should kick in, calling the above code 
// and populating the entries variable. 
_entriesByNumber = [entriesByNumber copy]; 

Quindi, è possibile creare le variabili pigri invitando gli inizializzatori personalizzati.

@lazy var entries: CustomArray = custominitforarray() 
@lazy var entriesByNumber: CustomDictionary = custominitfordictionary() 

PS: come mai non si dispone di una proprietà per le vociByNumber? Immagino sia privato? Per favore prova questo e rispondi al risultato perché sono troppo pigro per farlo da solo.

+0

è diventato semplicemente pigro, senza "@" in beta4 –

9

Che dire di questo:

class Container { 

    lazy var entries: [String] = self.newEntries() 

    func newEntries() -> [String] { 

     // calculate and return entries 

    } 

} 
+0

Grazie. L'apertura {manca dopo il nome della classe e il valore restituito nella funzione – Evgenii

+0

@Evgeny Risolto il problema "{". Grazie! –

0

Poiché la proprietà entries è solo una matrice dei valori in entriesByNumber si può fare tutto il carico giusto in entriesByNumber e solo entries dipendono entriesByNumber

lazy var entriesByNumber: [String : Entry] = { 
     var ret: [String : Entry] = [:] 
     for (number, entryDict) in entriesDict 
     { 
      ret[number] = Entry(dictionary: entryDict, container: self) 
     } 
     return ret 
    } 

var entries: [Entry] 
{ 
    get { return self.entriesByNumber.values } 
} 
Problemi correlati