Can I set computed property in get block in Swift? - swift

var myProperty: PropertyType {
get {
if let alreadyComupted = savedValue {
return alreadyComputed
}
return computeAndSave(someParam: "Hello")
}
set {
// is it possible to move *computeAndSave* body here somehow so I can call *set* method in above get definition?
}
}
private var savedValue: PropertyType?
private func computeAndSave(someParam: SomeType) -> PropertyType {
// perform computations and assign value to *savedValue*
}
I am fairly new to swift language, not sure if this is even standard by coding practice or not.

Basically you are describing a lazy variable. It calculates its initializer once, when the value is first fetched, and from then on uses the stored value (unless it is replaced). You can combine this with a define-and-call initializer:
lazy var myProperty: PropertyType = {
let p = // perform some expensive one-time calculation here
return p
}()
The outcome is that the first time you ask for the value of myProperty, the initializer method runs; but after that the previous result is used, and the initializer method never runs again.

Related

Swift memoizing/caching lazy variable in a struct

I drank the struct/value koolaid in Swift. And now I have an interesting problem I don't know how to solve. I have a struct which is a container, e.g.
struct Foo {
var bars:[Bar]
}
As I make edits to this, I create copies so that I can keep an undo stack. So far so good. Just like the good tutorials showed. There are some derived attributes that I use with this guy though:
struct Foo {
var bars:[Bar]
var derivedValue:Int {
...
}
}
In recent profiling, I noticed a) that the computation to compute derivedValue is kind of expensive/redundant b) not always necessary to compute in a variety of use cases.
In my classic OOP way, I would make this a memoizing/lazy variable. Basically, have it be nil until called upon, compute it once and store it, and return said result on future calls. Since I'm following a "make copies to edit" pattern, the invariant wouldn't be broken.
But I can't figure out how to apply this pattern if it is struct. I can do this:
struct Foo {
var bars:[Bar]
lazy var derivedValue:Int = self.computeDerivation()
}
which works, until the struct references that value itself, e.g.
struct Foo {
var bars:[Bar]
lazy var derivedValue:Int = self.computeDerivation()
fun anotherDerivedComputation() {
return self.derivedValue / 2
}
}
At this point, the compiler complains because anotherDerivedComputation is causing a change to the receiver and therefore needs to be marked mutating. That just feels wrong to make an accessor be marked mutating. But for grins, I try it, but that creates a new raft of problems. Now anywhere where I have an expression like
XCTAssertEqaul(foo.anotherDerivedComputation(), 20)
the compiler complains because a parameter is implicitly a non mutating let value, not a var.
Is there a pattern I'm missing for having a struct with a deferred/lazy/cached member?
Memoization doesn't happen inside the struct. The way to memoize is to store a dictionary off in some separate space. The key is whatever goes into deriving the value and the value is the value, calculated once. You could make it a static of the struct type, just as a way of namespacing it.
struct S {
static var memo = [Int:Int]()
var i : Int
var square : Int {
if let result = S.memo[i] {return result}
print("calculating")
let newresult = i*i // pretend that's expensive
S.memo[i] = newresult
return newresult
}
}
var s = S(i:2)
s.square // calculating
s = S(i:2)
s.square // [nothing]
s = S(i:3)
s.square // calculating
The only way I know to make this work is to wrap the lazy member in a class. That way, the struct containing the reference to the object can remain immutable while the object itself can be mutated.
I wrote a blog post about this topic a few years ago: Lazy Properties in Structs. It goes into a lot more detail on the specifics and suggest two different approaches for the design of the wrapper class, depending on whether the lazy member needs instance information from the struct to compute the cached value or not.
I generalized the problem to a simpler one: An x,y Point struct, that wants to lazily compute/cache the value for r(adius). I went with the ref wrapper around a block closure and came up with the following. I call it a "Once" block.
import Foundation
class Once<Input,Output> {
let block:(Input)->Output
private var cache:Output? = nil
init(_ block:#escaping (Input)->Output) {
self.block = block
}
func once(_ input:Input) -> Output {
if self.cache == nil {
self.cache = self.block(input)
}
return self.cache!
}
}
struct Point {
let x:Float
let y:Float
private let rOnce:Once<Point,Float> = Once {myself in myself.computeRadius()}
init(x:Float, y:Float) {
self.x = x
self.y = y
}
var r:Float {
return self.rOnce.once(self)
}
func computeRadius() -> Float {
return sqrtf((self.x * self.x) + (self.y * self.y))
}
}
let p = Point(x: 30, y: 40)
print("p.r \(p.r)")
I made the choice to have the OnceBlock take an input, because otherwise initializing it as a function that has a reference to self is a pain because self doesn't exist yet at initialization, so it was easier to just defer that linkage to the cache/call site (the var r:Float)

