I have a protocol with a method. I have thought that methods can be replaced with closures by the same name, but it doesn't seem to work:
protocol Foo {
func bar() // Type: Void -> Void
}
class X: Foo {
func bar() { }
}
class Y: Foo { // Compiler: doesn't conform to protocol Foo
let bar: Void->Void = {}
}
Is there a way to make this work? I want to override the methods behavior for a Test Stub implementation. Currently, I'd have to do this, which I'd like to shorten:
class Z: Foo {
var barClosure: Void -> Void = {}
func bar() {
barClosure()
}
}
let baz = Z()
baz.barClosure = { /* ... */ }
baz.bar() // Calls the closure replacement
Thanks to #Dániel Nagy, I was able to figure out what options I have. The protocol should require a closure. This way, the client code won't change, as closure calls are identical to method calls.
make the property mutable so implementations can decide if they want to lock the value
require a getter only (for the same reason)
initialize the property as immutable (let) in production code
initialize the property as mutable (var) in test code to provide alternate implementations in test cases, like mock observers do
Here's a modified example which works well in a Playground by returning strings:
protocol Foo {
var bar: () -> String { get }
}
class X: Foo {
// cannot be overwritten
let bar: () -> String = { return "default x" }
}
class Y: Foo {
private let _bar: () -> String = { return "default y" }
// Can be overwritten but doesn't have any effect
var bar: () -> String {
get {
return _bar
}
set {
}
}
}
class Z: Foo {
// Can be overwidden
var bar: () -> String = {
return "default z"
}
}
let bax = X()
bax.bar() // => "default x"
// bax.bar = { /* ... */ } // Forbidden
let bay = Y()
bay.bar() // => "default y"
bay.bar = { return "YY" }
bay.bar() // => "default y"
let baz = Z()
baz.bar() // => "default z"
baz.bar = { return "ZZ" }
baz.bar() // => "ZZ"
You declared the protocol to have a function, bar(), but in class Y, you just have a constant instead of a function, this is the problem. But if you want to have something like in class Y, you should change the protocol to:
protocol Foo {
var bar: () -> () {get set}
}
And implement like that:
class Test: Foo {
private var _bar: (() -> ())?
var bar: () -> () {
get {
return {}
}
set {
self._bar = newValue
}
}
}
UPDATED
If you to shorten your class, you can use something like that:
protocol Foo {
var barClosure: Void -> Void {get set}
}
class Z: Foo {
var barClosure: Void -> Void = {
//do here something
}
}
let a = Z()
a.barClosure()
The func keyword does a little bit more magic behind the scenes that you can’t replicate with properties – especially in the case of classes, where functions can be overridden, so vtables need to be built etc.
That said, if you were going to replace methods using closure expressions, you’d need to do more than the code you gave. The equivalent of this:
struct A {
let x: Int
func f() {
println("In f(), x is \(a.x)")
}
}
would be more like this:
struct A {
let x: Int
// returns a function that takes A objects, and
// returns a function that captures them
static let f: (A)->()->() = { a in
{ ()->() in println("In f(), x is \(a.x)") }
}
// equivalent of the dot notation call of f
var f: ()->() {
return A.f(self)
}
}
This replicates how struct methods actually work, and allows you to do all the same things an f method does:
let a = A(x: 5)
// static version of f
let A_f = A.f
// that static version bound to a self:
let f = A_f(a)
f()
// the above is equivalent to:
a.f()
But this still isn’t enough for A to conform to a protocol that requires an f() method.
Related
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
}
}
I want to pass to setter as argument one of predefined functions (in enum maybe or static) or custom function in closure.
like UIColor to UIView.backgroundColor (i can set .black or UIColor(...)). How can I do it with my custom class?
class MyClass {
var fun: ((String)->Void)?
}
var obj = MyClass()
obj.fun = {print($0)} . // It works now
obj.fun = .predefinedFunc // It's how i want to be able do
What you seem to want to do is "implicit member access". Unfortunately, this is not possible on closure types like (String) -> Void, because it only works on enums, as well as types with static members. (String) -> Void doesn't and can't have any static members.
It seems like what you want is simply a bunch of predefined functions. This can be done with an enum:
enum Function {
case predefinedFunc1
case predefinedFunc2
case predefinedFunc3 // name these properly!
var closure: (String) -> Void {
switch self {
case .predefinedFunc1: return { print($0) }
case .predefinedFunc2: ...
case .predefinedFunc3: ...
}
}
}
And then you'll be able to do:
class MyClass {
var fun: Function?
}
var obj = MyClass()
obj.func = .predefinedFunc1
If you also want to include an option to use a custom function, add an extra case with an associated value:
enum Function {
...
case custom((String) -> Void)
var closure: (String) -> Void {
switch self {
case .predefinedFunc1: return { print($0) }
...
case .custom(let f): return f
}
}
}
view.backgroundColor = .black
works because black is a static property of struct UIColor. The right-hand side is called an “implicit member expression,” see for example What is the Swift syntax " .bar" called?.
Function types are neither classes nor structs, and you cannot define a static property for a function type. Therefore an identical syntax is not possible.
What you can do is to define a “wrapper” struct for the function, with static properties for the predefined functions. Here is a simple example:
struct Fun {
let f: (String) -> Void
init(_ f: #escaping (String) -> Void) {
self.f = f
}
// Predefined functions:
static var printer = Fun( { print($0) } )
// ...
}
class MyClass {
var fun: Fun?
}
And then you can do
let obj = MyClass()
obj.fun = Fun( { print($0) } ) // set to custom function
obj.fun = .printer // set to predefined function
This approach also allows to extend the wrapper type by more predefined functions:
extension Fun {
static var printReversed = Fun( { print($0.reversed()) } )
}
// ...
obj.fun = .printReversed
Please define the func same as you callback func or nameless fun, then you can pass it as an argument.
class MyClass {
var fun: ((String)->Void)?
}
//MARK:- you have to provide the same param and return type in your predefined func.
func printer(Str :String)->Void{
print(Str)
}
var obj = MyClass()
obj.fun = {print($0)}
obj.fun = printer
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")
}
}
}
Take this code:
protocol P: class {
static var hello: String { get }
}
class A: P {
class var hello: String {
return "Hello"
}
}
class B: A {
override static var hello: String {
return "Hello World"
}
}
class C: A {}
class D: C {
override static var hello: String {
return "Hello D"
}
}
func sayHello(elements: P.Type...) {
for p in elements {
print(p.hello)
}
}
func sayHelloAgain(elements: A.Type...) {
for p in elements {
print(p.hello)
}
}
func sayHelloThe3rd(elements: [A.Type]) {
for p in elements {
print(p.hello)
}
}
sayHello(A.self, B.self, C.self)
sayHelloAgain(A.self, B.self, C.self)
Compare it to this (taken from this presentation)
func register<T: UITableViewCell where T: ReusableView, T: NibLoadableView>(_: T.Type) { ... }
tableView.register(FoodTableViewCell)
Why do I have to use A.self in one case, but not in the other?
And also, don't need to use .self when calling with one argument.
sayHello(A)
sayHello(A, B) //doesn't compile
The .self is syntactic salt. It's not necessary from a technical perspective, but it exists to cause errors in code that's often a result of a typo, such as:
struct Foo { }
let foo = Foo
This code will give you a compiler error, telling you that either you need to complete the initializer/function/method call, or append .self if you meant to refer to the type.
In the latter example, the context deals exclusively with types and not values, so there's no chance of confusing one with the other, thus, .self isn't necessary.
Perhaps there's a way to modify the function declaration in your example so as to not require the .self, but I'm not aware of such a feature. I'd be interested to find out.
Say I have a generic class
class Foo<T> { … }
Can I somehow specify that instances of this class can be converted to T in assignments? Example:
let foo = Foo<Int>()
func useAnInt(a: Int) {}
let getTheInt: Int = foo
useAnInt(foo)
Why not just use the underlying type? (Similar to #MrBeardsley's answer)
class Foo<T> {
var t : T
init(t: T) {
self.t = t
}
}
let foo = Foo(t: 3)
func useAnInt(a: Int) {}
let getTheInt: Int = foo.t
useAnInt(foo.t)
You are not able to do what you are asking. Even though Foo defines a generic type T, instances of Foo are still Foo and cannot be converted to the generic type. The reason you would declare a generic type at the class level is to use it multiple places throughout the class.
class Foo<T> {
var value: T
init(withValue: T) {
self.value = withValue
}
func getSomeValue() -> T {
return self.value
}
}
Generics don't mean the class itself is generic and can be converted.
One way of achieving what you want is to use a dedicated protocol for each of the target types that your class shall be convertible to. Here is very basic example:
protocol BoolAdaptable {
func adaptToBool() -> Bool
}
protocol IntAdaptable {
func adaptToInt() -> Int
}
protocol FloatAdaptable {
func adaptToFloat() -> Float
}
class Foo: BoolAdaptable, IntAdaptable, FloatAdaptable {
var v: NSNumber
init(_ v: NSNumber) {
self.v = v
}
func adaptToBool() -> Bool {
return v.boolValue
}
func adaptToInt() -> Int {
return v.integerValue
}
func adaptToFloat() -> Float {
return v.floatValue
}
}
let foo = Foo(NSNumber(double: 1.23))
let getTheBool = foo.adaptToBool() // true
let getTheInt = foo.adaptToInt() // 1
let getTheFloat = foo.adaptToFloat() // 1.23
This could easily be extended to support more complex conversions.