How to do multi-inheritance in swift? - ios

I need to implement a class (for convenience name it A) derived from UITableViewController and another(B) from UICollectionViewController. And there are a lot of things common, so I want to put them in class(C) and let A and B inherit C. Now A and B both have two class to inherit, but multiple inheritance is not allowed in swift, so how to implement this? I know there is no multi-inheritance allowed in swift, but I still want to know how to do the things I described above.

As stated in the comments by #Paulw11 is correct. Here is an example that involves A & B inheriting from C. Which I have named DogViewController and CatViewController (which inherits form PetViewController). You can see how a protocol might be useful. This is just an ultra basic example.
protocol Motion {
func move()
}
extension Motion where Self: PetViewController {
func move() {
//Open mouth
}
}
class PetViewController: UIViewController, Motion{
var isLoud: Bool?
func speak(){
//Open Mouth
}
}
class DogViewController:PetViewController {
func bark() {
self.speak()
//Make Bark Sound
}
}
class CatViewController: PetViewController {
func meow() {
self.speak()
//Make Meow Sound
}
}
//....
let cat = CatViewController()
cat.move()
cat.isLoud = false
cat.meow()

You can't have multiple inheritance in Swift, the way to go is to look at Protocols, but it is a rather big topic to be discussed in an answer.
There are also many other questions with the same scope

Multiple inheritance is not allowed in Swift. You can conform any protocol instead. Protocols are like interfaces in Java.

Related

Factory pattern with different protocols in swift