How Can I Match Swift 4 KVO on Non-Objective-C Type?

I have a Result type that I use in asynchronous processes:
internal enum Result<T> {
case success(T)
case failure(Error)
}
I also have a APIDataResultContext that I use to pass data between Operation subclasses:
internal final class APIDataResultContext: NSObject {
// MARK: Properties
private let lock = NSLock()
private var _result: Result<Data>!
internal var result: Result<Data>! {
get {
lock.lock()
let temp = _result
lock.unlock()
return temp
}
set {
lock.lock()
_result = newValue
lock.unlock()
}
}
}
In my unit tests, I need to determine when result has been set in an APIDataResultContext instance. I can't use KVO because my Result<T> type cannot be marked as dynamic since it can't be represented in Objective-C.
I don't know of another way that will allow me to monitor when result is changed other than using a closure property or a Notification, which I would prefer not to do. I will resort to one of the two if necessary, though.
What other way(s) can I monitor for a change of result?
I ended up adding a closure property to APIDataResultContext:
internal final class APIDataResultContext {
// MARK: Properties
internal var resultChanged: (()->())?
private let lock = NSLock()
private var _result: Result<Data>!
internal var result: Result<Data>! {
get {
lock.lock()
let temp = _result
lock.unlock()
return temp
}
set {
lock.lock()
_result = newValue
lock.unlock()
resultChanged?()
}
}
}
I use the closure in my tests to determine when result has been changed:
internal func testNeoWsFeedOperationWithDatesPassesDataToResultContext() {
let operationExpectation = expectation(description: #function)
let testData = DataUtility().data(from: "Hello, world!")
let mockSession = MockURLSession()
let testContext = APIDataResultContext()
testContext.resultChanged = {
operationExpectation.fulfill()
guard let result = testContext.result else {
XCTFail("Expected result")
return
}
switch result {
case .failure(_):
XCTFail("Expected data")
case .success(let data):
XCTAssertEqual(data, testData, "Expected '\(testData)'")
}
}
NeoWsFeedOperation(context: testContext, sessionType: mockSession, apiKey: testAPIKey, startDate: testDate, endDate: testDate).start()
mockSession.completionHandler?(testData, nil, nil)
wait(for: [operationExpectation], timeout: 2)
}
You've already solved this issue (and what you did is probably what I'd do), but there's probably still value in providing a literal answer for the title question: How can you use KVO on a non-Objective-C type?
As it turns out, it's not too difficult to do, although it is somewhat ugly. Basically, you need to create an Objective-C property that is typed Any with the same Objective-C name as the Swift name of the real property. Then, you put willSet and didSet handlers on the real property that call the appropriate KVO methods for the Objective-C property. So, something like:
#objc(result) private var _resultKVO: Any { return self.result }
internal var result: Result<Data>! {
willSet { self.willChangeValue(for: \._resultKVO) }
didSet { self.didChangeValue(for: \._resultKVO) }
}
(For the sake of simplicity, I'm assuming that result is your stored property, and removing the lock and the private property from the equation)
The caveat is that you will have to use _resultKVO instead of result when constructing key paths to observe, which means that if this needs to be observable from outside the object, you can't make _resultKVO private, and you'll have to clutter up your class's interface with it. But so it goes.
Again, I probably wouldn't do this for your particular use case (and if you did, you could obviously fire the notifications in result's set rather than having to bother with willSet and didSet), but in some cases this can be useful, and it's good to have an answer describing how to do it as a reference.

Whats the difference between these two properties?

What's the difference between these two??
var sharedContextA: NSManagedObjectContext {
return CoreDataStackManager.sharedInstantce().managedObjectContext
}
var sharedContextB = {
return CoreDataStackManager.sharedInstantce().managedObjectContext
}()
To clarify, I have seen:
var variable: Type {
code
return X
}
but I don't know the name of this or how it is different than the former:
var variable = {
code
return X
}()
sharedContextA is a computed property. The value to be returned is computed each time the getter of the property is called.
sharedContextB uses a closure to assign a default value to the property. The closure is executed once during initialization of the type the property belongs to, afterwards the stored value is read directly.

Swift computed property to return copy of underlying array

