In Swift I am trying to implement a method "tap" similar to the method which exists in Ruby.
I've come up with the following example code:
private protocol Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self
}
private extension Tap {
mutating func tap(_ block: (inout Self) -> Void) -> Self {
block(&self)
return self
}
}
extension Array: Tap {}
var a = Array(repeating: "Hello", count: 5)
a.tap {
$0.append("5")
}.tap {
$0.append("7")
}
print(a) // (Expected) => ["Hello", "Hello", "Hello", "Hello", "Hello", "5", "7"]
I'm not super familiar with mutating functions, inout parameters, or Swift in general, but the code above looks like it should work to me. tap works as expected when it's not being included in a method chain. When I include it as part of a method chain, like in the above example, the Swift compiler complains:
Cannot use mutating member on immutable value: function call returns immutable value
Can anyone explain to me why this doesn't work? Can anyone provide a working solution and explain why that solution works?
Edit:
Another example usage would be:
let user = User(fromId: someId).tap {
$0.firstName = someFirstName
$0.lastName = someLastName
}
tap is a convenience thing that comes from Ruby. I'm mainly interested in understanding why the types in my function aren't working out right.
The return self returns a copy of the original array, not the original array itself. Until this copy is stored as a var, it cannot be mutated. So, this would work:
var b = a.tap {
$0.append("5")
}
b.tap {
$0.append("7")
}
But not without storing b as a var first. Of course, you wouldn't create a b in the first place, you would just use a repeatedly as you already pointed out.
So, the issue is that you can accomplish tap once, but cannot chain taps. This is because the return of self is implicitly immutable, and you cannot call a mutating function on an immutable value. Changing tap to a non-mutating function could get you what you want:
private extension Tap {
func tap(_ block: (inout Self) -> Void) -> Self {
let copy = self
block(©)
return copy
}
}
var a = Array(repeating: "Hello", count: 5)
a = a.tap({$0.append("5")}).tap({$0.append("7")})
Because each invocation of tap( returns a copy of the original modified by the given block, you can call it on immutable types. That means that you can chain.
The only downside is that new a = in the beginning.
Related
The error is Cannot convert value of type '(O?, ObservedType) -> Void' to expected argument type '(AnyObject?, ObservedType) -> Void, but I find this curious since O is constrained as AnyObject.
For context, I'm creating my own Observable class, but this question is actually about the specific error message above rather than how I might use any other third-party framework to use observables. That is, how can I properly cast my completion handler in this case.
public class Observable<ObservedType> {
struct Observer<ObservedType> {
weak var observer: AnyObject?
let completion: (AnyObject?, ObservedType) -> Void
}
private var observers: [Observer<ObservedType>]
public var value: ObservedType? {
didSet {
if let _ = value {
notifyObservers()
}
}
}
public init(_ value: ObservedType? = nil) {
self.value = value
observers = []
}
public func observe<O: AnyObject>(forward object: O?, completion: #escaping (O?, ObservedType) -> Void) {
observers.append(Observer(observer: object, completion: completion)) // error here
if let value = value {
completion(object, value)
}
}
private func notifyObservers() {
for observer in observers {
if let value = value {
DispatchQueue.main.async { observer.completion(nil, value) }
}
}
}
}
Is it possible to cast my completion handler in this case, or in some way equate O and AnyObject
According to your types, I can pass any object I want to the first parameter of Observer.completion. But the function you're assigning to .completion can only accept some specific type O.
You have to change completion to (AnyObject?, ObservedType) -> Void.
public func observe<O: AnyObject>(forward object: O?, completion: #escaping (AnyObject?, ObservedType) -> Void) {
^^^^^^^^^^
And the function you pass will have to deal with the fact that it can be passed anything. I suspect that this will break your whole system. But I don't believe this style of Observable is going to work, anyway, because of exactly these kinds of type problems.
There's really no good way to directly store the Observer inside the Observable. You're not currently using it, but I assume you want it for something like removing the observer. There are ways to do that, but you can't store the observer itself. You can return a unique identifier (UUID, for example), or you can work with ObjectIdentifiers or you can pass back "remove this item" closures that the observer must call. But you generally don't want to store the observer directly (and definitely not as an AnyObject).
I recommend using Combine for this, since that's what it's designed for. Or if you need to support older iOS versions, see this experiment for ways to make this work, or this experiment for a simplified version closer to what you're trying to do here.
I believe I have some misunderstanding of how generics work. I have the protocol:
protocol CommandProtocol {
func execute<T>() -> T
func unExecute<T>() -> T
}
And a class that conforms to it:
class CalculatorCommand: CommandProtocol {
...
func execute<String>() -> String {
return calculator.performOperation(operator: `operator`, with: operand) as! String
}
func unExecute<Double>() -> Double {
return calculator.performOperation(operator: undo(operator: `operator`), with: operand) as! Double
}
...
}
The calculator.performOperation() method actually returns Double, but here I just try to play with generics so I replace return type from Double to String.
After that, I have a class which invokes these methods:
class Sender {
...
// MARK: - Public methods
func undo() -> Double {
if current > 0 {
current -= 1
let command = commands[current]
return command.unExecute()
}
return 0
}
func redo() -> Double? {
if current < commands.count {
let command = commands[current]
current += 1
let value: Double = command.execute()
print(type(of: value))
return command.execute()
}
return nil
}
...
}
In the undo() method everything works as expected (one thing that I did not understand fully is how Swift really knows whether the unExecute value will return Double or not, or compiler infers it based on the undo() return type?)
But in the redo() method, I am calling the execute() method which returns String, but the method expects Double, so I thought that my program would crash, but not, it works totally fine as if execute() method returns Double.
Please, could someone explain to me what exactly happens under the cover of this code? Thank you in advance.
You are correct that you misunderstand generics. First, let's look at this protocol:
protocol CommandProtocol {
func execute<T>() -> T
func unExecute<T>() -> T
}
This says "no matter what type the caller requests, this function will return that type." That's impossible to successfully implement (by "successfully" I mean "correctly returns a value in all cases without crashing"). According this protocol, I'm allowed to write the following code:
func run(command: CommandProtocol) -> MyCustomType {
let result: MyCustomType = command.execute()
return result
}
There's no way to write an execute that will actually do that, no matter what MyCustomType is.
Your confusion is compounded by a subtle syntax mistake:
func execute<String>() -> String {
This does not mean "T = String," which is what I think you expect it to mean. It creates a type variable called String (that has nothing to do with Swift's String type), and it promises to return it. when you later write as! String, that means "if this values isn't compatible with the type requested (not "a string" but whatever was requested by the caller), then crash.
The tool that behaves closer to what you want here is an associated type. You meant to write this:
protocol CommandProtocol {
associatedType T
func execute() -> T
func unExecute() -> T
}
But this almost certainly won't do what you want. For example, with that, it's impossible to have an array of commands.
Instead what you probably want is a struct:
struct Command {
let execute: () -> Void
let undo: () -> Void
}
You then make Commands by passing closures that do what you want:
let command = Command(execute: { self.value += 1 },
undo: { self.value -= 1 })
Alternately, since this is a calculator, you could do it this way:
struct Command {
let execute: (Double) -> Double
let undo: (Double) -> Double
}
let command = Command(execute: { $0 + 1 }, undo: { $0 - 1 })
Then your caller would look like:
value = command.execute(value)
value = command.undo(value)
You think this returns a Swift.Double, but no. This code is no different than using T instead of Double. Swift does not require the names of generic placeholders to match what you put in a protocol.
func unExecute<Double>() -> Double {
return calculator.performOperation(operator: undo(operator: `operator`), with: operand) as! Double
}
You're not actually looking for generic methods. You want this, instead.
protocol CommandProtocol {
associatedtype ExecuteValue
associatedtype UnExecuteValue
func execute() -> ExecuteValue
func unExecute() -> UnExecuteValue
}
I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.
I'm trying to create a protocol in Swift I can use for object construction. The problem I'm running into is that I need to store the type information so the type can be constructed later and returned in a callback. I can't seem to find a way to store it without either crashing the compiler or creating build errors. Here's the basics (a contrived, but working example):
protocol Model {
init(values: [String])
func printValues()
}
struct Request<T:Model> {
let returnType:T.Type
let callback:T -> ()
}
We have a simple protocol that declares a init (for construction) and another func printValues() (for testing). We also define a struct we can use to store the type information and a callback to return the new type when its constructed.
Next we create a constructor:
class Constructor {
var callbacks: [Request<Model>] = []
func construct<T:Model>(type:T.Type, callback: T -> ()) {
callback(type(values: ["value1", "value2"]))
}
func queueRequest<T:Model>(request: Request<T>) {
callbacks.append(request)
}
func next() {
if let request = callbacks.first {
let model = request.returnType(values: ["value1", "value2"])
request.callback(model)
}
}
}
A couple things to note: This causes a compiler crash. It can't figure this out for some reason. The problem appears to be var callbacks: [Request<Model>] = []. If I comment out everything else, the compiler still crashes. Commenting out the var callbacks and the compiler stops crashing.
Also, the func construct works fine. But it doesn't store the type information so it's not so useful to me. I put in there for demonstration.
I found I could prevent the compiler from crashing if I remove the protocol requirement from the Request struct: struct Request<T>. In this case everything works and compiles but I still need to comment out let model = request.returnType(values: ["value1", "value2"]) in func next(). That is also causing a compiler crash.
Here's a usage example:
func construct() {
let constructor = Constructor()
let request = Request(returnType: TypeA.self) { req in req.printValues() }
//This works fine
constructor.construct(TypeA.self) { a in
a.printValues()
}
//This is what I want
constructor.queueRequest(request)
constructor.next() //The callback in the request object should be called and the values should print
}
Does anyone know how I can store type information restricted to a specific protocol to the type can later be constructed dynamically and returned in a callback?
If you want the exact same behavior of next I would suggest to do this:
class Constructor {
// store closures
var callbacks: [[String] -> ()] = []
func construct<T:Model>(type:T.Type, callback: T -> ()) {
callback(type(values: ["value1", "value2"]))
}
func queueRequest<T:Model>(request: Request<T>) {
// some code from the next function so you don't need to store the generic type itself
// **EDIT** changed closure to type [String] -> () in order to call it with different values
callbacks.append({ values in
let model = request.returnType(values: values)
request.callback(model)
})
}
func next(values: [String]) {
callbacks.first?(values)
}
}
Now you can call next with your values. Hopefully this works for you.
EDIT: Made some changes to the closure type and the next function
Unfortunately there is no way to save specific generic types in an array and dynamically call their methods because Swift is a static typed language (and Array has to have unambiguous types).
But hopefully we can express something like this in the future like so:
var callbacks: [Request<T: Model>] = []
Where T could be anything but has to conform to Model for example.
Your queueRequest method shouldn't have to know the generic type the Request it's being passed. Since callbacks is an array of Request<Model> types, the method just needs to know that the request being queued is of the type Request<Model>. It doesn't matter what the generic type is.
This code builds for me in a Playground:
class Constructor {
var callbacks: [Request<Model>] = []
func construct<T:Model>(type:T.Type, callback: T -> ()) {
callback(type(values: ["value1", "value2"]))
}
func queueRequest(request: Request<Model>) {
callbacks.append(request)
}
func next() {
if let request = callbacks.first {
let model = request.returnType(values: ["value1", "value2"])
request.callback(model)
}
}
}
So I found an answer that seems to do exactly what I want. I haven't confirmed this works yet in live code, but it does compile without any errors. Turns out, I needed to add one more level of redirection:
I create another protocol explicitly for object construction:
protocol ModelConstructor {
func constructWith(values:[String])
}
In my Request struct, I conform to this protocol:
struct Request<T:Model> : ModelConstructor {
let returnType:T.Type
let callback:T -> ()
func constructWith(values:[String]) {
let model = returnType(values: values)
callback(model)
}
}
Notice the actual construction is moved into the Request struct. Technically, the Constructor is no longer constructing, but for now I leave its name alone. I can now store the Request struct as ModelConstructor and correctly queue Requests:
class Constructor {
var callbacks: [ModelConstructor] = []
func queueRequest(request: Request<Model>) {
queueRequest(request)
}
func queueRequest(request: ModelConstructor) {
callbacks.append(request)
}
func next() {
if let request = callbacks.first {
request.constructWith(["value1", "value2"])
callbacks.removeAtIndex(0)
}
}
}
Note something special here: I can now successfully "queue" (or store in an array) Request<Model>, but I must do so indirectly by calling queueRequest(request: ModelConstructor). In this case, I'm overloading but that's not necessary. What matters here is that if I try to call callbacks.append(request) in the queueRequest(request: Request<Model>) function, the Swift compiler crashes. Apparently we need to hold the compiler's hand here a little so it can understand what exactly we want.
What I've found is that you cannot separate Type information from Type Construction. It needs to be all in the same place (in this case it's the Request struct). But so long as you keep construction coupled with the Type information, you're free to delay/store the construction until you have the information you need to actually construct the object.
I'm using optional closures, but can't find a way to pass on a parameter.
Searched everywhere, tried all suggestions, but can't get it to work.
My code:
func DoAlert(title: String
, message: String
, actions: String
, sender: AnyObject?
, Ctlr : UIViewController
, SegueString: String?
, YesClosure: ()->() = {}
, NoClosure: ()->() = {}
, StartClosure: ()->() = {}
, EndClosure: ()->() = {}
) {
if (actions.rangeOfString("Ok") != nil {
alert.addAction(UIAlertAction(title: "OK", style: .Default ) { action -> Void in
EndClosure()
})}
} // end function
I want to add a closure for Ok, where the 'self' parameter is needed.
Something like below:
// add to func doAlert:
, OkClosure: (AnyObject)->() = {}
// add to action Ok (before the EndClosure:
OkClosure(sender!)
Getting error on first line:
AnyObject is not subtype of ()
If I leave AnyObject out of first line, Getting error:
Cannot convert the expression's type 'AnyObject' to type '() => ()'
All other trials give me similar 'Tuple' errors.
How do I code the passing of parameters in the optional closures in my code?
Firstly, to use closures as an argument for a function, you should declare them like so:
func myFunc(closure: (Int) -> Void) {
// Now I can call closure like so:
let myInt = 10
closure(myInt)
}
(As pointed out by #Airspeed Velocity, the parenthesis around Int are not strictly required because there is only one argument. Whether you include them is just personal preference)
Secondly, you can modify the previous function to include an optional closure, as follows:
(Note the ? and parenthesis around the closure that indicate the closure is an optional, not the return type)
func myFunc(closure: ((Int) -> Void)?) {
// Now when calling the closure you need to make sure it's not nil.
// For example:
closure?(10)
}
Thirdly, to add a default value of nil, which is what it looks like you're trying to do with the = {} on the end of YesClosure: ()->() = {}, you could do:
func myFunc(closure: ((Int) -> Void)? = nil) {
// Still need to make sure it's not nil.
if let c = closure {
c(10)
}
}
Finally, just as a note, you can set the names of the arguments of the closure, which can make it easier to identify what you're passing to the closure when calling it. For example:
(Note - here parenthesis are required around value: Int)
func myFunc(closure: ((value: Int) -> Void)) {
closure(value: 10)
}
Even more finally, you could use typealias. According to the documentation:
A type alias declaration introduces a named alias of an existing type into your program.
Here's an example of how to use it with a closure:
typealias MyClosureType = () -> Void
func myFunc(closure: MyClosureType) {
closure()
}
Hope that helps!
I think I found it. I can't use parameters in the closure when I call func. In func itself I need to define the parameters used (closure: (sender: AnyObject) -> Void), make sure the variables are defined (or provided as a separate parameter) and add them to the closure call.
#IBAction func buttonPressed(sender: AnyObject) {
myFunc (sender, doClosure)
}
func myFunc(sender: AnyObject, closure: (sender: AnyObject) -> Void) {
// Now I can call closure like so:
closure (sender: sender)
}
func doClosure(sender: AnyObject) {
println("sender = \(sender)")
}