2 instances of 1 class don't share their property - swift

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
}
}

Related

Not Able to access values with .Type swift

Why am I not able to assign and read value from Type B in below code? B.self should be passed as a type and not an instance, so it should access static var in class B right?
class A{
}
class B:A{
static var a = 5
}
class c{
static func a(){
b(type: B.self)
}
static func b(type:B.Type){
print(type.a)
}
func takeObject<T>(type:T.Type){
print(type(of:String.self)) // String.Type
print(type) // B
print(type.a) // Value of type 'T' has no member 'a'
var a :type // Use of undeclared type 'type'
}
}
let objects : c = c()
objects.takeObject(object: B.self)
Correct me please, I am new on this topic and it seems quite interesting.
As i think you just want to add objects of type B so you can specify generic T of type B as below,
class A {}
class B: A {
static var a = 5
}
class c {
static func a() {
b(type: B.self)
}
static func b(type: B.Type){
print(type.a)
}
func takeObject<T: B>(type: T.Type){
print(type)
print(type.a)
var a : T
}
}
let objects : c = c()
objects.takeObject(type: B.self)

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 - 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.

Extend existing protocols to implement another protocol with default implements

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.

Change type of generic method in generic class

Please consider the following classes:
// Models:
class A {}
class B: A { }
// Parsers:
class AbstractParser<T> {}
class ParserB<T: B>: AbstractParser<T> {}
// Services:
class AbstractService<T> {
func parser() -> AbstractParser<T> {
fatalError("This method must be overridden")
}
}
class ServiceA<T: A>: AbstractService<T> {
}
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB()
override func parser() -> ParserB<B> {
return _parser
}
}
I'm getting an error Method doesn not override any method from it's superclasses at overriden parser function. I could easily fix this by changing
class ServiceB<T: B>: ServiceA<T>
to
class ServiceB<T: B>: ServiceA<B>
but this will break a solution from this question: A variable in generic class gets wrong type
Is there any workaround for this?
EDIT
Thanks, Kenneth Bruno, your approach works, but it again leads to another error with types.
I add class C:
class C {
var item = B()
}
and a simple method to ServiceB:
func doSomething() {
var entities = [T]()
let c = C()
entities.append(c.item)
}
This causes error: Cannot invoke 'append' method with an argument list of type '(B)'. It seems the compiler can't understand that B and T are the same thing?
Also please note that I can't define var entities = [B](), as I need to pass this array to another function in AbstractService method.
Just as in your other question you need to use the generic type instead of a specific type, then the method signatures will match to override the function.
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB<T>()
override func parser() -> ParserB<T> {
return _parser
}
}
From the question edit:
This causes error: Cannot invoke 'append' method with an argument list of type '(B)'. It seems the compiler can't understand that B and T are the same thing?
Just to clarify things. In the edit code example <T: B> and B are not the same thing. B is a regular type, while <T: B> is a generic type, which may represent a B type or any of it's subtypes.
Merging the question code with the code proposed by #Kenneth results in the following, which leads to a type error
class C {
var item = B()
}
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB<T>()
override func parser() -> ParserB<T> {
return _parser
}
func doSomething() {
var entities = [T]()
let c = C()
entities.append(c.item) // Error: Cannot invoke 'append' method with an argument list of type '(B)'
}
}
Now let's say in the future we add a new type D, subtype of B and instantiate a ServiceB<D>. This would cause the function doSomething() to try to append an instance of B in an array of D which is illegal, that's why the compiler raises an error.
With the code proposed in the comments by #Kenneth, the entities array would be filled in the ServiceB<B> case, but would always be empty in the ServiceB<D>.
class D: B { }
class ServiceB<T: B>: ServiceA<T> {
...
func doSomething() {
var entities = [T]()
let c = C()
if let item = c.item as? T { entities.append(item) }
}
}
let service = ServiceB<B>()
service.doSomething() // Creates an array of B and append a single B instance on it
let serviceD = ServiceB<D>()
serviceD.doSomething() // Creates an array of D, c.item of type B can't be cast to D, the array will be empty
While my answer doesn't really solves your problem, I think it should put you one step closer to a solution.