Difference between block (Objective-C) and closure (Swift) in iOS - ios

In tutorials it's written that functionally both are same even closure is more easier then block and its avoided the complexity of block and memory management, I've gone through many tutorials but except these I'm not getting the difference between swift's "closure" and Objective-C "block".

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C.” iBooks:
“Swift closures and Objective-C blocks are compatible, so you can pass Swift closures to Objective-C methods that expect blocks. Swift closures and functions have the same type, so you can even pass the name of a Swift function.
Closures have similar capture semantics as blocks but differ in one key way: Variables are mutable rather than copied. In other words, the behavior of __block in Objective-C is the default behavior for variables in Swift.”

Slight differences. One was mentioned; variables are captured as variables, not as values. Which can be either useful or a trap. Importantly you can define a capture list in a Swift closure, so if you include self.property in the capture list, then the value of that property is captured, and not self. That also simplifies capturing weak variables.

To show an actual code example of the differences:
This does compile:
let x : #convention(swift) (inout Int) -> ()
This does not:
let y : #convention(block) (inout Int) -> ()
with the error (inout Int) -> () is not representable in Objective-C

Related

Swift Selector on UIScreen brightness returning UIDevice when invoked

I have the following snippet
let classByName = objc_lookUpClass("UIScreen")
let mainScreen = (classByName as? NSObjectProtocol)?.perform(Selector("mainScreen"))?.takeRetainedValue()
print(mainScreen) // Optional(<UIScreen: ....
print(mainScreen?.perform(Selector("brightness")).takeUnretainedValue()) // Optional(<UIDevice:...
As you can see the second method returns a reference to the current UIDevice instead of the CGFloat corresponding to a screen brightness...
Any idea on what's going on here?
You run into a corner case due to using dispatch methods that are not recommended in Swift.
Please note that everything you read below is related to the Objective-C message passing (aka method calling). When interoperating with Objective-C classes, the Swift compiler generates (more or less) the same caller code as the Objective-C compiler, so anything that applies to Objc, also applies to Swift code calling ObjC.
First of all, performSelector should not be used on methods that return float, since behind the scenes performSelector calls objc_msgSend, however for methods that return a float, the internal result of objc_msgSend is read from the wrong location.
A little bit of background of objc_msgSend - this function is at the core of the Objective-C dynamic dispatch, basically any method call on an Objective-C object results in objc_msgSend being called. I won't get into too many details here, there are many online materials about objc_msgSend, just want to summarize that the function is a very versatile one, and can be casted to match any method signature.
So, let's take the brightness example. What actually happens behind the scenes when using performSelector (the Objective-C method named in Swift perform(_:))? This is roughly how performSelector is implemented:
- (void)performSelector:(SEL)selector) {
return objc_msgSend(self, selector);
}
Basically the method simply forwards the value resulted by calling objc_msgSend.
Now the things get interesting. Because floats and ints use different return locations, the compiler will need to generate different reading location depending on its knowledge about the type of data returned by objc_msgSend.
And if there's a misunderstanding between what the compiler thinks objcSend will return, and what actually the function returns, then bad things might happen. But in your case there's a "fortunate" coincidence due to which your program doesn't crashes.
Basically your perform(Selector("brightness") call results in a objc_msgSend(mainScreen, Selector("brightness")) call that assumes that objc_msgSend will return an object. But in turn the called code - the brightness getter - returns a float.
So why isn't the app crashing when the Swift code tries to print the result (actually it should crash on takeUnretainedValue)?
It's because floats and ints (and object pointers are in the same category as int) have different return locations. And the performSelector reads from the return location for ints, as it expects an object pointer. Fortunately, at that point in time, the last method called is likely a method that returns an UIDevice instance. I assume that internally UIScreen.brightness asks the device object for this information.
Something like this happens:
1. Swift code calls mainScreen?.perform(Selector("brightness")
2. This results in Objective-C call [mainScreen performSelector:selector]
3. objc_msgSend(mainScreen, selector) is called
3. The implementation of UIScreen.brightness is executed
4. UIScreen.brightness calls UIDevice.current (or some other factory method)
5. UIDevice.current stores the `UIDevice` instance in the int return location
6. UIScreen.brightness calls `device.someMemberThatReturnsTheBrightness`
7. device.someMemberThatReturnsTheBrightness stores the brightness into
the float return location
8. UIScreen.brightness exits, its results is already at the proper location
9. performSelector exits
10. The Swift code expecting an object pointer due to the signature of
performSelector reads the value from the int location, which holds the
value stored at step #5
Basically, it's all about calling conventions, and about how your "innocent" code gets translated into assembly instructions. This is why the fully dynamic dispatch is not recommended, because the compiler doesn't have all the details to construct a reliable set of assembly instructions.

What is difference between Any , Hashable , AnyHashable in Swift 3?

I scratch my head through lots of tutorials to understand the difference between the above 3 terms and find new term type erased container, now it becomes confusing to me. It raises lots of question.
Why does Swift introduce AnyHashable ?
What is the fundamental difference between these 3 terms?
Difference between Any and AnyHashable ?
Difference between Hashable and AnyHashable?
When to use Hashable and when to use AnyHashable ?
Last but most confusing, what is the meaning of type erased term in the context of AnyHashable ?
As a context, I followed Swift Evolution Proposal SE-0131.
It's more important to understand what they are than what are the differences between them.
Any means "anything", ranging from swift enums, tuples, closures, structs, classes, protocols, whatever. Every type can be assigned to a variable of type Any.
Hashable is protocol that says "this object can be hashed i.e. has a hashcode". If your object can be hashed, implement this protocol, because lots of data structures (namely dictionaries and sets) need it.
So what is AnyHashable?
Normally, if you try to do this:
let a: Set<Hashable>?
it does not compile. This is because Hashable inherits from Equatable which contains Self.
Now, let's say you want to port a method from Objective-C to swift. That method takes a parameter of type NSSet. In Swift, this will turn into a Set, but what is its generic parameter? If we just put Any like we do with NSArrays, it does not work because Set's objects must be hashable. But if we put Set<Hashable> it does not work either because Hashable can only be used as a generic constraint. That's why they wrapped Hashable with an AnyHashable that does not use Self and so can be used as a generic parameter.
Regarding what "type erased" means:
Having Self in a protocol is kind of like a protocol with a generic parameter, and the generic parameter is always the conforming class. This causes the protocols to be unable to be used on its own like Set<Hashable> because the "generic parameter" is unknown. AnyHashable solves this problem by not using Self at all so it now becomes a normal struct. It "erases" the generic Self type.

What is difference between #noescape, #escaping and #autoclosure?

I am converting code to Swift using Xcode 8, but compiler warns to add #escape in some of the nested functions already created in Swift 2.3, with closure syntax. I have found some other keywords also #noescape and #autoclosure, but I have some question regarding this :
What is functional need of this keyword?
What is impact of writing #escaping ?
Is it necessary to write ?
Is #autoclosure behave same as #escape?
When to use which keyword and why ?
Here is Swift-evolution document, but not getting much from it.
The most important difference is between #escaping and #noescaping (there is no such keyword in Swift 3!). When a closure is marked as #noescape, you can be sure that the closure won't be retained by the method (e.g. to perform an asynchronous call), therefore you don't have to worry about ownership cycles (there are some other minor benefits).
#escaping closures can be saved or called sometimes in the future therefore you have to be sure to handle ownership (e.g. [weak self]) correctly.
For #autoclosure see How to use Swift #autoclosure . In short, it allows you to skip braces around the closure in some situations.
The default (when not specified) is #noescaping in Swift 3 (see rationale). They keyword does not actually exist anymore. There is only #escaping.
#escape means that your function can be called after method ends.
#noescape means that your closure will be called before the end of function it passed to.
#autoclosure means that you can omit writing closure braces, but it automatically becomes #noescape.
#autoclosure creates an automatic closure around the expression. So when the caller writes an expression like 2 > 1, it's automatically wrapped into a closure to become {2 > 1} before it is passed to some function.
2 - Easier for compiler to perform optimisations.
3 - beter to write, to give compiler(or anybody that using your function) information how it behaves with your closure
4 - no
5 - described on the top of the answer

Can I trigger a compiler warning when there is an implicitly captured "self" in Swift

If I have some code that takes a closure, and self is implicitly captured, can I make it cause a compiler warning? Is there some flag I can add to the compiler command for this?
Not exactly. But there is something that addresses what's presumably the reason you'd want this warning — to prevent situation where a closure capturing self can cause a retain cycle...
The potential retain cycle from capturing self in a closure comes up when the closure is passed as a parameter to a function but is used after the function returns — that is, the lifetime of the closure (and anything captured in it) "escapes" the context in which it's written. When the closure escapes, it has to be sure it still has access to the things it uses (like self and any properties or methods thereof), so we get into memory management and possible retain cycles, [weak self]/strongSelf, etc.
With #noescape, you can declare that closures passed as parameters to a function will not escape the calling context, and as such don't require the extra memory management overhead for closures that do. And the compiler can apply some other optimizations that make running your function and its closure faster.
func someFunctionWithNoescapeClosure(#noescape closure: () -> Void) {
closure()
}
Within a #noescape closure, you can then access methods/properties on self without explicitly writing self., because you're not capturing self anymore. And, once you label a parameter #noescape, if you try to do anything that would permit it to escape (say, take the closure from the parameter and assign it to a stored property), you'd get a compiler error (not just a warning).
For the full writeup from Apple, see Nonescaping Closures in The Swift Programming Language. And this post provides an alternate perspective that might explain things further.
No, the only thing I can think of which can do anything similar is linting.
SwiftLint might be able to do something like that, and if not you can probably write your own rule for just such a thing.

Why can't I reassign an instance method in Swift?

So this question has an obvious answer: "because the compiler won't let you" but I'm hoping someone can explain to me why this part of Swift works the way it does.
I ran into this question because I was building a view controller that needed to satisfy a protocol (UIImagePickerControllerDelegate). The protocol requires a callback function to call after a user selected an image. I wanted to be able to change the callback behavior at runtime.
Coming from a Python background, I figured that should be easy: just define the callback method on my class to satisfy the protocol and then redefine it later by just reassigning to it. That works perfectly fine in Python:
class Foo(object):
def bar(self):
print "bar"
foo = Foo()
foo.bar() # output "bar"
def baz():
print "baz"
foo.bar = baz
foo.bar() # output "baz"
But it doesn't work in Swift (even though I can do very nearly the same thing by declaring a variable to hold a closure):
import UIKit
class Foo {
func bar() -> String {
return "bar"
}
var baz: ()-> String = {
return "baz"
}
}
let foo = Foo()
foo.bar() // output: bar
foo.baz() // output: baz
let gee = {
return "gee"
}
foo.baz = gee
foo.baz() // output: gee
foo.bar = gee // error: cannot assign to bar in foo
So the question...why does Swift work this way? It's clearly not because it's impossible to alter function routing at runtime (otherwise the closure assignment wouldn't work). My best guess is that it's analogous to the let/var distinction for variables and that using "func" is implicitly telling the compiler that a function should be immutable. And I grant that it may be better to make instance methods immutable by default. But it is annoying when we need to comply with rigid protocols from UIKit. At least it would be nice if I could use a variable to satisfy a function requirement in a protocol.
(For the curious: I worked around this issue by declaring an instance variable to hold a closure that can be reassigned. I then declared the required protocol function and made it do nothing but call the closure. Which might(?) cause a retain cycle, but works.)
The code the compiler is allowed to emit is fundamentally different.
Making a simple test, compiling with -Onone for readability, and disassembling with Hopper, you can see what's going on (comments added manually):
In the case of an "instance method"/function, they can be called after being looked up in the vtable — in this example, *(*rax + 0x48) and *(*rax + 0x70) are pointers to the functions, and they're passed rax (the object itself) as a parameter (this becomes self).
However in the case of a closure variable, *(*rax + 0x50) is a pointer to the getter for bar. The getter is called first, and returns the closure which is then called — (rax)(rdx).
So these are simply different things. If you have a modifiable property that stores a closure, then certainly you need to call the getter before you can call the closure (since the value could have changed by being set elsewhere). But simple function dispatch doesn't require the extra level of indirection.
Im not certain how functions and closures work behind the scenes in swift, but i would think a function in swift is basically like a function in c, its defined at runtime and thats it. its compiled and lives at a certain address in memory and anything referencing that function has to look at that memory address, and that cant change at runtime.
A closure i would see as like a function pointer + normal function combination in c. so its probably a limitation of the way they implemented the function in swift. in python maybe behind the scenes everything is implemented like a function pointer + normal function.
as to why swift didnt implement it like python, i think only someone who works at Apple could tell you that, but maybe there is some overhead with using everything like a closure instead of just plain functions, so they make you only use closures when needed and the rest should be functions.
also having functions immutable could be the reason why protocols work behind the scenes, maybe allowing you to change the function at run time would break the protocol system.
Im not sure if anyone here is really fit to answer this (besides an apple employee lurking here maybe), but this is my best guess

Resources