Objective-C uses reference counting to delete objects that are no longer in use, and Dart uses garbage collection (GC) for this. The Dart wrapper objects that wrap Objective-C objects automatically increment the reference count when the wrapper is created, and decrement it when the wrapper is destroyed. For the most part this is all automatic and you don't need to worry about it.
However, when using blocks or protocols, it's possible to create reference cycles that will prevent these objects from being cleaned up. If a block/protocol method closes over a wrapper object that holds a reference to the block/protocol, this cycle will cause a memory leak. This example uses a protocol, but the same thing can happen with a block:
final foo = FooInterface(); foo.delegate = BarDelegate.implement( someMethod: () { foo.anotherMethod(); } );
foo.delegate is holding a reference to a BarDelegate whose someMethod implementation is a Dart function which implicitly holds a reference to the foo. If this was all pure Dart code, the garbage collector would be able to clean up this reference cycle, but since FooInterface and BarDelegate are both Objective-C types this will leak memory.
To break this cycle, the method implementation must hold foo as a WeakReference, but it‘s even better to write your methods to avoid the need for things like this. To ensure the method doesn’t capture anything unexpected, it's also a good idea to move its construction to a separate function.
BarDelegate createBarDelegate(WeakReference<FooInterface> weakFoo) { return BarDelegate.implement( someMethod: () { weakFoo.target?.anotherMethod(); } ); } final foo = FooInterface(); foo.delegate = createBarDelegate(WeakReference(foo));