I have a model class written in Objective-C that I'm converting to Swift. It contains an NSMutableArray internally, but the method signature for the getter, as well as the actual return value, are NSArray. When called, it creates an immutable copy to return.
Essentially, I want callers to be able to iterate/inspect the container, but not modify it. I have this test snippet:
class Container {
internal var myItems = [String]()
func sayHello() {
"I have: \(myItems)"
}
}
let cont = Container()
cont.myItems.append("Neat") // ["Neat"]
cont.sayHello() // This causes sayHello() to print: "I have: [Neat]"
var isThisACopy = cont.myItems
isThisACopy.append("Huh") // ["Neat", "Huh"]
cont.sayHello() // This ALSO causes sayHello() to print: "I have: [Neat]"
I've been trying to find a way to override the getter for myItems so that it returns an immutable copy, but can't seem to determine how.
Attempt #1
This produces a compiler error: Function produces expected type '_ArrayBuffer<(String)>'; did you mean to call it with '()'?
internal var myItems = [String]() {
var copy = [String]()
for item in ... { // What to use in the ...?
copy.append(item)
}
return copy
}
Attempt #2
This also produces a compiler error, because I'm (understandably) redefining the generated getter Invalid redeclaration of 'myItems()':
internal func myItems() -> [String] {
var copy = [String]()
for item in myItems {
copy.append(item)
}
return copy
}
Try this:
class Container {
private var _myItems: [String] = ["hello"]
internal var myItems: [String] {
return _myItems
}
}
let cont = Container()
cont.myItems.append("Neat") //not allowed
It uses a private stored property and a computed property that returns an immutable copy. It's not possible for a stored property to use custom getters.
A better way to expose mutable properties as immutable:
class Container {
private (set) internal var myItems: [String]
}

How do I initialize a property that depends on another property, when I don't have access to self yet?

I have two properties in my class. See this terrible example:
var length
var doubleLength
How do I initialize doubleLength based on length?
init() {
self.length = ...
self.doubleLength = self.length * 2
super.init()
}
I get an error that I can't access self before I call super.init(). Well I need to set all my variables before I can even call super.init() so what am I supposed to do?
if self.doubleLength is always supposed to be twice self.length (in this example) have you considered just using a computed property?
class MyClass: MySuperClass {
var length: Double
var doubleLength: Double {
return self.length * 2
}
init(len: Double) {
self.length = len
super.init()
}
}
You can temporarily delay the initialization of doubleLength an implicitly unwrapped optional, which will allow to temporarily assign a value to nil and assign it at a later time.
class Something: UICollectionViewLayout {
var doubleLength: Int! = nil
var length: Int {
return 50
}
init() {
super.init()
doubleLength = length * 2
}
}
Anyway, in this specific case I think it would be nicer to make doubleLength a computed property, since it can be always be computed from the value of length. Your class will be like
class Something: UICollectionViewLayout {
var doubleLength: Int {
return length * 2
}
var length: Int {
return 50
}
}
Thanks for your full reproduction, which is:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
var length: Int {
return 50
}
init() {
doubleLength = length * 2
super.init()
}
}
From this we can see that you're using a getter to return your property. I think this is what's causing the problem. For example, if you just do this:
import UIKit
class Something: UICollectionViewLayout {
var doubleLength: Int
// Simple variable, no code.
var length = 50
init() {
doubleLength = length * 2
super.init()
}
}
...then that works fine.
I believe this is because the Swift compiler is trying to prevent you from doing anything that might mean you use the base class's methods, properties or variables before it's been initialised. I know you're technically not, in your example, but consider how hard it is to trace back and see what's being done from your initialiser. For example, if you were to do:
var length: Int {
// Where "width" is a made-up property of UICollectionViewLayout
return width * 3
}
...then your code would be run from your initialiser and use a property of UICollectionViewLayout before its own init had been called, therefore making it possibly invalid.
So my best guess is that this is the Swift compiler making a blanket ban on calling out to any code outside the subclass initialiser before the super is initialised.
You get exactly the same error if you do this, for example:
class Something: UICollectionViewLayout {
func foo() {
// Do nothing
}
init() {
foo() // error: 'self' used before super.init call
super.init()
}
}
The place I remember this being explained is the "Intermediate Swift" video from WWDC 2014, from slide 191, about 20 minutes in, but I'm guessing it's somewhere in the book, too...
A property that depends on another is bad practice. Just like when you design a database, you avoid calculated fields, when you design classes, you also avoid calculated fields. Instead of having a doubleLength property, you should instead have a getDoubleLength method that returns the length * 2.