Lazy Loading Properties in Swift

Lazy loading Properties in swift

I think a lazy property initialized with a closure would work:

lazy var myLabel: UILabel = {
var temporaryLabel: UILabel = UILabel()
...
return temporaryLabel
}()

As I read “The Swift Programming Language.” (Checkerboard example) the closure is only evaluated once).

What is lazy meaning in Swift?

The word is used in two contexts.

  • a lazy variable is a stored property that is calculated once but not until it is referenced for the first time. If I have this:

    var x: Int = someExpensiveFunction()

    it is calculated when its owning object is instantiated. If I do this

    lazy var x: Int = someExpensiveFunction()

    It is not calculated until the first time I want to use x.

  • Lazy sequences are sequences in which some operations are calculated as they are needed. For example in this code

    [1, 2, 3].map { someExpensiveFunction($0) }

    The mapped sequence is fully calculated straight away. However in the following

     [1, 2, 3].lazy.map { someExpensiveFunction($0) }

    Each successive element of the final sequence is only calculated at the moment it is asked for e.g. by an iterator.

I suppose, technically, in the second case lazy is not being used as a keyword, but I include it for completeness.

How to override the lazy load dataArr by swift in the new swift file?

As far as I know you can override a lazy Objective-C property like

@property (readonly, nonnull) NSArray<NSDictionary<NSString*,NSString*> *> *dataArr;

only with a computed property in Swift

class TestSwift: theOCFatherClass { 

lazy var swiftDataArray = [["title":"cat1", "message":"the cat1"], ["title":"cat2", "message":"the cat2"], ["title":"cat3", "message":"the cat3"]]

override var dataArr : [[String:String]] {
return swiftDataArray
}

override func viewDidLoad() { ... }

}

Lazy loading property in Extension (Swift)

you can use computed property, combined with associatedObject. in this way, you can mimic a stored property. so the lazy var simulation will be:

// global var's address used as key
var #PropertyKey# : UInt8 = 0
var #varName# : #type# {
get {
if let v = objc_getAssociatedObject(self, & #PropertyKey#) as #type# {
return v
}else {
// the val not exist, init it and set it. then return it

// this way doesn't support nil option value.
// if you need nil option value, you need another associatedObject to indicate this situation.
}
}
set {
objc_setAssociatedObject(self, & #PropertyKey#, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
}
}

How to re-initialize a lazy property from another view?

I would suggest creating a function that loads the data into data and then whenever you need to reload data, simply reassign it.

class DataStore {
lazy var data: [String: String] = loadData()

func readFromDisk() -> Data? {...}

func processData(data: Data) -> [String:String] { ... }

func loadData() -> [String:String] {
guard let data = readFromDisk() else { return [:] }
return processData(data: data)
}
}

let store = DataStore()
let data = store.data // only loaded here
store.data = store.loadData() // reloads the data

If you don't want the loadData function to be exposed, you can also create a separate reloadData function.

class DataStore {
...
func reloadData() {
data = loadData()
}
}

and then instead of doing store.data = store.loadData(), simply call store.reloadData()

Swift - Lazy loading a property that can be made nil later

The piece that you're missing is that, in Objective-C, it's creating the _navController ivar and setter for you; in Swfit you need to create those yourself.

Once you have those in place, your navController property in Swift can look pretty similar to the Objective-C one:

private var _navController: UINavigationController? = nil

var navController: UINavigationController! {
get {
if _navController == nil {
let tempStoryboard = UIStoryboard(name: "Image", bundle: nil);
_navController = tempStoryboard.instantiateInitialViewController() as? UINavigationController
}

return _navController
}
set {
_navController = newValue
}
}

Note: I delcared navController as an implicitly unwrapped UINavigationController so that it can be set to nil while still making it accessible without unwrapping the value every time. While using an implicitly unwrapped type can be dangerous, it's ok (and appropriate) to use in this case. Since we check for nil in the getter itself, we can guarantee that it will always return a non-nil value. Additionally, even though we're using a conditional downcast on the value returned from instantiateInitialViewController, we can say that any value returned from that function that is not a UINavigationController would be a programmer error and the resulting crash would be appropriate.

Initialization of properties in a class, lazy properties in specific?

  1. Yep, that is correct.
  2. Yep, that is also correct.
  3. What is being initialized is the constant someClass. Declaration is the introduction of a new named value into your program. You declare the name of the constant (or variable) and identify its type like this:

    let someClass: SomeClassWithLazyVar

But at that point it still hasn't been initialized. You initialize the constant by assigning it a value:

someClass = SomeClassWithLazyVar()

The vast majority of the time (especially with constants) you declare the constant and initialize it at the same time:

let someClass = SomeClassWithLazyVar()

Whether or not you need to pass arguments inside the parentheses depends on the initializer for the object that you are creating. I'm assuming that SomeClassWithLazyVar has an initializer that takes no arguments, like this:

init() { }

Lazy load MirrorType

The MirorType is very limited in it's functionality. Besides that it's replaced by other functionality in Xcode 7 beta 4.

The point in your case is that the property has not been used yet. So it's actually still nil. The only way to make it not nil is by accessing the property by getting it's value. Unfortunately in Swift you can not do that by executing .valueForKey("propertyName")

If you are looking for a reflection library that is trying to get as much as possible out of Swift, then have a look at EVReflection

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

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


Related Topics



Leave a reply



Submit