I am writing a game using GameplayKit & SpriteKit Frameworks. In Apples examples about the GameplayKit you often see the following:
class PlayerEntity: GKEntity {
// MARK: Components
var renderComponent: RPRenderComponent {
guard let renderComponent = componentForClass(RPRenderComponent.self) else {
fatalError()
}
return renderComponent
}
var stateMachineComponent: RPStateMachineComponent {
guard let stateMachineComponent = componentForClass(RPStateMachineComponent.self) else {
fatalError()
}
return stateMachineComponent
}
// MARK: Initialisation
override init() {
super.init()
let renderComponent = RPRenderComponent()
renderComponent.node.entity = self;
let stateMachineComponent = RPStateMachineComponent(states: [
RPPlayerStandingState(entity: self),
RPPlayerFallingState(entity: self),
RPPlayerBouncingDownState(entity: self),
RPPlayerBouncingUpState(entity: self),
RPPlayerJumpingState(entity: self),
RPPlayerBoostState(entity: self)
])
addComponent(renderComponent)
addComponent(stateMachineComponent)
}
}
Components are created and initialized during the initialization of the class they belong to and added to the components-array via addComponent(component: GKComponent).
To make these components accessible from outside the class Apples example always use computed properties which call componentForClass() to return the corresponding component-instance.
The render component however is accessed 'per-frame' meaning that during every update-cycle I need to call the render component and this will lead to call the computed property which in my eyes leads to additional and avoidable processing-load.
Calling would look like:
func update(withDeltaTime time: NSTimeInterval) {
playerEntity.renderNode.DoSomethingPerFrame()
}
Instead of this I am doing it like following:
class PlayerEntity: GKEntity {
// MARK: Components
let renderComponent: RPRenderComponent
var stateMachineComponent: RPStateMachineComponent!
// MARK: Initialisation
override init() {
renderComponent = RPRenderComponent()
super.init()
renderComponent.node.entity = self
stateMachineComponent = RPStateMachineComponent(states: [
RPPlayerStandingState(entity: self),
RPPlayerFallingState(entity: self),
RPPlayerBouncingDownState(entity: self),
RPPlayerBouncingUpState(entity: self),
RPPlayerJumpingState(entity: self),
RPPlayerBoostState(entity: self)
])
addComponent(renderComponent)
addComponent(stateMachineComponent)
}
}
Instead of getting access to the components using a computed property I am holding a strong reference to it in my class. In my eyes I am avoiding additional overhead when calling a computed property since I avoid that "computation".
But I am not pretty sure why Apple has done that using computed properties. Maybe I am totally wrong about computed properties or maybe it's just because this is the coding-style of the one who wrote that example!?
Are Computed Properties affecting performance? Do they automatically mean more overhead?
Or:
Is it OK and 'Safe' (in terms of resources) to use computed properties like this? (In my eyes computed properties are despite being afraid quite an elegant solution, btw.)
It depends - how much each calculation of the property costs, and how often you do that calculation.
In general, you should use computed properties if the calculation cost is so low that it makes little difference, and functions if it takes longer. Alternatively, a computed property can cache its values if the computed property often returns the same result.
Used properly, there is very little cost involved. You also would need to suggest an alternative to a computed property that is as easy to use and faster.
Related
I have a view structured like a form that creates a model object. I am trying to bind the form elements (UIControl) to the model properties, so that the views auto-update when their corresponding model property is changed, and the model update when the controls are changed (two way binding). The model can change without the view knowing because multiple views can be linked to one same model property.
Approach 1: Plain Swift
My problem is the following: to observe changes to the model properties, I tried to use KVO in Swift, and specifically the observe(_:changeHandler:) method.
class Binding<View: NSObject, Object: NSObject, ValueType> {
weak var object: Object?
weak var view: View?
var objectToViewObservation: NSKeyValueObservation?
var viewToObjectObservation: NSKeyValueObservation?
private var objectKeyPath: WritableKeyPath<Object, ValueType>
private var viewKeyPath: WritableKeyPath<View, ValueType>
init(betweenObject objectKeyPath: WritableKeyPath<Object, ValueType>,
andView viewKeyPath: WritableKeyPath<View, ValueType>) {
self.objectKeyPath = objectKeyPath
self.viewKeyPath = viewKeyPath
}
override func bind(_ object: Object, with view: View) {
super.bind(object, with: view)
self.object = object
self.view = view
// initial value from object to view
self.view![keyPath: viewKeyPath] = self.object![keyPath: objectKeyPath]
// object --> view
objectToViewObservation = object.observe(objectKeyPath) { _, change in
guard var view = self.view else {
// view doesn't exist anymore
self.objectToViewObservation = nil
return
}
guard let value = change.newValue else { return }
view[keyPath: self.viewKeyPath] = value
}
// view --> object
viewToObjectObservation = view.observe(viewKeyPath) { _, change in
guard var object = self.object else {
// object doesn't exist anymore
self.viewToObjectObservation = nil
return
}
guard let value = change.newValue else { return }
object[keyPath: self.objectKeyPath] = value
}
}
}
However some of the properties of my model have types CustomEnum, CustomClass, Bool?, and ClosedRange<Int>, and to use observe I had to mark them as #objc dynamic, which yielded the error:
Property cannot be marked #objc because its type cannot be represented in Objective-C
Approach 2: Using RxSwift rx.observe
I turned to RxSwift and the rx.observe method thinking I could work around this problem, but the same thing happened (at runtime this time).
// In some generic bridge class between the view and the model
func bind(to object: SomeObjectType) {
object.rx
.observe(SomeType.self, "someProperty")
.flatMap { Observable.from(optional: $0) }
.bind(to: self.controlProperty)
.disposed(by: disposeBag)
}
Approach 3: Using RxSwift BehaviorRelays?
This is my first experience with RxSwift, and I know I should be using BehaviorRelay for my model, however I don't want to change all my model properties as my model object is working with other framework. I could try to implement a bridge then, to transform model properties into BehaviorRelay, but I would come across the same problem: how to listen for model changes.
In this question, there were no answer as to how to listen for property changes without refactoring all model properties to RxSwift's Variable (currently deprecated).
Approach 4: Using didSet Swift property observer?
The didSet and willSet property observers in plain Swift would allow listening for changes, however this would require to mark all the properties in the model with these observers, which I find quite inconvenient, since my model object has a lot of properties. If there is a way to add these observers at runtime, this would solve my problem.
I believe that what I am trying to achieve is quite common, having a set of views that modify a model object, however I can't find a way to properly link the model to the view, so that both auto-update when needed.
Basically, I'm looking for an answer to one of the following questions:
Is there something I overlooked, is there a better way to achieve what I want?
or How to overcome the "Property cannot be marked #objc" problem?
or How to bridge my model object to BehaviorRelay without changing my model?
or How to add didSet observers at runtime?
You said:
I believe that what I am trying to achieve is quite common, having a set of views that modify a model object, however I can't find a way to properly link the model to the view, so that both auto-update when needed.
Actually it's not at all common. One idea you don't mention is to wrap your entire model into a Behavior Relay. Then the set of views can modify your model object.
Each of your views, in turn, can observe the model in the behavior relay and update accordingly. This is the basis of, for example, the Redux pattern.
You could also use your approach #3 and use property wrappers to make the code a bit cleaner:
#propertyWrapper
struct RxPublished<Value> {
private let relay: BehaviorRelay<Value>
public init(wrappedValue: Value) {
self.relay = BehaviorRelay(value: wrappedValue)
}
var wrappedValue: Value {
get { relay.value }
set { relay.accept(newValue) }
}
var projectedValue: Observable<Value> {
relay.asObservable()
}
}
But understand that the whole reason you are having this problem is not due to Rx itself, but rather due to the fact that you are trying to mix paradigms. You are increasing the complexity of your code. Hopefully, it's just a temporary increase during a refactoring.
Old Answer
You said you want to make it "so that the views auto-update when their corresponding model property is changed, and the model update when the controls are changed (two way binding)."
IMO, that way of thinking about the problem is incorrect. Better would be to examine each output independently of all other outputs and deal with it directly. In order to explain what I mean, I will use the example of converting °F to °C and back...
This sounds like a great reason to use 2-way binding but let's see?
// the chain of observables represents a view model
celsiusTextField.rx.text // • this is the input view
.orEmpty // • these next two convert
.compactMap { Double($0) } // the view into an input model
.map { $0 * 9 / 5 + 32 } // • this is the model
.map { "\($0)" } // • this converts the model into a view
.bind(to: fahrenheitTextField) // • this is the output view
.disposed(by: disposeBag)
fahrenheitTextField.rx.text
.orEmpty
.compactMap { Double($0) }
.map { ($0 - 32) * 5 / 9 }
.map { "\($0)" }
.bind(to: celsiusTextField.rx.text)
.disposed(by: disposeBag)
The above code handles the two-way communication between the text fields without two-way binding. It does this by using two separate view models (The view model is the code between the text Observable and the text Observer as described in the comments.)
We can see a lot of duplication. We can DRY it up a bit:
extension ControlProperty where PropertyType == String? {
func viewModel(model: #escaping (Double) -> Double) -> Observable<String> {
orEmpty
.compactMap { Double($0) }
.map(model)
.map { "\($0)" }
}
}
You may prefer a different error handling strategy than what I used above. I was striving for simplicity since this is an example.
The key though is that each observable chain should be centered on a particular effect. It should combine all the causes that contribute to that effect, implement some sort of logic on the inputs, and then emit the needed output for that effect. If you do this to each output individually you will find that you don't need two-way binding at all.
How i can use lazy initialization with get and set() closure.
Here is lazy initialization code:
lazy var pi: Double = {
// Calculations...
return resultOfCalculation
}()
and here is getter/setter code :
var pi: Double {
get {
//code to execute
return someValue
}
set(newValue) {
//code to execute
}
}
I assume what you're trying to do is lazily generate the default for a writable property. I often find that people jump to laziness when it isn't needed. Make sure this is really worth the trouble. This would only be worth it if the default value is rarely used, but fairly expensive to create. But if that's your situation, this is one way to do it.
lazy implements one very specific and fairly limited pattern that often is not what you want. (It's not clear at all that lazy was a valuable addition to the language given how it works, and there is active work in replacing it with a much more powerful and useful system of attributes.) When lazy isn't the tool you want, you just build your own. In your example, it would look like this:
private var _pi: Double?
var pi: Double {
get {
if let pi = _pi { return pi }
let result = // calculations....
_pi = result
return result
}
set { _pi = newValue }
}
This said, in most of the cases I've seen this come up, it's better to use a default value in init:
func computePi() -> Double {
// compute and return value
}
// This is global. Globals are lazy (in a thread-safe way) automatically.
let computedPi = computePi()
struct X {
let pi: Double // I'm assuming it was var only because it might be overridden
init(pi: Double = computedPi) {
self.pi = pi
}
}
Doing it this way only computes pi once in the whole program (rather than once per instance). And it lets us make pi "write-exactly-once" rather than mutable state. (That may or may not match your needs; if it really needs to be writable, then var.)
A similar default value approach can be used for objects that are expensive to construct (rather than static things that are expensive to compute) without needing a global.
struct X {
let pi: Double
init(pi: ExpensiveObject = ExpensiveObject()) {
self.pi = pi
}
}
But sometimes getters and setters are a better fit.
The point of a lazy variable is that it is not initialized until it is fetched, thus preventing its (possibly expensive) initializer from running until and unless the value of the variable is accessed.
Well, that's exactly what a getter for a calculated variable does too! It doesn't run until and unless it is called. Therefore, a getter for a calculated variable is lazy.
The question, on the whole, is thus meaningless. (The phrase "How i can use lazy initialization" reveals the flaw, since a calculated variable is never initialized — it is calculated!)
I learned Swift from the CS193P class. It recommends the following API for a ViewController FaceViewController to update its view FaceView:
var expression = FacialExpression(eyes: .Closed, eyeBrows: .Relaxed, mouth: .Smirk) {
didSet {
updateUI() // Model changed, so update the View
}
}
However, I have not seen an extension of this concept for when a view updates its own model. For example this does not make sense:
// Implementing an imaginary delegate UIFaceViewDelegate
func faceView(_ faceView: FaceView, didEpdateExpressionTo expression: FacialExpression {
self.expression = expression
// This triggers another update to the view, and possibly infinite recursion
}
In Objective-C, this was very straightforward because you could use getters and setters as your public API and the backing store as your private state. Swift can use calculated variables to use this approach as well but I believe the Swift designers have something different in mind.
So, what is an appropriate way for a view controller to represent state changes in response to view updates, while also exposing a reasonable read/write API for others to inspect its state?
I also watched the cs193p Winter 2017 videos. For the FaceIt app, the mdoel need to be translated to how it will be displayed on the view. And it's not 1 to 1 translation, but more like 3 to 2 or something like that. That's why we have helper method updateUI(_:).
As for the question on how the view controller would update model based on the change in the view. In this example, we couldn't update the model as we need to figure out how to map 2 values to 3 values? If we want persistence, we could just stored the view state in core data or userDefaults.
In a more general settings, where the model change need to update the view and view change need to update the model, then we'll need to have indirection to avoid the cycle like you envision.
For example, since the FacialExpression is a value type. We could have something like:
private var realExpression = FacialExpression(eyes: .Closed, eyeBrows: .Relaxed, mouth: .Smirk)
var expression: FacialExpression {
get { return realExpression }
set {
realExpression = newValue
updateUI() // Model changed, so update the View
}
}
}
Then in your imaginary delegate UIFaceViewDelegate we could have the following:
// Implementing an imaginary delegate UIFaceViewDelegate
func faceView(_ faceView: FaceView, didEpdateExpressionTo expression: FacialExpression {
self.realExpression = expression
// This WILL NOT triggers another update to the view, and AVOID THE possibly of infinite recursion
}
Following is my test code:
class SubView:UIView{
}
class TestVC: UIViewController {
var testView : SubView = SubView.init(frame: CGRect.zero) {
didSet{
print("testView didSet")
}
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
var testBtn = UIButton.init(frame: CGRect(x: 0, y: 0, width: 264, height: 45))
testBtn.backgroundColor = .red
testBtn.addTarget(self, action: #selector(clickToUpdateTestView), for: UIControlEvents.touchUpInside)
self.view.addSubview(testBtn)
}
func clickToUpdateTestView() -> Void {
self.testView = SubView.init(frame: CGRect.zero)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
But I get "testView didSet" in console output when button is clicked. What's the difference with your implement?
Hange's solution is good, although it does not work for reference types, as they said.
It also introduces another, basically redundant (private) variable, mimicking Objective-C's way of distinguishing between properties and backing member variables. This is a matter of style, personally I would mostly try to avoid that (but I have done the same thing Hange suggests, too).
My reason is that for reference types you need to do this differently anyways and I try to avoid following too many different coding patterns (or having too many redundant variables).
Here's a different proposal:
The important point is to break the cycle at some point. I usually go by "only inform your delegates if you actually did change something about your data". You can do so either in the view's themselves (many do so anyways for rendering performance reasons), but that's not always the case. The view controller isn't a bad place for this check, so I would adapt your observer like this:
var expression = FacialExpression(eyes: .Closed, eyeBrows: .Relaxed, mouth: .Smirk) {
didSet {
if updateIsNecessary() {
updateUI() // Model changed, so update the View
}
}
}
updateIsNecessary() obviously determines whether the view actually needs to be changed or not and might rely on oldValue and/or whatever mapping you have between model and view data. Now if the change actually originated from the view in the first place (which informed the view controller, who informed the model, who now informs the view controller again) there shouldn't be anything necessary to update, as the view was the one making a change in the first place.
You might argue that this introduces unnecessary overhead, but I doubt the performance hit is actually big, as it's usually just some easy checks. I usually have a similar check when the model gets updated, too, for the same reasons.
Giving the variable expression should be in sync with the FaceView representation meaning expression should have the correct value even if FaceView was set from an input other than our expression and vice versa you can simply make sure updateUI is called iff expression 's newValue is different from its oldValue. This will avoid the recursive call from FaceView to expression to updateUI and back to FaceView
var expression: FacialExpression = FacialExpression(eyes: .Closed, eyeBrows: .Relaxed, mouth: .Smirk) {
didSet {
if expression != oldValue {
updateUI()
}
}
}
This means FacialExpression should conform to Equatable which you can do by overloading == operator.
public extension FacialExpression: Equatable {
static func ==(lhs: FacialExpression, rhs: FacialExpression) -> Bool {
return lhs == rhs // TODO: Logic to compare FacialExpression
}
}
I didn't use a proper text editor so pardon me if I've made typos
EDIT:
There will be one unnecessary update of FaceView with the same expression value when expression is set from the imaginary delegate first time with a different value but there won't be anymore repetition since expression will then be in sync.
To avoid even that, you can compare expression with another expression property in FaceView that holds the current expression.
var expression: FacialExpression = FacialExpression(eyes: .Closed, eyeBrows: .Relaxed, mouth: .Smirk) {
didSet {
if expression != faceView.currentExpression {
updateUI()
}
}
}
I've recently started profiling one of my iOS app written in swift and realized how annoying ARC is compared to other more adopted GC like Mark-And-Sweep.
One of the most prevalent causes for Strong Reference Cycle was retaining instance property within a closure that is passed to another object retained, again, by the class.
For example,
class MyClass {
private let text = "hello world"
private let anotherClass = AnotherClass()
init() {
addText()
}
private func addText() {
anotherClass.addText { return self.text }
}
}
Retain cycle like above can be avoided by passing argument to the method instead of accessing self directly.
class MyClass {
private let text = "hello world"
private let anotherClass = AnotherClass()
init() {
addText(text)
}
private func addText(text:String) {
anotherClass.addText { return text }
}
}
Is the second approach considered a good practice?
FYI, I'm aware that retain cycle like above can be broken using capture list. I'm just curious as to patterns that are more resilient to memory leaks.
Since the property let text ... is a constant, I think that the second approach is fine and can be considered a best practice.
But if you use the same approach with a var text ... property, then the behaviour changes:
in the first approach an execution of the closure will use the current value of text,
while in the second approach an execution of the closure will always use the original value of text.
I commonly use a "faulting" or lazy initialization pattern in iOS when dealing with big objects.
Whenever a class has a property pointing to a "fat" object, I create a custom getter that checks if the iVar is nil. If it is, it creates the fat object and returns it. If it isn't, it just returns the "fat" object.
The container of this property also subscribes to memory warnings, and when one is received, it sets the iVar to nil, reducing the memory footprint. As you see, it's pretty similar to faulting in Core Data.
I'm trying to reproduce this in Swift, but haven't found a decent and elegant solution so far.
a) First Attempt: lazy stored properties
This doesn't work, because if I set the property to nil, it will remain nil forever. The "magic" only happens the first time you access the property:
struct FatThing{
// I represent something big, which might have to be
// "faulted" (set to nil) when a memory warning
// is received
var bigThing = "I'm fat"
}
class Container {
lazy var fat: FatThing? = FatThing()
}
var c = Container()
c.fat
c.fat = nil
c.fat // returns nil
b) Second attempt: A stored property with observers
This also fails, because of the lack of get observers. I need a willGet and didGet, not just willSet and didSet.
Why on Earth are there no get obeservers? What's the use of this half backed thing called observers?
c) Third attempt: A computed property with a stored helper property
This is the only working option I've found so far, but it's as ugly as a baboon's rear end!
struct FatThing{
// I represent something big, which might have to be
// "faulted" (set to nil) when a memory warning
// is received
var bigThing = "I'm fat"
}
class Container {
private var _fat : FatThing? // having this extra and exposed var kills my inner child
var fat: FatThing? {
get{
if _fat == nil {
_fat = FatThing()
}
return _fat
}
set{
_fat = newValue
}
}
}
var c = Container()
c.fat
c.fat = nil
c.fat // returns FatThing
So much for making my code look simpler and shorter...
Is there a simple and elegant way to implement this? This is no exotic stuff in a memory deprived environment as iOS!
The ability to override the getter or setter individually is a peculiarity of objective C that has no counterpart in swift.
The right option at your disposal is no. 3, using a backing property to store the fat data and a computed property to make it accessible. I agree that there's some boilerplate code, but that's the tradeoff for having what you need.
However, if you use that pattern frequently, then you can create a protocol:
protocol Instantiable {
init()
}
and implement it in your FatThing struct/class. Next, create a generic function containing the boilerplate code:
func lazyInitializer<T: Instantiable>(inout property: T?) -> T {
if property == nil {
property = T()
}
return property!
}
Note that T must implement Instantiable - that allows you to create an instance with a parameterless constructor.
Last, use it as follows:
private var _fat : FatThing? // having this extra and exposed var kills my inner child
var fat: FatThing? {
get { return lazyInitializer(&self._fat) }
set { _fat = newValue }
}
Note that in your code you don't have to declare the fat computer property as optional - you are ensuring in the get implementation that it is always not nil, so a better implementation is:
var fat: FatThing {
get{
if _fat == nil {
_fat = FatThing()
}
return _fat!
}
set{
_fat = newValue
}
}