In Swift 5, What Is a Way to Compare Pointers to Two Closures

In Swift 5, what is a way to compare pointers to two closures?

About pointers: notably, objects (classes) are reference types, so the equality of two objects is not the same as the identity of two objects. For equality (if defined within the class), you have the == operator, and for identity, the === operator:

class Foo:Equatable {
var i:Int = 0
static func == (lhs: Foo, rhs: Foo) -> Bool {
return lhs.i == rhs.i
}
}

let foo1 = Foo()
let foo2 = Foo()
let referenceToFoo1 = foo1

foo1 == foo2 // equality: true, since foo1.i == foo2.i, which is the criteria for equality
foo1 === foo2 // identity: false, since they are two different instances
foo1 === referenceToFoo1 // identity: true, both variables point to the same instance
foo1.i = 2
print(referenceToFoo1.i) // 2, since it refers to the same object

"Reference" can also be called a "pointer," although in Swift, unlike in C, we don't have to delve into pointer arithmetic, which is a pretty low-level way of dealing with memory addresses of pointers to objects and other data.


Just like classes, closures are also reference types in Swift, so in addition to their "equality" (do they contain the same code and captured information etc.) we can also look into their identity (i.e. do these two variables refer to the same closure or two different ones, even if they look the same etc.).

Problem is, Swift doesn't really seem to want to help us there.

Just like == doesn't work for closures, neither does ===. Neither do closure-types seem to conform to any protocol (and note that there's no single "closure type" but rather an infinite multitude of them depending on parameters and return types).

Furthermore, even casting a closure to AnyObject doesn't work:

foo1 as AnyObject === referenceToFoo1 as AnyObject // true, as expected

// with the `action1` closure from the question:
action1 as AnyObject === action1 as AnyObject // false; a bit of a surprise

Looks like every time Swift casts a closure to AnyObject, it creates a new AnyObject instance for some reason… So comparing these also reveals nothing.

So… I don't think we can reason about the identity or equality of closures in Swift. Maybe there is some other way, possibly via unsafe pointers… well, let me know if anyone had any luck going down that rabbit hole!

Function pointers, Closures, and Lambda

A lambda (or closure) encapsulates both the function pointer and variables. This is why, in C#, you can do:

int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
return i < lessThan;
};

I used an anonymous delegate there as a closure (it's syntax is a little clearer and closer to C than the lambda equivalent), which captured lessThan (a stack variable) into the closure. When the closure is evaluated, lessThan (whose stack frame may have been destroyed) will continue to be referenced. If I change lessThan, then I change the comparison:

int lessThan = 100;
Func<int, bool> lessThanTest = delegate(int i) {
return i < lessThan;
};

lessThanTest(99); // returns true
lessThan = 10;
lessThanTest(99); // returns false

In C, this would be illegal:

BOOL (*lessThanTest)(int);
int lessThan = 100;

lessThanTest = &LessThan;

BOOL LessThan(int i) {
return i < lessThan; // compile error - lessThan is not in scope
}

though I could define a function pointer that takes 2 arguments:

int lessThan = 100;
BOOL (*lessThanTest)(int, int);

lessThanTest = &LessThan;
lessThanTest(99, lessThan); // returns true
lessThan = 10;
lessThanTest(100, lessThan); // returns false

BOOL LessThan(int i, int lessThan) {
return i < lessThan;
}

But, now I have to pass the 2 arguments when I evaluate it. If I wished to pass this function pointer to another function where lessThan was not in scope, I would either have to manually keep it alive by passing it to each function in the chain, or by promoting it to a global.

Though most mainstream languages that support closures use anonymous functions, there is no requirement for that. You can have closures without anonymous functions, and anonymous functions without closures.

Summary: a closure is a combination of function pointer + captured variables.

How different @escpaing closure are stored in memory compare to @nonescaping

Think of an escaping block as code that jumps back to where the function was called originally. Meaning, if you have this method which executes the escaping block if variable is set to "yes":

func thisMethodHasA(variable: String, withAn escaping: @escaping (()->())) {
if variable == "yes" {

escaping()
//this will execute the code in the brackets

}
//this will return the method
}

and you call it like so (in playgrounds):

thisMethodHasA(variable: "no") {
print("the bracket code is executed")
}
print("thisMethodHasNowFinished")

the printed result is:

thisMethodHasNowFinished

As you see, the code is never executed.

If we set it to "yes":

thisMethodHasA(variable: "yes") {
print("the bracket code is executed")
}
print("thisMethodHasNowFinished")

the bracket code is executed
thisMethodHasNowFinished

As you see, the code inside the brackets was run before the method ended it's course.

So really, escaping blocks are pointers to code which only allocates a potential reference of memory space for that escaping block.. but without actually allocating that space until the escaping block is called. So i would say that escaping blocks are referenced similarly to how class references are performed to minimize memory allocation. So what your referenced sentence means, is that the code in escaping blocks keep a singular pointer throughout the app cycle, unlike a method pointer, which is deallocated whenever it's run it's course. By this definition, i'd suggest that it is stored in the stack, not the heap (to address your question).

I found these links/posts and articles which seem to get to a close answer too:
https://stackoverflow.com/a/41257089/7183483

For a good read on how Swift manages both Stack and Heap allocation:
https://medium.com/@itchyankles/memory-management-in-rust-and-swift-8ecda3cdf5b7

this one also explains the logic behind alocation.. so perhaps there is some hinting here at how these blocks are managed.. again, seems to be a lack of solid documentation on this topic out there!

How to compare two UIImage objects

One way is to convert them to image data first, and then compare that.

- (BOOL)image:(UIImage *)image1 isEqualTo:(UIImage *)image2
{
NSData *data1 = UIImagePNGRepresentation(image1);
NSData *data2 = UIImagePNGRepresentation(image2);

return [data1 isEqual:data2];
}

Pointers in Swift

  1. Is UnsafePointer <T> equal to const T * Pointer in ? and UnsafeMutablePointer <T> is equal to T * Pointer in C?

Well, use a bridging header in a Swift app to see how the C pointers are bridged:

const int *myInt;
int *myOtherInt;

bridges to

var myInt: UnsafePointer<Int32>!
var myOtherInt: UnsafeMutablePointer<Int32>!

  1. What is the difference between Unsafe[Mutable]Pointer and UnsafeRaw[Mutable]Pointer?

Swift 3 added a UnsafeRawPointer API to replace the Unsafe[Mutable]Pointer<Void> type. Conversion between pointers of a different type is no longer allowed in Swift. Instead, the API provides interfaces (.assumingMemoryBound(to:) or .bindMemory(to:capacity:)) to bind memory to a type.

With regard to question 3, the ampersand means that the variable is inout. I don't believe you can declare a variable as inout unless it is being used by a function that directly modifies the underlying memory, but I'll let the experts correct me. Instead, use withUnsafePointer.

Thanks to Martin's helpful comment, this syntax was never valid in Swift, and there is no safe way to create "free pointers" to Swift variables.

What is the Swift equivalent of isEqualToString in Objective-C?

With Swift you don't need anymore to check the equality with isEqualToString

You can now use ==

Example:

let x = "hello"
let y = "hello"
let isEqual = (x == y)

now isEqual is true.

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

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.”



Related Topics



Leave a reply



Submit