I am trying to use factory pattern in swift, and give is my code
I have two protocols
protocol MyProtocol1{
func callLoginAPI()
}
protocol MyProtocol2{
func callPaymentAPI()
}
I have two structures which conform to these protocols
struct MyManager1: MyProtocol1{
func callLoginAPI()
{
debugPrint("Inisde--MyManager1 and ready to call an Login API")
}
}
struct MyManager2: MyProtocol2{
func callPaymentAPI()
{
debugPrint("Inisde--MyManager2 and ready to call Payment API")
}
}
I want to use the factory pattern to create the instance of Manager by passing the Protocol and returning a concrete object of the struct that conforms to that protocol
Example: ManagerFactory.create(MyProtocol1) --> should give me instance of MyManager1 and doing ManagerFactory.create(MyProtocol2) --> should give me instance of MyManager2
I assume that this may not work as I am asking for a concrete type at runtime, so I ended up doing something like this
protocol IManagerFactory{
func getMyManager1() -> MyProtocol1
func getMyManager2() -> MyProtocol2
}
struct ManagerFactory: IManagerFactory
{
func getMyManager1() -> MyProtocol1 {
return MyManager1()
}
func getMyManager2() -> MyProtocol2 {
return MyManager2()
}
}
But I am curious if what I am trying to do in the example is achievable, I am using swift 4.2.
I have seen other examples but all of them have the same protocol which they conform to like rectangle, square and circle conform to same protocol shape.
In my case, I have two separate protocols which do completely different things so is that even possible what I am trying to do in the example? OR the way I ended up with is the only way to go about it.
Please suggest what is the best possible approach.
First, I'm very suspicious of a "manager" that is a value (a struct) rather than an instance (a class). Do you really mean to be using structs and protocols here at all? Structs have no identity; two structs with the same properties must be completely interchangeable for each other, and things like that don't usually get named "manager."
What you're describing is certainly writeable. It's just kind of useless. Here's how you write it:
struct ManagerFactory {
static func create(_ type: MyProtocol1.Protocol) -> MyProtocol1 {
return MyManager1()
}
static func create(_ type: MyProtocol2.Protocol) -> MyProtocol2 {
return MyManager2()
}
}
let mgr1 = ManagerFactory.create(MyProtocol1.self)
let mgr2 = ManagerFactory.create(MyProtocol2.self)
But this is just an elaborate way to use method overloading to replace names.
What you seem to want is a single method, but what would its return type be? Even in C#, I don't think this is writable without adding nasty downcasts. (This is the point you and paulw11 discuss in the comments.) This isn't a limitation of Swift; it's a fundamental characteristic of types. Even in JavaScript, you'd need to know what you expect to get back or else you won't know what methods you can call on it (it's just you track that expectation in your head and docs rather than in the compiler and code).
You seem to have created a lot of protocols here, and I'm betting they mostly have exactly one implementation. That's bad Swift. Don't create protocols until you have a specific need for one. Don't create attractions for fun. They will burn you very quickly.
If your protocols really look like this, and you really have different implementations of these methods (i.e. don't do this if there is only one implementation of MyProtocol1 "just in case"), what you really want are functions:
struct API {
let login: () -> Void
let payment: () -> Void
}
let myAPI = API(login: myLoginFunction, payment: myPaymentFunction)
This will let you create different APIs if you need them. But again, only if you need this flexibility. If not, just use classes for instances, and structs for values, and avoid protocols until you have at least 2, and better 3, implementations in your program.
Suggest a swifty option:
protocol Manager {
// a generic protocol for all managers
}
protocol BadManager: Manager {
// properties and behaviour of BadManager
mutating func noBonus()
}
protocol GoodManager: Manager {
// properties and behaviour of GoodManager
mutating func bigBonus()
}
protocol ManagerFactory {
associatedtype Manager
mutating func createManager() -> Manager
}
struct gm: GoodManager {
mutating func bigBonus() {
print("tons of cookies & coffee")
}
}
struct bm: BadManager {
mutating func noBonus() {
print("all fired")
}
}
enum ManagerCreator<Manager>: ManagerFactory {
func createManager() -> Manager {
switch self {
case .goodManager:
return gm() as! Manager
case .badManager:
return bm() as! Manager
}
}
case goodManager
case badManager
}

Swift Advanced - Setting extensions during run time

Is there a way to set extensions during run time in Swift?
I got a protocol named "CuteProtocol" and an extension to that protocol named "CuteExtension". When I want to add this extension to classes I just do as follows:
class CuteClass: UIViewController, CuteProtocol {
}
However I have many of these classes which should implement this protocol and I don't want to add them one by one, I don't want to make a base class either.
Is there a way to set extensions-protocols during run time as follows:
let cuteClass = CuteClass()
cuteClass. // ADD EXTENSION-PROTOCOL SOMEHOW HERE.
No, but you can extension for example UIViewController, or other base class
extension UIViewController: CuteProtocol {
// your code conforming to Cute Protocol goes here.
}
you can play with runtime modifiers in ObjC freely, but in Swift such kinda pattern is not really common.
NOTE: you can find more information about this in the ObjC Runtime Library, if you are interested.
You can not set extensions in runtime, BUT you don't have to set them in class definition either. you can extend classes like:
extension CuteClass: CuteProtocol {
// your code conforming to Cute Protocol goes here.
}
Update 1
Or if you want to have default implementations to CuteProtocol, you can extend CuteProtocol itself too:
protocol CuteProtocol {
func f1()
}
extension CuteProtocol {
func f1() {
// default implementation
}
}
This way each class can change f1 implementation if want to or use the default implementation.
You can even add conditional extensions like:
extension CuteProtocol where Self: CuteClass {
func f1() { }
func f2() { }
}
so if you write extension CuteClass: CuteProtocol {} all CuteClass instances and subclasses will have access to method f1 and f2.
But be-aware that functions added in extensions support dynamic-dispatch IFF they're defined in protocol.
In the sample I provided, f1 will be called with dynamic-dispatch but f2 will be called with static-dispatch. i.e: if CuteChildClass: CuteClass changes f2 implementation and you call f2 from a CuteProtocol variable, the code you provided in the extension will be called.

Using protocol as a concrete type conforming to 'AnyObject' is not supported

I'm trying to implement a simple multi-delegate situation:
protocol Subscribable: class {
associatedtype Subscriber: AnyObject
var subscribers: NSHashTable<Subscriber> { get }
}
protocol ControllerSubscriber: class {
func controllerDidSomething()
}
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = NSHashTable<Subscriber>.weakObjects() // Error
}
Error: Using 'ControllerSubscriber' as a concrete type conforming to protocol 'AnyObject' is not supported.
My question is:
What does this error mean exactly?
What are the underlying concepts the thing I'm trying to do fails for?
Why is this "not supported"?
And of course, how do I work around this? In the sense of an actual solution not a work around.
I have such a hard time understanding Swift's generics system. I seem to be running into seemingly simple situations like this constantly. I just want to put a thing conforming to a protocol into another thing :( . I would like to know where my thinking goes wrong so I can fix it and never have to see these errors again.
There is this related question but please note the answers give only workarounds, no explanations or solutions.
It is probably not fair to blame this problem on Swift. Reasoning about types seems to be some meta-art we will first have to get used to (unless you have been sitting on the C++ standards committee for the last 30 years that is :-).
Turns out your problem is related to your choice of NSHashTable as the data structure to hold your subscribers. The following would compile with minimal changes:
protocol Subscribable: class {
associatedtype Subscriber
var subscribers: [Subscriber?] { get }
}
protocol ControllerSubscriber: class {
func controllerDidSomething()
}
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = [Subscriber?]()
}
however, it lacks the weak semantics and is not really useful yet. The list of subscribers is exhibited as a property and has to be manipulated directly by the clients. Furthermore each implementation of Subscribable has to implement its own notification mechanism and there is hardly any logic that is centralised by this approach. Technically you can use it like this:
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = [Subscriber?]()
func notify() {
for case let subscriber? in subscribers {
subscriber.controllerDidSomething()
}
}
}
var controller = Controller()
class IWillSubscribe : ControllerSubscriber {
func controllerDidSomething() {
print("I got something")
}
}
controller.subscribers.append(IWillSubscribe())
controller.notify()
but that is neither very practical nor very readable. This would have been an acceptable solution (since it was the only one) up to Java 7, but even in Java 8 (and much more so in Swift) we would like to encapsulate the notification logic into the Subscribable protocol as a default implementation, but that would be another post.
Since you chose to implement subscribers as an NSHashTable (there is probably an ARC reason to desire weak references here) there seems to be some Objective-C trickery involved. After much experimentation (and finally finding the fourth answer to this question I got the following to work:
protocol Subscribable: class {
associatedtype Subscriber : AnyObject
var subscribers: NSHashTable<Subscriber> { get }
}
#objc protocol ControllerSubscriber: class {
func controllerDidSomething()
}
class Controller: Subscribable {
typealias Subscriber = ControllerSubscriber
var subscribers = NSHashTable<Subscriber>.weakObjects()
func notify() {
for subscriber in subscribers.allObjects {
subscriber.controllerDidSomething()
}
}
}
var controller = Controller()
class IWillSubscribe : ControllerSubscriber {
func controllerDidSomething() {
print("I got something")
}
}
let iDoSubscribe = IWillSubscribe()
controller.subscribers.add(iDoSubscribe)
controller.notify()
which is virtually identical to your original (with some proof around it). As it seems Objective-C #protocols are not quite the same as Swift protocols, but Swift can actually do either.
There is quite a lot of subtlety in this though, only allObjects works without type erasure, your trusty objectEnumerator only returns Any? and that is a stupid animal to get anything from. Also note that
let iDoSubscribe = IWillSubscribe()
is instrumental. At first I tried
controller.subscribers.add(IWillSubscribe())
which actually added something to the count of subscribers, but went away with any attempt to iterate (as one should expect from a weak reference that is not referred to anywhere else).
A very late answer that is already way too long, just to prove that this is still an issue, even with Swift 3. Maybe this will get better once this Jira ticket is resolved.

