diff --git a/src/ObjCRuntime/Blocks.cs b/src/ObjCRuntime/Blocks.cs index d6c017945127..920fb05db7ca 100644 --- a/src/ObjCRuntime/Blocks.cs +++ b/src/ObjCRuntime/Blocks.cs @@ -564,10 +564,27 @@ unsafe internal static BlockLiteral CreateBlock (Action action) } // This class will free the specified block when it's collected by the GC. - internal class BlockCollector : TrampolineBlockBase { + internal class BlockCollector { + IntPtr block; + int count; public BlockCollector (IntPtr block) - : base (block, owns: true) { + this.block = block; + count = 1; + } + + public void Add (IntPtr block) + { + if (block != this.block) + throw new InvalidOperationException (string.Format ("Can't release the block 0x{0} because this BlockCollector instance is already tracking 0x{1}.", block.ToString ("x"), this.block.ToString ("x"))); + Interlocked.Increment (ref count); + } + + ~BlockCollector () + { + for (var i = 0; i < count; i++) + Runtime.ReleaseBlockOnMainThread (block); + count = 0; } } #endif diff --git a/src/ObjCRuntime/Runtime.cs b/src/ObjCRuntime/Runtime.cs index dba492ab66e6..46a74137bf44 100644 --- a/src/ObjCRuntime/Runtime.cs +++ b/src/ObjCRuntime/Runtime.cs @@ -2046,7 +2046,11 @@ static Delegate ReleaseBlockWhenDelegateIsCollected (IntPtr block, Delegate @del if (block == IntPtr.Zero) return @delegate; - block_lifetime_table.Add (@delegate, new BlockCollector (block)); + if (block_lifetime_table.TryGetValue (@delegate, out var existingCollector)) { + existingCollector.Add (block); + } else { + block_lifetime_table.Add (@delegate, new BlockCollector (block)); + } return @delegate; }