Extension doesn't go in derived class in swift [duplicate] - ios

This question already has answers here:
Swift 2 protocol extension not calling overridden method correctly
(3 answers)
Closed 7 years ago.
I am implementing a protocol and providing some optional methods in swift but then I am implement these optional methods in derived class. When I call a protocol method it is calling extension method not the derived class method.
protocol ProtocolA {
func method1()
// Optional
func method2()
}
extension ProtocolA {
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Protocol A")
}
}
class A : ProtocolA {
func method1() {
print("In method 1 - class A")
}
}
class B : A {
func method2() {
print("In method 2 - Class B")
}
}
var a : A = B()
// It should call - In method 2 - Class B but the output is "In method 2 - Protocol A"
a.method2()

First you should implement the method on Class A for on class B you can override the method for example:
protocol ProtocolA {
func method1()
// Optional
func method2()
}
extension ProtocolA {
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Protocol A")
}
}
class A : ProtocolA {
func method1() {
print("In method 1 - Class A")
}
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Class A")
}
}
class B : A {
override func method2() {
print("In method 2 - Class B")
}
}
var a : A = B()
a.method2()
or use the class B as a Type directly:
protocol ProtocolA {
func method1()
// Optional
func method2()
}
extension ProtocolA {
func method2(){
// It comes here, instead of class B method2.
print("In method 2 - Protocol A")
}
}
class A : ProtocolA {
func method1() {
print("In method 1 - Class A")
}
// func method2(){
// // It comes here, instead of class B method2.
// print("In method 2 - Class A")
// }
}
class B : A {
func method2() {
print("In method 2 - Class B")
}
}
var b : B = B()
b.method2()
The problem is the runtime choose the function that was implemented based on the Type of variable.

Related

Call a method with dynamic class name in swift

