Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Lazy Variables that Load more than Once (Computed Properties?)

I'm trying to translate some Objective-C code that was essentially lazy loading a variable multiple times. The code was similar to the following:

-(NSFetchedResultsController *)fetchedResultsController {
    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    //...code to build the fetchedResultsController with a new predicate

Whenever they wanted to rebuild the fetchedResultsController to use a new predicate, they would just set it to "nil" and call it, and it would rebuild it with a new predicate.

I'm struggling to do this same task in Swift. As far as I can tell, Swift lazy variables become normal variables after they are called for the first time. This is causing issues for me because if I try to set my swift variable back to nil, and recall it, it doesn't rebuild but remains nil.

The working code to load my fetchedResultsController as a lazy varaible is below. I've tried changing it to a computed property by adding a check if its nil and have it within a get block, but that hasn't worked. Any ideas?

    lazy var taskController : NSFetchedResultsController? = {
        var subtaskRequest = NSFetchRequest(entityName: "Subtasks")
        var segIndex = self.segmentedControl.selectedSegmentIndex
        subtaskRequest.predicate = NSPredicate(format: "task.category.name == %@", self.segmentedControl.titleForSegmentAtIndex(segIndex)!)
        subtaskRequest.sortDescriptors = [NSSortDescriptor(key: "task.englishTitle", ascending: true), NSSortDescriptor(key: "sortOrder", ascending: true)]


        let controller = NSFetchedResultsController(fetchRequest: subtaskRequest, managedObjectContext:
            self.managedObjectContext!, sectionNameKeyPath: "task.englishTitle", cacheName: nil)
        controller.delegate = self
        return controller
    }()
like image 959
Unome Avatar asked Nov 20 '14 23:11

Unome


People also ask

Are computed properties lazy in Swift?

Swift's lazy properties let us delay the creation of a property until it's actually used, which makes them like a computed property. However, unlike a computed property they store the result that gets calculated, so that subsequent accesses to the property don't redo the work.

What is the difference between computed property and lazy property?

But what is the difference between a lazy variable and a computed property? A lazy variable is a stored property whose initialization is delayed. The initial value is computed only one time. A computed property is a value that is not stored anywhere.

What are lazy variables in Swift?

A lazy var is a property whose initial value is not calculated until the first time it's called. It's part of a family of properties in which we have constant properties, computed properties, and mutable properties.

What is lazy initialization in Swift?

lazy initialisation is a delegation of object creation when the first time that object will be called. The reference will be created but the object will not be created. The object will only be created when the first time that object will be accessed and every next time the same reference will be used.


2 Answers

You can create something similar to the Objective-C method using a computed property backed by an optional variable.

var _fetchedResultsController: NSFetchedResultsController?

var fetchedResultsController: NSFetchedResultsController {
    get {
        if _fetchedResultsController != nil {
            return _fetchedResultsController!
        }
        //create the fetched results controller...
        return _fetchedResultsController!
    }
}
like image 178
Connor Avatar answered Oct 26 '22 22:10

Connor


lazy just implements a very specific memoization pattern. It's not as magical as you'd sometimes like it to be. You can implement your own pattern to match your ObjC code pretty easily.

Just make a second private optional property that holds the real value. Make a standard (non-lazy) computed property that checks the private property for nil and updates it if it's nil.

This is pretty much identical to the ObjC system. In ObjC you had two "things," one called _fetchedResultsController and the other called self.fetchedResultsController. In Swift you'll have two things, one called self.fetchedResultsController and the other called self._cachedFetchedResultsController (or whatever).

like image 21
Rob Napier Avatar answered Oct 26 '22 22:10

Rob Napier