Why assign void to local variable - swift

So this is actually possible.
func clearItems() {
}
func reloadItems(_ clearItems: (() -> Void)? = nil) {
if let void = clearItems?() {
}
}
reloadItems(clearItems)
Should this be illegal? Or should we be forced to use _ intead of a variable name? Can void actually be consumed in some way here?

Void is a type in Swift just like anything else. There's seldom need to pass it around, but that doesn't change the fact the language supports returning and storing it in constants.
This implicitly happens anyway, you're just being explicit. You can, if you want return () at the end of every function that doesn't return a value since () represents an instance of Void. The compiler does that for you though so you don't need to.

Yes, but you need to change your reloadItems method to look like this:
func reloadItems(_ clearItems: (() -> Void)? = nil) {
if let void = clearItems {
void() // Call void.
}
}
by saying clearItems?(), you are calling the passed function, which is not the thing you wanted to do. You wanted to safely unwrap the passed function, so you need to treat it as a passed variable like the above snippet.
If you didn't use the if let statement, you can call clearItems like this:
clearItems?()
This will call the passed function if it isn't nil, and will do nothing if it is nil.
So your reloadItems function can simply become like this:
func reloadItems(_ clearItems: (() -> Void)? = nil) {
clearItems?() // This will call the passed function if it isn't nil, and will do nothing if it is nil.
}

Related

Cannot convert Generic value to AnyObject, when it is constrained by AnyObject

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.

What's the difference between the two closure

I tried comment and uncomment the activity() in the following code. I found when I commented the activity() the result in playground would just show "play tennis" once. However it would show twice if I uncommented activity(). What's the difference between the two statements?
class Baby {
var name = "peter"
var favoriteActivity: (() -> ())!
func outsideActivity(activity: #escaping () -> ()) {
//activity()
favoriteActivity = activity
}
}
var cuteBaby = Baby()
cuteBaby.outsideActivity {
print("play tennis")
}
cuteBaby.favoriteActivity()
This is what’s going on:
Consider this method:
func outsideActivity(activity: #escaping () -> ()) {
//activity()
favoriteActivity = activity
}
All that does is save the closure in the favoriteActivity property
Thus, when you do:
// create `Baby` instance
var cuteBaby = Baby()
// this method saves closure in `favoriteActivity`, but doesn’t call it
cuteBaby.outsideActivity {
print("play tennis")
}
// this now calls the closure
cuteBaby.favoriteActivity()
All the outsideActivity method does is save the closure in a property called favoriteActivity.
Thus you see one print statement.
However, now consider this method:
func outsideActivity(activity: #escaping () -> ()) {
activity()
favoriteActivity = activity
}
This actually calls the closure before saving it in the property.
So, when you do:
// create `Baby` instance
var cuteBaby = Baby()
// this method both calls the closure and then also saves it in `favoriteActivity`
cuteBaby.outsideActivity {
print("play tennis")
}
// this now calls the saved closure a second time
cuteBaby.favoriteActivity()
In this case, you’ll see your print statement being called twice.
That’s why the first rendition calls the closure only once, whereas the second calls the closure twice.
Usually when you pass a closure to a method, you either (a) call the closure from within the method (perhaps in some completion handler or the like); or (b) save the closure in some property so you can call it later.
So, this second example is very unusual, where outsideActivity both calls the closure itself and saves that closure in some property so you can call it again later. You usually do one or the other, but not both.

how to pass a callback function in another function in swift?

so i'm doing my first app,
and i want to do a function that will be a uniform funciton to sevral places in the system, and not belong to only one specific class.
Is there a way for me to pass a callback function as a parameter to another function ?
here is just a demonstration of what i mean.
ClassA {
func classAcallbackFunction (displayString: String) {
print (displayString)
}
ClassB().classBFunction(classAcallbackFunction())
}
ClassB {
func classBfunction (myCallbackfunc: func) {
mycallbackfunc("all is working !!!")
}
}
The parameter you have declared is not correct. Replace it with something like this:
func classBFunction(_ completion: (String) -> Void) {
completion("all working")
}
Like shared by regina_fallangi in the comments, callbacks are usually called completion handlers, which is why I replaced the names accordingly.
Extra Credit:
If you only want to optionally pass a function, you could do this:
func classBFunction(_ completion: ((String) -> Void)? = nil) {
completion?("all working")
}
Now you could also just call classBFunction().

"Closure cannot implicitly capture a mutating self parameter" - after updating to Swift 3 [duplicate]

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.

How to define a function with a function type parameter in Swift

I could define a function like this
func doWithAction(action: ()-> void) {
// something
}
However, when I use the function, the auto-completion of Xcode give me a block/closure
self.addPullToRefreshControllerWithAction { () -> void in
}
I know closure and function are something same in Swift, but I want to lead the one who use this function to pass a function in, not a block. The reason why I do this is I want this function to behave like a selector and a delegation
yes, closure and functions are practically the same in swift, so if the function expects a closure, you can pass a function with the same signature as a parameter instead. like this
func iAmAFunc(() -> Void) -> Void {
//do stuff
}
func funcThatTakesVoidAndReturnsVoid() -> Void {
//do stuff
}
var closureThatTakesVoidAndReturnsVoid: () -> Void = { }
iAmAFunc(funcThatTakesVoidAndReturnsVoid)
iAmAFunc(closureThatTakesVoidAndReturnsVoid)