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.
Related
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
}
}
Suppose we have:
class BaseClass {
var id: String
}
class Child1: BaseClass {}
class Child2: BaseClass {}
struct Structure<T : BaseClass> {
var map = [String: T]()
}
Is it possible for an extension to return the specific type?
extension BaseClass {
static func <- <T : BaseClass>(left: T, right: T) -> Structure<T> where T == Self {
return Structure(map: [left.id, right])
}
}
The compiler doesn't like T == Self, or the left/right operator being T, but you can see what I'm trying to do. I'm trying to return the specific type of BaseClass so that I only have to implement these operators once.
So then you could use it like this:
var child1 = Child1()
var child11 = Child1()
// the structure returned matches the type of the operator inputs
var structure: Structure<Child1> = child1 + child11
If I try to put T in the operator left, right params, the compiler doesn't like that either.
This also doesn't work (for obvious reasons), but if there a way I could rewrite it to make it work?
extension BaseClass {
func combine<T : BaseClass>(with: T) -> Structure<T> {
// this doesn't work because 'self' can be assumed to be T
return Structure<T>(map: [self.id : with])
}
}
You can define the operator. You just can't put it inside of a type.
func + <T>(left: T, right: T) -> Structure<T> {
.init(map: [left.id: right])
}
var structure = Child1() + Child1()
If you want it to be a method, you'll need a protocol.
protocol BaseClassProtocol: BaseClass { }
extension BaseClassProtocol {
func combine(with instance: Self) -> Structure<Self> {
.init(map: [id: instance])
}
}
extension BaseClass: BaseClassProtocol { }
…but if you're going to have a protocol, you can throw the operator in there too if you want.
extension BaseClassProtocol {
static func + (left: Self, right: Self) -> Structure<Self> {
.init(map: [left.id: right])
}
func combine(with instance: Self) -> Structure<Self> {
self + instance
}
}
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)
I have this class and protocol in a framework:
public protocol P {}
open class C {
public init(_ p: P.Type) {
//super.init() etc
}
}
And in the project using this framework:
enum E: P {
// cases...
}
The thing that bugs me is that for every class that inherits C, I need to define the same init() like this:
final class C1: C {
init() {
super.init(E.self)
}
}
final class C2: C {
init() {
super.init(E.self)
}
}
// etc...
Is there a way for me to declare this default init in my project, like using an extension this way:
extension C {
// Declare the init(E.self) here somehow?
}
This way, I would simply call C1(), C2() etc without defining it in the subclass.
Thanks for your help.
You could create a protocol that contains the init, extend the protocol and provide a default implementation, and assign the protocol to C.
public protocol P {}
enum E: P {
}
protocol A {
init(_ p: P.Type)
}
extension A {
init(_ p: P.Type) {
// Add a default implementation
self.init(E.self)
}
}
class C: A {
// If you want to override, note you need to add `required`
required init(_ p: P.Type) {
}
}
class C1: C {
// No need to init here
}
Or if you don't want another protocol, you will need a new class that implements the init and subclass C and have your C1 and C2 inherit this new class.
Its what is usually done when people create BaseUIViewController and make their UIViewControllers subclasses of this:
public protocol P {}
enum E: P {
}
class C {
init(_ p: P.Type) {
}
}
class CBase: C {
// Override and provide default implementation
override init(_ p: P.Type) {
super.init(E.self)
}
}
class C1: CBase {
// No need to init here
}
class C2: CBase {
// No need to init here
}
Declare a convenience initialiser
extension C
{
public convenience init()
{
self.init(E.self)
}
}
let c1 = C1()
let c2 = C2()
Or you can put the convenience initialiser in the main definition of C.
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")
}
}
}