How can we call class functions with a dynamic class name?
Assume the following example where I have two class with methods with same signature
class Foo{
class func doSomething()
}
class Foobar {
class func doSomething()
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: dynamicClass)
x.doSomething()
}
How can this be implemented so that x accepts values at run time
Edit: Sorry, I missed to mention that I was looking for any other ways other than protocol oriented approach. This is more of an exploratory question to explore if there is a more direct approach/pods/libraries to achieve this.
I liked this question, because it made me to think a lit'bit outside of the box.
I'll answer it, by dividing it into a few parts.
First
call class functions
Class function is basically a Type methods, which can be achieved using the static word inside the class context.
Taking that into account, you can get a simple solution, using protocol and passing the class reference (conforming to that protocol) like this:
protocol Aaa{
static func doSomething();
}
class Foo : Aaa{
static func doSomething() {
print("Foo doing something");
}
}
class FooBar : Aaa{
static func doSomething() {
print("FooBar doing something");
}
}
class ActualWork{
//Using class (static) method
func callDynamicClassMethod <T: Aaa> (x: T.Type) {
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicClassMethod(x: Foo.self);
aw.callDynamicClassMethod(x: Foo.self);
}
Second
In case you don't really need the method on the class context, you may consider using instance methods. In that case the solution would be even simpler, like this:
protocol Bbb{
func doSomething();
}
class Bar : Bbb{
func doSomething() {
print("Bar instance doing something");
}
}
class BarBar : Bbb{
func doSomething() {
print("BarBar instance doing something");
}
}
class ActualWork{
//Using instance (non-static) method
func callDynamicInstanceMethod <T: Bbb> (x: T){
x.doSomething();
}
}
//This is how you can use it
func usage(){
let aw = ActualWork();
aw.callDynamicInstanceMethod(x: Bar());
aw.callDynamicInstanceMethod(x: BarBar());
}
Third
If you need to use the class func syntax, as OP originally did:
class func doSomething()
You CANNOT simply use a protocol. Because protocol is not a class...
So compiler won't allow it.
But it's still possible, you can achieve that by using
Selector with NSObject.perform method
like this:
class ActualWork : NSObject{
func callDynamicClassMethod<T: NSObject>(x: T.Type, methodName: String){
x.perform(Selector(methodName));
}
}
class Ccc : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
}
class Ddd : NSObject{
#objc class func doSomething(){
print("Ccc class Doing something ");
}
#objc class func doOther(){
print("Ccc class Doing something ");
}
}
//This is how you can use it
func usage() {
let aw = ActualWork();
aw.callDynamicClassMethod(x: Ccc.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doSomething");
aw.callDynamicClassMethod(x: Ddd.self, methodName: "doOther");
}
Generics and Protocol oriented programming will do the job:
protocol Doable {
static func doSomething()
}
class Foo: Doable {
static func doSomething() {
debugPrint("Foo")
}
}
class Foobar: Doable {
static func doSomething() {
debugPrint("Foobar")
}
}
class ActualWork {
func callDynamicClassMethod<T: Doable>(x: T.Type) {
x.doSomething()
}
}
let work = ActualWork()
work.callDynamicClassMethod(x: Foo.self)
work.callDynamicClassMethod(x: Foobar.self)
you can achieve this with help of Protocol
protocol common {
static func doSomething()
}
class Foo : common{
static func doSomething() {
print("Foo")
}
}
class Foobar : common {
static func doSomething() {
print("Foobar")
}
}
class ActualWork{
//call following method with a variable type so that it accepts dynamic class name
func callDynamicClassMethod(x: common.Type) {
x.doSomething()
}
}
let fooObj : common = Foo()
let Foobarobj : common = Foobar()
let workObk = ActualWork()
workObk.callDynamicClassMethod(x:Foo.self)
workObk.callDynamicClassMethod(x:Foobar.self)
I think, there are three solutions. I shared an sample below.
Use "protocol" that has "doSomething()" function requirements.
Create a function which gets function definition as a parameter.
Use reflection. you can use EVReflection that is good Api for reflection.
sample code:
protocol FooProtocol {
static func doSomething()
}
class Foo: FooProtocol {
class func doSomething() {
print("Foo:doSomething")
}
}
class Foobar: FooProtocol {
class func doSomething() {
print("Foobar:doSomething")
}
}
class ActualWork {
func callDynamicClassMethod<T: FooProtocol>(x: T.Type) {
x.doSomething()
}
func callDynamicClassMethod(x: #autoclosure () -> Void) {
x()
}
func callDynamicClassMethod(x: () -> Void) {
x()
}
}
ActualWork().callDynamicClassMethod(x: Foo.self)
ActualWork().callDynamicClassMethod(x: Foobar.self)
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething())
ActualWork().callDynamicClassMethod(x: Foobar.doSomething())
print("\n")
ActualWork().callDynamicClassMethod(x: Foo.doSomething)
ActualWork().callDynamicClassMethod(x: Foobar.doSomething)
Looks like you are searching for duck typing, and this is harder to achieve in a statically typed language (with some exceptions, listed in the linked Wikipedia page).
This is because dynamically calling a method requires knowledge about the layout of the target object, thus either inheritance of the class declaring the method, or conformance to a protocol that requires that method.
Starting with Swift 4.2, and the introduction of dynamic member lookup, there is another approach to solve your problem, however it also involves some ceremony:
// This needs to be used as base of all classes that you want to pass
// as arguments
#dynamicMemberLookup
class BaseDynamicClass {
subscript(dynamicMember member: String) -> () -> Void {
return { /* empty closure do nothing */ }
}
}
// subclasses can choose to respond to member queries any way they like
class Foo: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Foo")
}
}
class Bar: BaseDynamicClass {
override subscript(dynamicMember member: String) -> () -> Void {
if member == "doSomething" { return doSomething }
return super[dynamicMember: member]
}
func doSomething() {
print("Dynamic from Bar")
}
}
func test(receiver: BaseDynamicClass) {
receiver.doSomething()
}
test(receiver: Bar()) // Dynamic from Bar
To conclude, in the current Swift version there is no way to have both the argument and the method dynamic, some common ground needs to be set.

Protocol Extensions and subclasses

