class A {
func test(string: String, another defaultValue: String = "") {
///...
}
}
class B {
func test(string: String, different defaultValue: Bool = true) {
///...
}
}
protocol Test {
func test(string: String)
}
extension A: Test {
func test(string: String) {
self.test(string: string)
}
}
extension B: Test {
func test(string: String) {
self.test(string: string)
}
}
When I do this I get the following error
Function call causes an infinite recursion
How to confirm to the protocol Test to the classes which have similar function names
When A or B conform to Test, there is no way for the program to know which .test you're calling, cause the internal .test methods in A & B have default values.
To resolve the ambiguity, you can be specific:
extension A: Test {
func test(string: String) {
self.test(string: string, another: "")
}
}
extension B: Test {
func test(string: String) {
self.test(string: string, different: true)
}
}
You have to call class methods with full signature:
extension A: Test {
func test(string: String) {
self.test(string: string, another: "")
}
}
extension B: Test {
func test(string: String) {
self.test(string: string, different: true)
}
}
As swift allows method overloading, you may use the same function name with different signatures.
In your example class methods have different signatures, comparing to the protocol methods, so it is fine. However class methods have default values and can be called without full signature and in this case it is ambiguous as the signature become the same.
Related
I have a protocol with the default implementation in the extension of that protocol. When I try to create a concrete mock object of that protocol to unit test, the default implementation always gets executed. I am not able to figure why. Any help would be appreciated. I am on xcode 11.3
protocol ABC: AnyObject {
func doSomething()
}
extension ABC {
func doSomething() {
print("Did Something")
}
}
final class ClassToBeTested {
var abc: ABC?
func methodToBeTested() {
abc?.doSomething()
}
}
In Test Target
final class MockABC: ABC {
func doSomething() {
print("Did Something in Test Target")
}
}
final class Tests: XCTestCase {
func testMethod() {
let obj = ClassTobeTested()
// abc property is of type protocol ABC
obj.abc = MockABC()
*This line calls the default implementation of the protocol of ABC and not the
implementation in MockABC class - verifiable by breakpoints and print statements*
obj.methodToBeTested()
}
}
I have read the static dispatch which happens in such cases, but could not find any particular reason to this. Kindly help.
You need to inject the protocol.
protocol ABC: AnyObject {
func doSomething() -> String
}
extension ABC {
func doSomething() -> String {
return "Did Something"
}
}
final class ClassToBeTested {
private let abc: ABC
init(abc: ABC) {
self.abc = abc
}
func methodToBeTested() -> String {
return abc.doSomething()
}
}
Testing Target
final class ABCMock: ABC {
func doSomething() {
print("Did Something in Test Target")
}
}
final class ClassToBeTestedTests: XCTestCase {
private let mockABC: MockABC = .init()
func test_methodToBeTested() {
let obj = ClassTobeTested()
XCTAssertEqual(obj.methodToBeTested(), "Did Something in Test Target")
}
}
This snippet of code it's very simple, but according to your question this is the best way.
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.
I'm sure that is a simple question for you.
How can I write a func with two parameters with one GKState?
UPDATE
Apple use
func willExitWithNextState(_ nextState: GKState)
If I use somefunc(state:GKState) works fine
while somefunc(state:GKState, string:String) does't work, why???
Other example
I've tried this:
class Pippo:GKState {}
//1
func printState (state: GKState?) {
print(state)
}
printState(Pippo) //Error cannot convert value of type '(Pippo).Type' (aka 'Pippo.Type') to expected argument type 'GKState?'
//2
func printStateAny (state: AnyClass?) {
print(state)
}
printStateAny(Pippo) //NO Error
//3
func printStateGeneral <T>(state: T?) {
print(state)
}
printStateGeneral(Pippo) //No Error
//4
func printStateAnyAndString (state: AnyClass?, string:String) {
print(state)
print(string)
}
printStateAnyAndString(Pippo/*ExpectedName Or costructor*/, string: "Hello") //ERROR
printStateAnyAndString(Pippo()/*ExpectedName Or costructor*/, string: "Hello") //ERROR cannot convert value of type 'Pippo' to expected argument type 'AnyClass?'
SOLUTION THANKS #0x141E
func printStateAnyAndString (state: GKState.Type, string:String) {
switch state {
case is Pippo.Type:
print("pippo")
default:
print(string)
}
}
printStateAnyAndString(Pippo.self, string: "Not Pippo")
Thanks for reply
If you want a parameter to be a class, use Class.Type or AnyClass
func printState (state: AnyClass, string:String) {
print(state)
print(string)
}
and use Class.self as the argument
printState(Pippo.self, string:"hello pippo")
Update
If your function definition is
func printState (state:GKState, string:String) {
if state.isValidNextState(state.dynamicType) {
print("\(state.dynamicType) is valid")
}
print(state)
print(string)
}
you'll need to pass in an instance of GKState (or a subclass of GKState) as the first argument, not the class/subclass itself. For example,
let pippo = Pippo()
printState (pippo, "Hello")
Throughout your sample code you have used AnyClass, whereas you should (probably) be using AnyObject. AnyClass refers to a class definition, whereas AnyObject is an instance of a class.
class MyClass { }
func myFunc1(class: AnyClass)
func myFunc2(object: AnyObject)
let myObject = MyClass() // create instance of class
myFunc1(MyClass) // myFunc1 is called with a class
myFunc2(myObject) // myFunc2 is called with an instance
You have also made most of your parameters Optionals with the "?", whereas it doesn't look required. For example:
printState(nil) // What should this do?
Is it possible to return a type of generic that conforms to protocol for later use with class functions using Swift 1.2? Take a look:
protocol SomeProtocol
{
static func start(kind: Kind)
}
class A: SomeProtocol
{
class func start(kind: Kind)
{
print("A started")
}
}
class B: SomeProtocol
{
class func start(kind: Kind)
{
print("B started")
}
}
enum Kind {
case Akind
case Bkind
private func classKind<T: SomeProtocol>() -> T.Type
{
switch self {
case .Akind: return A.self
case .Bkind: return B.self
}
}
func doSomething() {
self.classKind().start(self)
}
}
I tried various methods but every of them ended with some errors. Currently I got 'A' is not a subtype of 'T' in classKind method (same for 'B') and cannot invoke 'start' with an argument list of type '(Kind)' in doSomething.
I'm sure I'm pretty close but can't solve it...
If you're using Swift 2, to achieve what you want you only need to change:
private func classKind<T: SomeProtocol>() -> T.Type { ... }
to
private func classKind() -> SomeProtocol.Type { ... }
Now back to the not-working code to see where the errors were coming from. You don't need to make the changes I'm now detailing, this is just to explain the errors.
First examine your doSomething method:
func doSomething() {
self.classKind().start(self)
// Error: Argument for generic parameter 'T' could not be inferred.
//
// (I'm using Xcode 7 b6, which may explain the differing error messages)
}
For the type returned by classKind to be inferred, you'd have to do:
let type: A.Type = self.classKind() // Or you could use `B.Type`.
type.start(self)
Which obviously defeats the point of your goal, since you have to specify the type you want.
Secondly, the errors in classKind:
private func classKind<T: SomeProtocol>() -> T.Type
{
switch self {
case .Akind: return A.self
// Cannot convert return expression of type 'A.Type' to return type 'T.Type'.
case .Bkind: return B.self
// Cannot convert return expression of type 'B.Type' to return type 'T.Type'.
}
}
To see why this doesn't work consider the following example, in which I have another type that conforms to SomeProtocol:
struct C: SomeProtocol { ... }
Then in doSomething:
func doSomething() {
let type: C.Type = self.classKind()
type.start(self)
}
The errors you're getting can now be read as: Cannot convert return expression of type 'A.Type'/'B.Type' to return type 'C.Type'.
I have an extension on UIView implementing a protocol
protocol SomeProtocol {
var property : Int
}
extension UIView : SomeProtocol {
var property : Int {
get {
return 0
}
set {
// do nothing
}
}
}
in a concrete subclass I want to override this extension method:
class Subclass : UIView, SomeProtocol {
var _property : Int = 1
var property : Int {
get { return _property}
set(val) {_property = val}
}
}
I set breakpoints and see that the extension method is called and not the concrete subclass method:
var subclassObject = Subclass()
someObject.doSomethingWithConcreteSubclassObject(subclassObject)
// other code;
fun doSomethingWithConcreteSuclassObject(object : UIView) {
var value = object.property // always goes to extension class get/set
}
As others have noted, Swift does not (yet) allow you to override a method declared in a class extension. However, I'm not sure whether you'll ever get the behavior you want even if/when Swift someday allows you to override these methods.
Consider how Swift deals with protocols and protocol extensions. Given a protocol to print some metasyntactic variable names:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
An extension to provide default implementations:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
And a class that conforms to the protocol:
class FooBar : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
}
Swift will use dynamic dispatch to call the appropriate implementations of foo() and bar() based on each variable's runtime type rather than on the type inferred by the compiler:
let a = FooBar()
a.foo() // Prints "FOO"
a.bar() // Prints "BAR"
let b: Metasyntactic = FooBar()
b.foo() // Prints "FOO"
b.bar() // Prints "BAR"
If, however, we extend the protocol further to add a new method:
extension Metasyntactic {
func baz() -> String {
return "baz"
}
}
And if we override our new method in a class that conforms to the protocol:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift will now use static dispatch to call the appropriate implementation of baz() based on the type inferred by the compiler:
let a = FooBarBaz()
a.baz() // Prints "BAZ"
let b: Metasyntactic = FooBarBaz()
b.baz() // Prints "baz"
Alexandros Salazar has a fantastic blog post explaining this behavior in depth, but suffice it to say that Swift only uses dynamic dispatch for methods declared in the original protocol, not for methods declared in protocol extensions. I imagine the same would be true of class extensions, as well.
I know this question has been asked a while ago. But this will be handy for someone who looking for an easier way. There is a way of overriding an extension methods. I know its bit hacky but it does the job beautifully.
If you declare your protocol with #objc
#objc protocol MethodOverridable {
func overrideMe()
}
In Extension
extension MainClass: MethodOverridable {
func overrideMe() {
print("Something useful")
}
}
Subclass - You can able to override it in your subclass. It works like a magic. Well, not really when adding #objc it exposes your protocol to Objective-C and its Runtime. That allows your subclass to override.
class SubClass: MainClass {
override func overrideMe() {
print("Something more useful")
}
}
Swift 5
class Class
{
#objc dynamic func make() { print("make from class") }
}
class SubClass: Class {}
extension SubClass {
override func make() {
print("override")
}
}
It looks like you can override property for 2nd super class property. For example, you can access UIView property by making extension to the UILabel wanting to override frame property of UIView. This sample works for me in Xcode 6.3.2
extension UILabel {
override public var frame: CGRect {
didSet {
println("\(frame)")
}
}
}
You can't do this through normal means.
It's in Apple's docs that you can't override a method in an extension in a subclass.
Also, extensions can add new functionality to a type, but they cannot override existing functionality.
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
I think you forgot to override the superclass property in your subclass:
class Subclass : UIView {
var _property : Int = 1
override var property : Int {
get { return _property}
set(val) {_property = val}
}
}