I have a bunch of functions that I would like to be able to specify a default closure if one is not provided. I can't seem to figure out how to do it without some ugly code.
So for example, I would like the perform function to accept an optional parameter called closure that is executed when provided. Otherwise it will default to executing myClosure. How can I make this better so I don't have to repeat the function calls?
class MyClas {
typealias closureType = ((number: Int) -> Int)?
func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = nil) -> Int {
if closure == nil {
return myClosure(number)
} else {
return closure!(number: number)
}
}
}
Ideally, I could do this!
class MyClass {
typealias closureType = ((number: Int) -> Int)?
func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = myClosure) -> Int {
return closure(number: number)
}
}
Your problem is that you've made made myClosure a method (or member function), which means it doesn't have the signature you want (it's instead a curried function, of type MyClass->Int->Int).
Either pull it out of the class, or make it a static (or rather "class" in the case of a class) method:
class MyClass {
typealias closureType = (number: Int) -> Int
class func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = MyClass.myClosure) -> Int {
return closure(number: number)
}
}
P.S. once you do this, it doesn't need to be optional any more
Just to show it compiling as a non-static method:
class MyClass {
typealias closureType = MyClass -> (number: Int) -> Int
func myClosure (number: Int) -> Int {
return number * 2
}
func perform(number: Int, closure: closureType = myClosure) -> Int {
return closure(self)(number: number)
}
}
let c = MyClass()
println(c.perform(5)) // prints 10
Closure is first-class citizen in Swift. So you can provide default value for it.
class MyClass {
func perform(number: Int, closure: Int -> Int = { $0 * 2 }) -> Int {
return closure(number)
}
}
Related
I have this function, which return sum of numbers
func sum<T: Numeric>(_ a: T, _ b: T) -> T {
return a + b
}
And I need to improve this function so that also return the concatenation of Strings by this function without overloading. I probe use RangeReplaceableCollection, but i can't use this protocol with Numeric protocol.
For example:
sum(2, 3) -> 5
sum(1.5, 2.4) -> 3.9
sum("abc", "def") -> "abcdef"
To have one generic function for such a case you would need to find a common behavior that could be used as a constraint for a generic Type. In your case, you can do (but you should NOT) this:
DON'T DO THIS
extension String: AdditiveArithmetic {
// some stupid placeholders, as there is no obvious behavior for that :D
public static func - (lhs: String, rhs: String) -> String {
lhs
}
public static var zero: String {
""
}
}
func sum<T: AdditiveArithmetic>(_ a: T, _ b: T) -> T {
a + b
}
print(sum("LOl", "KEK")) // LOLKEK
print(sum(1, 2)) // 3
I would RECOMMEND just to add a new func for that particular case
func sum(_ a: String, _ b: String) -> String {
a + b
}
protocol AddProtocol {
static func +(lhs: Self, rhs: Self) -> Self
}
func add<T: AddProtocol>(num1: T, _ num2: T) -> T {
return num1 + num2
}
extension Int: AddProtocol {
}
extension String: AddProtocol {}
print(add(num1: "Abc", "Xyz"))
print(add(num1: 12, 30))
I need some help passing a function to my second class. I have tried many things but it still not work.
class Main {
func one() {
let test = Sub(function: two)
}
func two(val: Int, completion: ((Int, String)?)->()) { }
}
class Sub {
var function: (Int, ((Int, String)?)->())
init(function: (Int, ((Int, String)?)->())) {
self.function = function
}
}
Why is it that i get error on this line
let test = Sub(function: two)
which says: Cannot convert value of type '(Int, ((Int, String)?) -> ()) -> ()' to expected argument type '(Int, ((Int, String)?) -> ())'
What is the reason?
Function has a return value plus the completion , you need to change syntax of function var inisde Sub and the init also
class Main {
func one() {
let test = Sub(function: two)
}
func two(val: Int, completion: ((Int, String)?)->()) { }
}
class Sub {
var function: ((Int, ((Int, String)?)->())) -> ()
init(function:#escaping ((Int, ((Int, String)?)->())) -> ()) {
self.function = function
}
}
#escaping need to be added
class Main {
func one() {
let test = Sub(function: two)
}
func two(val: Int, completion: (Int, String)?)->() { }
}
class Sub {
var function: (Int, (Int, String)?)->()
init(function: #escaping (Int, (Int, String)?)->()) {
self.function = function
}
}
Where do I put the mocked code? Do I need to write everything again? Do I change the original code?
Short answer: using protocols.
If your injectable object is final, a struct, or an enum, it isn't even possible to override it to mock. Instead of using a concrete type as your dependency, use a protocol and conform your implementation to it. In addition to allowing "mocking" regardless of the real type (class, struct, enum), this lists the public interface all in one place, uninterrupted by the implementations. It also forces you to think about what needs to be part of the non-private interface.
With retroactive protocol conformance (i.e. in extensions), you can even use this to mock system classes like, e.g., CBCentralManager or CLLocationManager.
Example:
Not easily mockable:
struct Foo {
let id: Int
let data: Int
}
final class FooManager {
var x: Int
func getFoo(id: Int) -> Foo {
return Foo(id: id, data: x)
}
}
class FooUser {
let fooManager: FooManager
init(fooManager: FooManager) {
self.fooManager = fooManager
}
func getData() -> Int {
return fooManager.getFoo(id: 3).data
}
}
Trivially mockable:
struct Foo {
let id: Int
let data: Int
}
// Easy to see what's visible.
protocol FooManager {
func getFoo(id: Int) -> Foo
}
final class RealFooManager: FooManager {
private var x: Int
func getFoo(id: Int) -> Foo {
return Foo(id: id, data: x)
}
}
class FooUser {
let fooManager: FooManager
init(fooManager: FooManager) {
self.fooManager = fooManager
}
func getData() -> Int {
return fooManager.getFoo(id: 3).data
}
}
// In test target.
class MockFooManager: FooManager {
var requestedId: Int?
var data: Int = 17
func getFoo(id: Int) -> Foo {
requestedId = id
return Foo(id, data: data)
}
}
class FooUserTests {
func testFooUserGetData() {
let mock = MockFooManager()
let user = FooUser(fooManager: mock)
let data = user.getData()
XCTAssertEqual(data, mock.data)
XCTAssertEqual(mock.requestedId, 3)
}
}
I want to use generic protocol type as a function return type like this:
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> P<T> {
return C<T>()
}
}
But this code compile with errors complained:
Cannot specialize non-generic type 'P'
Generic parameter 'T' is not used in function signature
Is there any way to achieve similar function with Swift?
Swift 5.1 supports returning associated types using Opaque type. Using opaque type, your code builds successfully. Ref
protocol P {
associatedtype T
func get() -> T?
func set(v: T)
}
class C<T>: P {
private var v: T?
func get() -> T? {
return v
}
func set(v: T) {
self.v = v
}
}
class Factory {
func createC<T>() -> some P {
return C<T>()
}
The problem is you cannot use the syntax P<T>. P is a protocol, meaning it can't be treated as a generic type (Cannot specialize non-generic type 'P'), even though it may have a given associatedtype.
In fact, because it has an associatedtype, you now can't even use the protocol type itself directly – you can only use it as a generic constraint.
One solution to your problem is to simply change your function signature to createC<T>() -> C<T>, as that's exactly what it returns.
class Factory {
func createC<T>() -> C<T> {
return C<T>()
}
}
I'm not entirely sure what you would gain from having the return type be a protocol here. Presumably your example is just a simplification of your actual code and you want to be able to return an arbitrary instance that conforms to P. In that case, you could use type erasure:
class AnyP<T> : P {
private let _get : () -> T?
private let _set : (T) -> ()
init<U:P where U.T == T>(_ base:U) {
_get = base.get
_set = base.set
}
func get() -> T? {return _get()}
func set(v: T) {_set(v)}
}
class Factory {
func createC<T>() -> AnyP<T> {
return AnyP(C<T>())
}
}
How can I set a protocol's function so that it can receive an optional argument or even ignore it ?
I have this protocol :
protocol Game {
func modeName(forRound: Int) -> ModeName
}
With these 2 special classes :
//Goal: Default forRound should be 0 if none provided
class OnlineGame : Game {
func modeName(forRound: Int = 0) -> ModeName {
//Some code
}
}
//Goal: I don't care about the forRound value here
class OfflineGame : Game {
func modeName(_ forRound: Int) -> ModeName {
//Some code
}
}
First of all, in the protocol, you are declaring "method", and the first parameter of "method" has no external name by default. So here is the very normal case code:
class SomeGame: Game {
func modeName(forRound: Int) -> ModeName {
// ...
}
}
let game: Game = SomeGame()
let modeName = game.modeName(1) // not `game.modeName(forRound: 1)`
In your OnlineGame case, if the parameter has default value, it has external name automatically even if it's the first parameter of the method. You can override that behavior with _ as explicit external name:
class OnlineGame : Game {
func modeName(_ forRound: Int = 0) -> ModeName {
//Some code
}
}
In your OfflineGame case, you can ignore the parameter with _ as internal name:
class OfflineGame : Game {
func modeName(_: Int) -> ModeName {
//Some code
}
}