简体   繁体   中英

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
    }()

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!
    }
}

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM