Suppose there is some struct, with a nested struct that has some functionality I want to modify or extend. How do you override a computed property of a struct, when the computed property is inside a nested struct? Example:
public struct Foo {
var c: Int
init(c: Int) {
self.c = c
}
// Suppose there's lots of implementation
}
extension Foo {
struct FooContent {
var a: Int
public var b: Int { self.a + 1 }
init(a: Int) {
self.a = a
}
}
// Suppose there's lots of implementation
}
var obj = Foo.FooContent(a: 1)
print(obj.b)
Suppose I want to override b to be self.a + 2, and not touch any other functionality in Foo or FooContent. Is there a way to do this something along the lines of
extension Foo.FooContent {
public var b: Int { self.a + 2 }
// won't compile because b is already defined
}
Seems like a big hole in the language design that structs + extension functionality can't be inherited. I figure I'm missing something.
I have two classes which have the same variables and the same methods but the methods do different things. I want to declare an instance name and later on I want to decide which of the classes will be instanciated.
class A {
var x : Int = 0
func calc() {
x = 10
}
}
class B {
var x : Int = 0
func calc() {
x = 33
}
}
class X : UIViewController {
var value : Int = 0
var AorB : (class A or B, I decide later on in the code)
...
override func viewDidLoad() {
super.viewDidLoad()
// Here I want to decide that aorB is an Instance of A or of B
}
How can I solve this?
Try this method:
protocol SomeProtocol{}
class A:SomeProtocol {
var x : Int = 0
func calc() {
x = 10
}
}
class B:SomeProtocol {
var x : Int = 0
func calc() {
x = 33
}
}
class X : UIViewController {
var value : Int = 0
var AorB : SomeProtocol!
...
override func viewDidLoad() {
super.viewDidLoad()
AorB = A()
AorB = B()
// Here I want to decide that aorB is an Instance of A or of B
}
I'm considering converting a project using my own custom signal framework to use ReactiveSwift instead, but there is a fundamental issue I've never figured out how to resolve in ReactiveSwift:
As a simplified example, let's say you have two mutable properties:
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
Then, we derive a property that combines both to implement our logic:
let c = Property.combineLatest(a, b).map { a, b in
return a + b
}
Later, we receive some information that causes us to update the values of both a and b at the same time:
a.value = 3
b.value = 4
The problem now is that c will inform its listeners that it has the values 3 -> 5 -> 7. The 5 is entirely spurious and does not represent a valid state, as we never wanted a state where a was equal to 3 and b was equal to 2.
Is there a way around this? A way to suppress updates to a Property while updating all of its dependencies to new states, and only letting an update through once you are done?
combineLatest‘s fundamental purpose is to send a value when either of its upstream inputs send a new value, so I don’t think there’s a way to avoid this issue if you want to use that operator.
If it’s important that both values update truly simultaneously then consider using a MutableProperty<(Int, Int)> or putting the two values in a struct. If you give a little more context about what you’re actually trying to accomplish then maybe we could give a better answer.
Pausing Updates
So I really don't recommend doing something like this, but if you want a general purpose technique for "pausing" updates then you can do it with a global variable indicating whether updates are paused and the filter operator:
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
var pauseUpdates = false
let c = Property.combineLatest(a, b)
.filter(initial: (0, 0)) { _ in !pauseUpdates }
.map { a, b in
return a + b
}
func update(newA: Int, newB: Int) {
pauseUpdates = true
a.value = newA
pauseUpdates = false
b.value = newB
}
c.producer.startWithValues { c in print(c) }
update(newA: 3, newB: 4)
But there are probably better context-specific solutions for achieving whatever you are trying to achieve.
Using a sampler to manually trigger updates
An alternate solution is to use the sample operator to manually choose when to take a value:
class MyClass {
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
let c: Property<Int>
private let sampler: Signal<Void, Never>.Observer
init() {
let (signal, input) = Signal<Void, Never>.pipe()
sampler = input
let updates = Property.combineLatest(a, b)
.map { a, b in
return a + b
}
.producer
.sample(with: signal)
.map { $0.0 }
c = Property(initial: a.value + b.value, then: updates)
}
func update(a: Int, b: Int) {
self.a.value = a
self.b.value = b
sampler.send(value: ())
}
}
let x = MyClass()
x.c.producer.startWithValues { c in print(c) }
x.update(a: 3, b: 4)
Using zip
If a and b are always going to change together, you can use the zip operator which waits for both inputs to have new values:
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
let c = Property.zip(a, b).map(+)
c.producer.startWithValues { c in print(c) }
a.value = 3
b.value = 4
Use zip with methods for each type of update
class MyClass {
let a = MutableProperty<Int>(1)
let b = MutableProperty<Int>(2)
let c: Property<Int>
init() {
c = Property.zip(a, b).map(+)
}
func update(a: Int, b: Int) {
self.a.value = a
self.b.value = b
}
func update(a: Int) {
self.a.value = a
self.b.value = self.b.value
}
func update(b: Int) {
self.a.value = self.a.value
self.b.value = b
}
}
let x = MyClass()
x.c.producer.startWithValues { c in print(c) }
x.update(a: 5)
x.update(b: 7)
x.update(a: 8, b: 8)
Combining the values into one struct
I thought I would provide an example of this even though you said you didn't want to do it, because MutableProperty has a modify method that makes it less cumbersome than you might think to do atomic updates:
struct Values {
var a: Int
var b: Int
}
let ab = MutableProperty(Values(a: 1, b: 2))
let c = ab.map { $0.a + $0.b }
c.producer.startWithValues { c in print(c) }
ab.modify { values in
values.a = 3
values.b = 4
}
And you could even have convenience properties for directly accessing a and b even as the ab property is the source of truth:
let a = ab.map(\.a)
let b = ab.map(\.b)
Creating a new type of mutable property to wrap the composite property
You could create a new class conforming to MutablePropertyProtocol to make it more ergonomic to use a struct to hold your values:
class MutablePropertyWrapper<T, U>: MutablePropertyProtocol {
typealias Value = U
var value: U {
get { property.value[keyPath: keyPath] }
set {
property.modify { val in
var newVal = val
newVal[keyPath: self.keyPath] = newValue
val = newVal
}
}
}
var lifetime: Lifetime {
property.lifetime
}
var producer: SignalProducer<U, Never> {
property.map(keyPath).producer
}
var signal: Signal<U, Never> {
property.map(keyPath).signal
}
private let property: MutableProperty<T>
private let keyPath: WritableKeyPath<T, U>
init(_ property: MutableProperty<T>, keyPath: WritableKeyPath<T, U>) {
self.property = property
self.keyPath = keyPath
}
}
With this, you can create mutable versions of a and b that make it nice and easy to both get and set values:
struct Values {
var a: Int
var b: Int
}
let ab = MutableProperty(Values(a: 1, b: 2))
let a = MutablePropertyWrapper(ab, keyPath: \.a)
let b = MutablePropertyWrapper(ab, keyPath: \.b)
let c = ab.map { $0.a + $0.b }
c.producer.startWithValues { c in print(c) }
// Update the values individually, triggering two updates
a.value = 10
b.value = 20
// Update both values atomically, triggering a single update
ab.modify { values in
values.a = 30
values.b = 40
}
If you have the Xcode 11 Beta installed, you can even use the new key path based #dynamicMemberLookup feature to make this more ergonomic:
#dynamicMemberLookup
protocol MemberAccessingProperty: MutablePropertyProtocol {
subscript<U>(dynamicMember keyPath: WritableKeyPath<Value, U>) -> MutablePropertyWrapper<Value, U> { get }
}
extension MutableProperty: MemberAccessingProperty {
subscript<U>(dynamicMember keyPath: WritableKeyPath<Value, U>) -> MutablePropertyWrapper<Value, U> {
return MutablePropertyWrapper(self, keyPath: keyPath)
}
}
Now instead of:
let a = MutablePropertyWrapper(ab, keyPath: \.a)
let b = MutablePropertyWrapper(ab, keyPath: \.b)
You can write:
let a = ab.a
let b = ab.b
Or just set the values directly without creating separate variables:
ab.a.value = 10
ab.b.value = 20
I want to override properties in the following class. Say I have a class A that has a boolean property r. For the superclass A, I want r to be set and get normally. For the subclass B, I want r to always be false. I'm not sure why this is harder than it should be...
class A {
init(r: Bool) {
self.r = r
}
var r: Bool {
willSet(n) {
r = n
}
get {
return r
}
}
}
class B: A {
override var r: Bool {
willSet(n) {
r = n
}
get {
return false
}
}
}
let a = A(r: true)
a.r = false
print(a.r) // prints 'false', which is good
let b = B(r: true)
print(b.r) // prints 'true'
b.r = false // ERROR: I can't get pass this point 'Execution was interrupted on playground
print(b.r)
I agree with #Hamish: stored property in base class, with computed property override. Except, a read-only property can't override a mutable property. But, you can make the overridden setter do nothing, and the overridden getter return what you want.
class A {
init(r: Bool) {
self.r = r
}
var r: Bool
}
class B: A {
override var r: Bool {
set {}
get {
return false
}
}
}
let a = A(r: true)
print(a.r) // "true"
a.r = false
print(a.r) // "false"
let b = B(r: true)
print(b.r) // "false"
b.r = true
print(b.r) // "false"
Is it possible to add protocol compliance to a different protocol by way of an extension?
For instance we would like A to comply with B:
protocol A {
var a : UIView {get}
}
protocol B {
var b : UIView {get}
}
I want to give a default implementation (compliance) of B to objects of type A
// This isn't possible
extension A : B {
var b : UIView {
return self.a
}
}
The motivation being to reuse objects of A in cases where a B is required without creating my own "bridge"
class MyClass {
func myFunc(object : A) {
...
...
let view = object.a
... do something with view ...
myFunc(object) // would like to use an 'A' without creating a 'B'
}
func myFunc2(object : B) {
...
...
let view = object.b
... do something with view ...
}
}
As a side note we can extend a class to implement a protocol
class C {
let C : UIView
}
// this will work
extension C : B {
var B : UIView {
return self.c
}
}
and protocols can give default implementations
extension A {
// a default implementation
var a : UIView {
return UIView()
}
}
When extending A, you could specify that the type also conforms to B:
extension A where Self: B {
var b : UIView {
return self.a
}
}
Then make your type conform to A and B, e.g.
struct MyStruct : A, B {
var a : UIView {
return UIView()
}
}
Due to the protocol extension, instances of MyStruct will be able to use a and b, even though only a was implemented in MyStruct:
let obj = MyStruct()
obj.a
obj.b
You can make A inherits from B:
protocol A: B { var a: String { get } }
protocol B { var b: String { get } }
// Default implementation of property b
extension A {
var b: String { get { return "PropertyB" } }
}
class MyClass: A {
var a: String { get { return "PropertyA" } }
func printA(obj: A) {
print(obj.a)
printB(obj)
}
func printB(obj: B) {
print(obj.b)
}
}
let obj = MyClass()
obj.printA(obj)
Since A inherits from B, every property in B is available in A.