I am wondering why the following doesn't print out what I think it should.
/* Fails */
protocol TheProtocol {
func update()
}
class A: TheProtocol {
}
class B : A {}
extension TheProtocol {
func update() {
print("Called update from TheProtocol")
}
}
extension TheProtocol where Self: B {
func update() {
print("Called update from B")
}
}
let instanceB = B()
instanceB.update()
let instanceBViaProtocol:TheProtocol = B()
instanceBViaProtocol.update()
This will print the following:
Called update from B
Called update from TheProtocol // Why not: Called update from B (extension)
I am especially wondering why
instanceBViaProtocol.update()
Doesn't execute the update() in the extension on TheProtocol:
extension TheProtocol where Self: B {
func update() {
print("Called update from B")
}
}
I would think it would since B inherits from A which adopts TheProtocol, so I would think that B would then implicitly adopt TheProtocol as well.
Moving the protocol adoption to B from A yields the expected result.
protocol TheProtocol {
func update()
}
class A { // Remove TheProtocol
}
class B : A, TheProtocol {} // Add TheProtocol
extension TheProtocol {
func update() {
print("Called update from TheProtocol")
}
}
extension TheProtocol where Self: B {
func update() {
print("Called update from B")
}
}
let instanceB = B()
instanceB.update()
let instanceBViaProtocol:TheProtocol = B()
instanceBViaProtocol.update()
Result:
Called update from B
Called update from B
I took a look at https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94#.6cm4oqaq1 and http://krakendev.io/blog/subclassing-can-suck-and-heres-why, but I was unable to figure this out. Are extension methods not honored on subclasses of entities that adopt the protocol?
The answer is Method Dispatch + a Bug in Swift.
Method dispatch is the mechanism used by the compiler to choose an implementation to execute when a method is invoked. Swift uses 3 kinds of method dispatch. You can read about it here
The dispatch method, is determined by the type of the reference, not by the type of the instance. In your case the reference type is TheProtocol.
let instanceBViaProtocol:TheProtocol = B()
instanceBViaProtocol.update()
You have a protocol extension that defines common behavior for a requirement method. In that case, dynamic dispatch is used. That means that the implementation declared in B should be used. But there is a bug in Swift that causes the issue.
For each type Swift uses a witness table to register the implementations used for dynamic dispatch. The bug causes the B class to fail to register its implementation of update() in the Witness table of TheProtocol. And when update is dispatched through the TheProtocol table, the wrong implementation is used.
Here you have your example with some changes. Notice that if you declare update in the superclass and override it in the subclass, it works as expected. That's the clearest way to see the bug to mee.
protocol TheProtocol {
func update()
}
class A: TheProtocol {
func update(){
print("Implementation of A")
}
}
class B : A {
override func update(){
print("Implementation of B")
}
}
//All those who conform to TheProtocol will execute this.
extension TheProtocol {
func update() {
print("Common: TheProtocol")
}
}
extension TheProtocol where Self: B {
func update() {
print("Common: TheProtocol for B's")
}
}
extension TheProtocol where Self: A {
func update() {
print("Common: TheProtocol for A's")
}
}
let instanceBViaProtocol:TheProtocol = B() //It prints "Implementation of B"
instanceBViaProtocol.update()
I hope this answers you question.
https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/ has an awesome explanation on method dispatch in swift.
Here you can read a short thing I wrote about method dispatch in protocol extensions.

Duplicate codes in Controller

I am currently working on one project. It may potentially have duplicated codes in multiple controllers like below.
Controller A
class A: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
// about 50~70 lines of codes
#IBAction func scanButtonTapped {
// used self (as AVCaptureMetadataOutputObjectsDelegate)
// used view
// called presentViewController(...), which is a func in UIViewController
}
}
Controller B
class B: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
#IBAction func scanButtonTapped {
// will need same logic as in Controller A
}
}
My current solution is have another class C, and move the duplicated codes into it. However, if I do so, controller can cast to AVCaptureMetadataOutputObjectsDelegate, but not to UIViewController.
class C {
func btnTapped (view: UIView, controller: AnyClass) {
// logic is here
// controller can cast to AVCaptureMetadataOutputObjectsDelegate
// but controller cannot cast to UIViewController
}
}
so A and B will have
class A {
#IBAction func scanButtonTapped {
let c = C()
c.btnTapped(view, self)
}
}
My question is if it is possible to cast controller into UIViewController. OR is there another way to refactor the codes properly?
What about extend AVCaptureMetadataOutputObjectsDelegate protocol and create default implementation by protocol extension (POP approach)?
protocol ScanButtonClickable: AVCaptureMetadataOutputObjectsDelegate {
func btnTapped() // this line is optional
}
extension Clickable where Self: UIViewController {
func btnTapped() {
// logic is here
}
}
class A: UIViewController, ButtonClickable {
...
}
class B: UIViewController, ButtonClickable {
...
}
Try this:
//declare your default method to be used across classes
protocol MyProtocol {
func myFunc()
}
//provide the implementation of your default behavior here in myFunc()
extension MyProtocol {
func myFunc() {
print("Default behavior")
}
}
class A: MyProtocol {
}
class B: MyProtocol {
}
let a = A()
a.myFunc()
let b = B()
b.myFunc()
//prints
Default behavior
Default behavior

