Objects with common property - swift

I have three different classes A, B and C with some commons properties. For instance all of them have property called index. Also all of them inheritance from other class X which doesn't have property index and I can't modify these classes (it's from framework). Now I want to create instantiation one of these classes and set index property. How I'm doing it now:
func returnPreparedObjet() -> X? {
if some_condition1 {
let a = A()
a.index = 1
return a
}
else if some_condition2 {
let b = B()
b.index = 1
return b
}
else if some_condition3 {
let c = C()
c.index = 1
return c
}
return nil
}
What is the best option to achieve it without repeat .index = 1 and return lines? Can I achieve this also in situation when A,B,C don't inheritance from X?

You could group the three classes under a common protocol:
protocol Indexed {
var index: Int { get set }
}
, and add conformance for the three classes
extension A: Indexed {}
extension B: Indexed {}
extension C: Indexed {}
no code will be needed in the extensions as the classes already declare a writable index property.
You can then simplify the returnPreparedObject to something like this:
func returnPreparedObject() -> X? {
let result: (X & Indexed)?
if some_condition1 {
result = A()
} else if some_condition2 {
result = B()
} else if some_condition3 {
result = C()
}
result?.index = 1
return result
}

Related

2 instances of 1 class don't share their property

I have 2 classes(A,B) that have instances of another class(C) as their property. Class C have property with some values(no matter what type). A class have methods that removes and append objects from/to C. B class have method that returns objects from class C. Now classes A and B have their views, on A view user able to append and remove object from C and view updates everytime when C changes, and view B call B class method when appear to load object from C, but method returns 0 objects.Here is code example:
class C{
var property = [Something]
}
class A{
var c = C()
func appendOrremove(){
//... some action
}
}
class B{
var c = C()
func getProperty()->[Something]{
//... return property of c
}
}
I can provide exact my code where I faced the problem, but it will much more code than above.Thanks in advance!
Okey I better show my code
class FavoriteBeers{
var favoriteBeers = [Beer]()
}
class BeersListInteractor:BeersListInteractorProtocol{
private var favoriteBeers = FavoriteBeers()
func addToFavorites(beer: Beer){
favoriteBeers.favoriteBeers.append(beer)
saveFavoriteBeers()
}
func removeFromFavorites(_ beer: Beer) {
favoriteBeers.favoriteBeers.removeAll { $0 == beer }
saveFavoriteBeers()
}
}
class FavoriteBeersInteractor:FavoriteBeersInteractorProtocol{
private var favoriteBeers = FavoriteBeers()
func getFavoriteBeers()-> [Beer]{
return favoriteBeers.favoriteBeers
}
}
You don't show how objects of the A and B classes are related but that will be important for how they share the c object. Here's a playground example that would work if something else controls A and B instances.
class Something{
}
class C{
var property = [Something()]
}
class A{
var c: C?
func appendOrremove(){
}
}
class B{
var c: C?
func getProperty()->[Something]{
return c?.property ?? []
}
}
let exC = C()
let exA = A()
exA.c = exC
let exB = B()
exB.c = exC
Another common situation would have A objects create B objects. In that case you might want classes defined something like:
class A{
var c = C()
var b: B
init() {
b = B(c)
}
func appendOrremove(){
}
}
class B{
var c: C
init(_ inC: C) {
c = inC
}
func getProperty()->[Something]{
return c.property
}
}

Synchronising combined Properties in ReactiveSwift

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

How can i pass class as a parameter to a function in Swift?

Let us consider i have two different classes.
class A {
var something = "Hello"
}
class B {
var something = "World"
}
Now
class C {
func request() {
//Call with class A or B it can contain any class. I can call either class A or B depending on condition
update(myClass: A or B)
}
func update(myClass:A or B ) {
print(myClass.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
Plz help me achieve this using Swift
You cannot declare a function in Swift that could accept an input argument of several different types, so you cannot declare a type as A or B. However, you don't actually need this to solve your specific problem.
Since you want to access a common property of the two class instances, you should declare that property in a protocol, make both classes conform to that protocol, then make the function take an input argument of the protocol type.
protocol SomethingProtocol {
var something: String { get }
}
class A: SomethingProtocol {
let something = "Hello"
}
class B: SomethingProtocol {
let something = "World"
}
class C {
func request() {
//Call with class A or B it can contain any class. I can call either class A or B depending on condition
update(something: A())
update(something: B())
}
func update(something: SomethingProtocol) {
print(something.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
Use a protocol
protocol MyProtocol: class {
var something: String { get set }
}
class A: MyProtocol {
var something = "Hello"
}
class B: MyProtocol {
var something = "world"
}
class C {
func update(myClass:MyProtocol ) {
print(myClass.something) //Since both class have same varaible var something so this code should work either i pass class A or B through function
}
}
usage:
let a = A()
let b = B()
let c = C()
print(c.update(myClass: a))
print(c.update(myClass: b))
Output:
hello
world
Create a protocol that both A and B conforms to and use it as the parameter type in update()
protocol SomeProtocol {
var something: String {get set}
}
func update(_ o: SomeProtocol) {
print(o.something)
}
Let it be known that I think using a protocol is the cleanest option that will best solve your problem.
However, it is possible to use Any to pass any object as a parameter, this will require checking which class you are dealing with inside your update method.
Something like this...
class C {
func update(myClass: Any) {
if let a = myClass as? A {
print(a.something)
}
if let b = myClass as? B {
print(b.something)
}
}
}
This might be neater as a switch - ref
class C {
func update(myClass: Any) {
switch myClass {
case let a as A:
print(a.something)
case let b as B:
print(b.something)
default:
print("not a thing")
}
}
}

Swift: func return type inheritting class and conforming one or more protocols

From an external library I've got the following scenario.
The protocol and base class:
protocol P1 {
// P1 Stuff
}
class A {
// A Stuff
}
Then there is an extension, which causes my troubles. It is defined for the combination of types P1 and A.
extension P1 where Self : A {
public func myDesiredFunc() {
// Do stuff.
}
}
And finally there are the implementations B1 - Bn, which I use.
class B1 : A, P1 {
}
class B2 : A, P1 {
}
...
In my code I need to put together instances of B-classes and work with them. The problem is, that I need to use the extension func myDesiredFunc(). So I need somehow define, that the array type is something like [(A & P1)] and the return type of producing funciton is (A & P1) as well.
However, with this code:
func createBeeInstance() -> (A & P1) {
if something {
return B1()
} else if something {
return B2()
}
...
}
I'm getting the error:
Non-protocol type 'A' cannot be used within a protocol composition.
Is there a way to say that the return type is a composition of class and protocol? I'm not able to change the scenario because it's an external library.
Swift 4:
^_^
it's possible now to compose class and protocol in swift 4 so modifying the previous snippets to this should work
class A {
// A Stuff
required init () {}
}
protocol P1 {
// P1 Stuff
}
class B1 : A {}
class B3: P1 {}
class B2 : A, P1 {}
func createBeeInstance<T: P1 & A>(type: T.Type) -> T {
return type.init()
}
var things = [P1 & A]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
//let f1 = createBeeInstance(type: B1.self) // will error
//let f2 = createBeeInstance(type: B3.self) // will error
things.append(f) // is fine
--- OLD Way which did not work ---
You may use this way ,
having the Sample you provided with modifying class A to have init
class A {
// A Stuff
required init () {}
}
modifying createBee method to
func createBeeInstance<T: P1>(type: T.Type) -> T where T: A {
return type.init()
}
this way you will provide the type as an input e.g. B1.self
for array we can provide typealieased generic
typealias B<T:P1> = T where T: A
var things = [B<A>]() // still Element has to be P1 as well
let f = createBeeInstance(type: B2.self)
let f1 = createBeeInstance(type: B1.self)
things.append(f)
One possible solution would be to define a protocol that defines the essential nature of objects of type A (let's call the new protocol Aable), and make the A type conform to it:
class A: Aable {
// A stuff
}
You could then constrain the P1 protocol extension with Aable instead of A:
extension P1 where Self : Aable {
func myDesiredFunc() {
// Do stuff.
}
}
That would allow you to use protocol composition for the return type of a function...
func createBeeInstance(useB1: Bool) -> (Aable & P1) {
return useB1 ? B1() : B2()
}
...as well as for the element type of an array:
var things = [Aable & P1]()
for i in 1...5 {
let b = createBeeInstance(useB1: i % 2 == 0)
things.append(b)
}
for thing in things {
thing.myDesiredFunc()
}

Swift - difference between class level instantiation and method level instantiation

What is the difference between the following usages? Is there a difference?
class B { }
// usage 1
class A {
var b: B = B();
}
// usage 2
class A {
var b: B!
init() {
self.b = B()
}
}
Edit:
Some of the answers point out that in usage 2 the value does not need to be an optional since it gets a value in the initializer.
Instantiation is done in the declarative order of the assignation statements. But class level statements (stored properties) are done before method level statements:
// in this example, the order will be C, D, B, A
class MyClass {
init() {
b = B()
a = A()
}
var a: A
var b: B
var c: C = C()
var d: D = D()
}
Assuming the extra ! in usage 2 is not something you meant, no there is absolutely no difference between
// usage 1
class A {
var b: B = B();
}
and
// usage 2
class A {
var b: B
init() {
self.b = B()
}
}
It's exactly the same.
Yes, there's a huge difference between these two. In usage 2, b is an implicitly unwrapped optional. When you do:
let a = A()
then a.b will be set in both cases, but in usage 2, somebody can then do:
a.b = nil
and then you'll get an error if you try to use it.