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
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)
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")
}
}
}
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.
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.
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.