how to inject a delegate in swift using typhoon?

Using typhoon I'm trying to inject the type of "worker" in my view controller. my "Worker" requires a delegate so that when the work is done, it calls this method. I need to set my view controller to be the delegate of the worker class that was injected. in other words a circular dependency.
Updated question with source:
//my typhoon assembly class
import Typhoon
class Assembly : TyphoonAssembly {
public dynamic func viewController() -> AnyObject {
return TyphoonDefinition.withClass(ViewController.self) {
(definition) in
definition.injectProperty("worker", with: self.foo())
definition.scope = TyphoonScope.Singleton
}
}
public dynamic func foo() -> AnyObject {
return TyphoonDefinition.withClass(Foo.self) {
(definition) in
definition.injectProperty("delegate", with: self.viewController())
}
}
}
Foo is where the work done, it implements WorkHandler protocol and has a delegate of type SomeProtocol to call when work has finished:
import Foundation
#objc
protocol SomeProtocol: class {
optional func hasFinishedWork(value: Bool)
}
protocol WorkHandler : class {
func doSomething()
}
class Foo: WorkHandler{
//how will this get set?
var delegate:SomeProtocol?
func doSomething(){
print("doing the work")
delegate?.hasFinishedWork!(true)
}
}
And my ViewController conforms to SomeProtocol like so:
import UIKit
class ViewController: UIViewController, SomeProtocol{
var worker:WorkHandler?
override func viewDidLoad() {
super.viewDidLoad()
worker?.doSomething();
}
#objc func hasFinishedWork(value: Bool){
print("The work was all done")
}
}
above code gives the following error when it runs:
2016-02-29 20:25:43.250 TestApp[30604:5316415] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Subclass of NSProxy or NSObject is required.'
Is anyone able to help with this?
Turns out i had to make my protocol to inherit from NSObject:
#objc
protocol SomeProtocol: class {
optional func hasFinishedWork(value: Bool)
}
#objc
protocol WorkHandler : class {
func doSomething()
}
class Foo: NSObject, WorkHandler{
//how will this get set?
var delegate:SomeProtocol?
#objc func doSomething(){
print("doing the work")
delegate?.hasFinishedWork!(true)
}
}
Now it works as expected.

Why custom delegate in iOS is not called

I am trying to create a custom delegate using playground in swift. However the doSomething method is not being called through callback.
It seems that delegate?.doSomething() does not fire to the XYZ class doSomething method.
Thanks in advance!
import UIKit
#objc protocol RequestDelegate
{
func doSomething();
optional func requestPrinting(item : String,id : Int)
}
class ABC
{
var delegate : RequestDelegate?
func executerequest() {
delegate?.doSomething()
println("ok delegate method will be calling")
}
}
class XYZ : RequestDelegate
{
init()
{
var a = ABC()
a.delegate = self
}
func doSomething() {
println("this is the protocol method")
}
}
var a = ABC()
a.executerequest()
It seems that delegate?.doSomething() does not fire to the XYZ class
doSomething method.
That is correct. class ABC has an optional delegate property, but the value of
the property is nowhere set. So the delegate is nil
and therefore the optional chaining
delegate?.doSomething()
simply does nothing. Also you have defined a class XYZ but
not created any instances of that class.
If you set the delegate of a to an instance of XYZ then
it will work as expected:
var a = ABC()
a.delegate = XYZ()
a.executerequest()

Resources