How would you implement the following pattern in Swift?
The Container
class is initialized with a JSON array that contains dictionaries. These dictionaries are used to initialize Entry
classes. However, the initialization of the Entry
objects happens lazily, when either the entries
or the searchEntries
property is accessed.
@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
What about this:
class Container {
lazy var entries: [String] = self.newEntries()
func newEntries() -> [String] {
// calculate and return entries
}
}
It seems that this question has largely been answered, but to circle back to the original post, here is (IMHO) a relatively succinct translation in Swift. The key is that you can chain lazy properties. Note that I used both a class function and a closure - either is fine.
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")
You could use an optional as the instance variable. Then create a function that returns the optional if it exists, and a new object if it does not to simulate lazy loading.
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!
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With