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?
- Yep, that is correct.
- Yep, that is also correct.
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
Swift 4.2 Imagepickercontroller Issue
Viewcontroller Slide Animation
How to Reference Swift Playground Itself
When and How to Use @Noreturn Attribute in Swift
Swift 2 Protocol Extension Not Calling Overridden Method Correctly
Draw a Hole in a Rectangle with Spritekit
"Unrecognized Selector Sent to Instance" in Swift
How to Write Inline Assembly in Swift
How to Print a String from Plist Without "Optional"
Only First Track Playing of Avmutablecomposition()
Swift Map(_:) Extension for Set()
Make Property of Type and Also Conform to Protocol in Swift
Best Practice for Swift Methods That Can Return or Error
Curl Through Nstask Not Terminating If a Pipe Is Present
How to Convert PDF to Png Efficiently
In Swift, Can You Split a String by Another String, Not Just a Character