Get the class type that implements a protocol swift

So what I am trying to do is make it easy for me to implement many custom UITableViewCells on one tableView, to do this I wanted to create a protocol that would facilitate filling out the function:
- (void)registerClass:(nullable Class)cellClass forCellReuseIdentifier:(NSString *)identifier
my protocol so far looks like this:
protocol TableViewCellClassReportingProtocol: class {
func reuseID() -> String
}
extension TableViewCellClassReportingProtocol {
static func classObject() -> AnyClass? {
return self.class
}
}
however I am having issues with getting the class type even thought I specify that this protocol must be implemented by a class. Any suggestions, I may be approaching this the wrong way
So this was close to the right answar and let me both elaborate and give credit to Charles A.
dynamicType is part of the answar! great call!
the function implamintation also had to change, because of subclassing and static really meaning "class final"
Protocol for class method
the override points must be
override class func reuseID() -> String

Override var conforming to a protocol with a var conforming to a child of the overridden var protocol

This is my inheritance structure
Protocols
protocol BaseProtocol {
}
protocol ChildProtocol: BaseProtocol {
}
Classes
class BaseClass: NSObject {
var myVar: BaseProtocol!
}
class ChildClass: BaseClass {
override var myVar: ChildProtocol!
}
I'm receiving a compiler error:
Property 'myVar' with type 'ChildProtocol!' cannot override a property with type 'BaseProtocol!'
What is the best approach to achieve this?
UPDATE
I updated the question trying to implement the solution with generics but it does not work :( This is my code (now the real one, without examples)
Protocols
protocol TPLPileInteractorOutput {
}
protocol TPLAddInteractorOutput: TPLPileInteractorOutput {
func errorReceived(error: String)
}
Classes
class TPLPileInteractor<T: TPLPileInteractorOutput>: NSObject, TPLPileInteractorInput {
var output: T!
}
And my children
class TPLAddInteractor<T: TPLAddInteractorOutput>: TPLPileInteractor<TPLPileInteractorOutput>, TPLAddInteractorInput {
}
Well, inside my TPLAddInteractor I can't access self.output, it throws a compiler error, for example
'TPLPileInteractorOutput' does not have a member named 'errorReceived'
Besides that, when I create the instance of TPLAddInteractor
let addInteractor: TPLAddInteractor<TPLAddInteractorOutput> = TPLAddInteractor()
I receive this other error
Generic parameter 'T' cannot be bound to non-#objc protocol type 'TPLAddInteractorOutput'
Any thoughts?
#tskulbru is correct: it can't be done, and this has nothing to do with your protocols. Consider the example below, which also fails…this time with Cannot override with a stored property 'myVar':
class Foo {
}
class Goo: Foo {
}
class BaseClass: NSObject {
var myVar: Foo!
}
class ChildClass: BaseClass {
override var myVar: Foo!
}
To understand why, let's reexamine the docs:
Overriding Properties
You can override an inherited instance or class property to provide
your own custom getter and setter for that property, or to add
property observers to enable the overriding property to observe when
the underlying property value changes.
The implication is that if you are going to override a property, you must write your own getter/setter, or else you must add property observers. Simply replacing one variable type with another is not allowed.
Now for some rampant speculation: why is this the case? Well, consider on the one hand that Swift is intended to be optimized for speed. Having to do runtime type checks in order to determine whether your var is in fact a Foo or a Bar slows things down. Then consider that the language designers likely have a preference for composition over inheritance. If both of these are true, it's not surprising that you cannot override a property's type.
All that said, if you needed to get an equivalent behavior, #tskulbru's solution looks quite elegant, assuming you can get it to compile. :)
I don't think you can do that with protocols
The way i would solve the problem you are having is with the use of generics. This means that you essentially have the classes like this (Updated to a working example).
Protocols
protocol BaseProtocol {
func didSomething()
}
protocol ChildProtocol: BaseProtocol {
func didSomethingElse()
}
Classes
class BaseClass<T: BaseProtocol> {
var myProtocol: T?
func doCallBack() {
myProtocol?.didSomething()
}
}
class ChildClass<T: ChildProtocol> : BaseClass<T> {
override func doCallBack() {
super.doCallBack()
myProtocol?.didSomethingElse()
}
}
Implementation/Example use
class DoesSomethingClass : ChildProtocol {
func doSomething() {
var s = ChildClass<DoesSomethingClass>()
s.myProtocol = self
s.doCallBack()
}
func didSomething() {
println("doSomething()")
}
func didSomethingElse() {
println("doSomethingElse()")
}
}
let foo = DoesSomethingClass()
foo.doSomething()
Remember, you need a class which actually implements the protocol, and its THAT class you actually define as the generic type to the BaseClass/ChildClass. Since the code expects the type to be a type which conforms to the protocol.
There are two ways you can go with your code, depending what you want to achieve with your code (you didn't tell us).
The simple case: you just want to be able to assign an object that confirms to ChildProtocol to myVar.
Solution: don't override myVar. Just use it in ChildClass. You can do this by design of the language Swift. It is one of the basics of object oriented languages.
Second case: you not only want to enable assigning instances of ChildProtocol, you also want to disable to be able to assign instances of BaseProtocol.
If you want to do this, use the Generics solution, provided here in the answers section.
If you are unsure, the simple case is correct for you.
Gerd

Resources