diff --git a/pkgs/ffigen/CHANGELOG.md b/pkgs/ffigen/CHANGELOG.md index 92c4a40d8..145c49cdd 100644 --- a/pkgs/ffigen/CHANGELOG.md +++ b/pkgs/ffigen/CHANGELOG.md @@ -1,9 +1,13 @@ -## 18.0.0-dev +## 18.0.0-wip - Add variable substitutions that can be used in the `headers.entry-points` to locate Apple APIs: `$XCODE`, `$IOS_SDK`, and `$MACOS_SDK`. - __Breaking change__: Change the `usrTypeMappings` field of `Config`'s factory constructor from a `List` to a `Map`. +- Add a `keepIsolateAlive` parameter to the block and protocol constructors that + allows a block or protocol to keep its owner isolate alive. +- __Breaking change__: `keepIsolateAlive` defaults to true, so all existing ObjC + blocks and protocols now keep their isolates alive by default. ## 17.0.0 diff --git a/pkgs/ffigen/lib/src/code_generator/objc_block.dart b/pkgs/ffigen/lib/src/code_generator/objc_block.dart index d46c3d913..bec4391fd 100644 --- a/pkgs/ffigen/lib/src/code_generator/objc_block.dart +++ b/pkgs/ffigen/lib/src/code_generator/objc_block.dart @@ -240,8 +240,12 @@ abstract final class $name { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static $blockType fromFunction(${func.dartType} fn) => - $blockType($newClosureBlock($closureCallable, $convFn), + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static $blockType fromFunction(${func.dartType} fn, + {bool keepIsolateAlive = true}) => + $blockType($newClosureBlock($closureCallable, $convFn, keepIsolateAlive), retain: false, release: true); '''); @@ -274,11 +278,12 @@ abstract final class $name { /// but only supports void functions, and is not run synchronously. See /// NativeCallable.listener for more details. /// - /// Note that unlike the default behavior of NativeCallable.listener, listener - /// blocks do not keep the isolate alive. - static $blockType listener(${func.dartType} fn) { - final raw = $newClosureBlock( - $listenerCallable.nativeFunction.cast(), $listenerConvFn); + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static $blockType listener(${func.dartType} fn, + {bool keepIsolateAlive = true}) { + final raw = $newClosureBlock($listenerCallable.nativeFunction.cast(), + $listenerConvFn, keepIsolateAlive); final wrapper = $wrapListenerFn(raw); $releaseFn(raw.cast()); return $blockType(wrapper, retain: false, release: true); @@ -290,14 +295,17 @@ abstract final class $name { /// caller until the callback is handled by the Dart isolate that created /// the block. Async functions are not supported. /// - /// This block does not keep the owner isolate alive. If the owner isolate has - /// shut down, and the block is invoked by native code, it may block + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. If the owner isolate + /// has shut down, and the block is invoked by native code, it may block /// indefinitely, or have other undefined behavior. - static $blockType blocking(${func.dartType} fn) { - final raw = $newClosureBlock( - $blockingCallable.nativeFunction.cast(), $listenerConvFn); + static $blockType blocking(${func.dartType} fn, + {bool keepIsolateAlive = true}) { + final raw = $newClosureBlock($blockingCallable.nativeFunction.cast(), + $listenerConvFn, keepIsolateAlive); final rawListener = $newClosureBlock( - $blockingListenerCallable.nativeFunction.cast(), $listenerConvFn); + $blockingListenerCallable.nativeFunction.cast(), + $listenerConvFn, keepIsolateAlive); final wrapper = $wrapBlockingBlockFn($wrapBlockingFn, raw, rawListener); $releaseFn(raw.cast()); $releaseFn(rawListener.cast()); diff --git a/pkgs/ffigen/lib/src/code_generator/objc_protocol.dart b/pkgs/ffigen/lib/src/code_generator/objc_protocol.dart index 50bc756d1..3d124d864 100644 --- a/pkgs/ffigen/lib/src/code_generator/objc_protocol.dart +++ b/pkgs/ffigen/lib/src/code_generator/objc_protocol.dart @@ -176,14 +176,18 @@ interface class $name extends $protocolBase $impls{ '''); } - final args = buildArgs.isEmpty ? '' : '{${buildArgs.join(', ')}}'; + buildArgs.add('bool \$keepIsolateAlive = true'); + final args = '{${buildArgs.join(', ')}}'; final builders = ''' /// Builds an object that implements the $originalName protocol. To implement /// multiple protocols, use [addToBuilder] or [$protocolBuilder] directly. + /// + /// If `\$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static $name implement($args) { final builder = $protocolBuilder(); $buildImplementations - return $name.castFrom(builder.build()); + return $name.castFrom(builder.build(keepIsolateAlive: \$keepIsolateAlive)); } /// Adds the implementation of the $originalName protocol to an existing @@ -199,10 +203,13 @@ interface class $name extends $protocolBase $impls{ /// Builds an object that implements the $originalName protocol. To implement /// multiple protocols, use [addToBuilder] or [$protocolBuilder] directly. All /// methods that can be implemented as listeners will be. + /// + /// If `\$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static $name implementAsListener($args) { final builder = $protocolBuilder(); $buildListenerImplementations - return $name.castFrom(builder.build()); + return $name.castFrom(builder.build(keepIsolateAlive: \$keepIsolateAlive)); } /// Adds the implementation of the $originalName protocol to an existing @@ -215,10 +222,13 @@ interface class $name extends $protocolBase $impls{ /// Builds an object that implements the $originalName protocol. To implement /// multiple protocols, use [addToBuilder] or [$protocolBuilder] directly. All /// methods that can be implemented as blocking listeners will be. + /// + /// If `\$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static $name implementAsBlocking($args) { final builder = $protocolBuilder(); $buildBlockingImplementations - return $name.castFrom(builder.build()); + return $name.castFrom(builder.build(keepIsolateAlive: \$keepIsolateAlive)); } /// Adds the implementation of the $originalName protocol to an existing diff --git a/pkgs/ffigen/pubspec.yaml b/pkgs/ffigen/pubspec.yaml index e40aa13ff..3a308188d 100644 --- a/pkgs/ffigen/pubspec.yaml +++ b/pkgs/ffigen/pubspec.yaml @@ -3,7 +3,7 @@ # BSD-style license that can be found in the LICENSE file. name: ffigen -version: 18.0.0-dev +version: 18.0.0-wip description: > Generator for FFI bindings, using LibClang to parse C, Objective-C, and Swift files. @@ -41,7 +41,7 @@ dev_dependencies: dart_flutter_team_lints: ^2.0.0 json_schema: ^5.1.1 leak_tracker: ^10.0.7 - objective_c: ^6.0.0 + objective_c: ^7.0.0 test: ^1.16.2 dependency_overrides: diff --git a/pkgs/ffigen/test/native_objc_test/block_test.dart b/pkgs/ffigen/test/native_objc_test/block_test.dart index 8a4b7136e..2dc2d0d18 100644 --- a/pkgs/ffigen/test/native_objc_test/block_test.dart +++ b/pkgs/ffigen/test/native_objc_test/block_test.dart @@ -10,6 +10,7 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:io'; +import 'dart:isolate'; import 'package:ffi/ffi.dart'; import 'package:objective_c/objective_c.dart'; @@ -863,6 +864,193 @@ void main() { expect(objectRetainCount(objectPtr), 0); } }); + + test('Block.fromFunction, keepIsolateAlive', () async { + final isolateSendPort = Completer(); + final blocksCreated = Completer(); + final blkKeepAliveDestroyed = Completer(); + final receivePort = RawReceivePort((msg) { + if (msg is SendPort) { + isolateSendPort.complete(msg); + } else if (msg == 'Blocks created') { + blocksCreated.complete(); + } else if (msg == 'blkKeepAlive destroyed') { + blkKeepAliveDestroyed.complete(); + } + }); + + var isExited = false; + late final RawReceivePort exitPort; + exitPort = RawReceivePort((_) { + isExited = true; + exitPort.close(); + }); + + final isolate = Isolate.spawn((sendPort) { + final blkKeepAlive = + VoidBlock.fromFunction(() {}, keepIsolateAlive: true); + final blkDontKeepAlive = + VoidBlock.fromFunction(() {}, keepIsolateAlive: false); + sendPort.send('Blocks created'); + + final isolatePort = RawReceivePort((msg) { + if (msg == 'Destroy blkKeepAlive') { + blkKeepAlive.ref.release(); + sendPort.send('blkKeepAlive destroyed'); + } + }) + ..keepIsolateAlive = false; + + sendPort.send(isolatePort.sendPort); + }, receivePort.sendPort, onExit: exitPort.sendPort); + + await blocksCreated.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Both blocks are still alive. + expect(isExited, isFalse); + + (await isolateSendPort.future).send('Destroy blkKeepAlive'); + await blkKeepAliveDestroyed.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Only blkDontKeepAlive is alive. + expect(isExited, isTrue); + + receivePort.close(); + }, skip: !canDoGC); + + test('Block.listener, keepIsolateAlive', () async { + final isolateSendPort = Completer(); + final blocksCreated = Completer(); + final blkKeepAliveDestroyed = Completer(); + final receivePort = RawReceivePort((msg) { + if (msg is SendPort) { + isolateSendPort.complete(msg); + } else if (msg == 'Blocks created') { + blocksCreated.complete(); + } else if (msg == 'blkKeepAlive destroyed') { + blkKeepAliveDestroyed.complete(); + } + }); + + var isExited = false; + late final RawReceivePort exitPort; + exitPort = RawReceivePort((_) { + isExited = true; + exitPort.close(); + }); + + final isolate = Isolate.spawn((sendPort) { + final blkKeepAlive = VoidBlock.listener(() {}, keepIsolateAlive: true); + final blkDontKeepAlive = + VoidBlock.listener(() {}, keepIsolateAlive: false); + sendPort.send('Blocks created'); + + final isolatePort = RawReceivePort((msg) { + if (msg == 'Destroy blkKeepAlive') { + blkKeepAlive.ref.release(); + sendPort.send('blkKeepAlive destroyed'); + } + }) + ..keepIsolateAlive = false; + + sendPort.send(isolatePort.sendPort); + }, receivePort.sendPort, onExit: exitPort.sendPort); + + await blocksCreated.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Both blocks are still alive. + expect(isExited, isFalse); + + (await isolateSendPort.future).send('Destroy blkKeepAlive'); + await blkKeepAliveDestroyed.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Only blkDontKeepAlive is alive. + expect(isExited, isTrue); + + receivePort.close(); + }, skip: !canDoGC); + + test('Block.blocking, keepIsolateAlive', () async { + final isolateSendPort = Completer(); + final blocksCreated = Completer(); + final blkKeepAliveDestroyed = Completer(); + final receivePort = RawReceivePort((msg) { + if (msg is SendPort) { + isolateSendPort.complete(msg); + } else if (msg == 'Blocks created') { + blocksCreated.complete(); + } else if (msg == 'blkKeepAlive destroyed') { + blkKeepAliveDestroyed.complete(); + } + }); + + var isExited = false; + late final RawReceivePort exitPort; + exitPort = RawReceivePort((_) { + isExited = true; + exitPort.close(); + }); + + final isolate = Isolate.spawn((sendPort) { + final blkKeepAlive = VoidBlock.blocking(() {}, keepIsolateAlive: true); + final blkDontKeepAlive = + VoidBlock.blocking(() {}, keepIsolateAlive: false); + sendPort.send('Blocks created'); + + final isolatePort = RawReceivePort((msg) { + if (msg == 'Destroy blkKeepAlive') { + blkKeepAlive.ref.release(); + sendPort.send('blkKeepAlive destroyed'); + } + }) + ..keepIsolateAlive = false; + + sendPort.send(isolatePort.sendPort); + }, receivePort.sendPort, onExit: exitPort.sendPort); + + await blocksCreated.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Both blocks are still alive. + expect(isExited, isFalse); + + (await isolateSendPort.future).send('Destroy blkKeepAlive'); + await blkKeepAliveDestroyed.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Only blkDontKeepAlive is alive. + expect(isExited, isTrue); + + receivePort.close(); + }, skip: !canDoGC); }); } diff --git a/pkgs/ffigen/test/native_objc_test/protocol_test.dart b/pkgs/ffigen/test/native_objc_test/protocol_test.dart index f949d4887..8f4a27afe 100644 --- a/pkgs/ffigen/test/native_objc_test/protocol_test.dart +++ b/pkgs/ffigen/test/native_objc_test/protocol_test.dart @@ -8,6 +8,7 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:io'; +import 'dart:isolate'; import 'package:ffi/ffi.dart'; import 'package:objective_c/objective_c.dart'; @@ -379,7 +380,8 @@ void main() { proxyBuilder.implementMethod_withSignature_andBlock_( otherSel, otherSignature, otherBlock.ref.pointer.cast()); - final proxy = DartProxy.newFromBuilder_(proxyBuilder); + final proxy = + DartProxy.newFromBuilder_withDisposePort_(proxyBuilder, 0); final MyProtocol asMyProtocol = MyProtocol.castFrom(proxy); final SecondaryProtocol asSecondaryProtocol = SecondaryProtocol.castFrom(proxy); @@ -404,7 +406,8 @@ void main() { test('Unimplemented method', () { final proxyBuilder = DartProxyBuilder.new1(); final consumer = ProtocolConsumer.new1(); - final proxy = DartProxy.newFromBuilder_(proxyBuilder); + final proxy = + DartProxy.newFromBuilder_withDisposePort_(proxyBuilder, 0); final MyProtocol asMyProtocol = MyProtocol.castFrom(proxy); // Optional instance method, not implemented. @@ -446,7 +449,8 @@ void main() { proxyBuilder.implementMethod_withSignature_andBlock_( sel, signature, block.ref.pointer.cast()); - final proxy = DartProxy.newFromBuilder_(proxyBuilder); + final proxy = + DartProxy.newFromBuilder_withDisposePort_(proxyBuilder, 0); final proxyPtr = proxy.ref.pointer; final blockPtr = block.ref.pointer; @@ -539,5 +543,68 @@ void main() { expect(EmptyProtocol.conformsTo(inst), isFalse); expect(UnusedProtocol.conformsTo(inst), isFalse); }); + + test('keepIsolateAlive', () async { + final isolateSendPort = Completer(); + final protosCreated = Completer(); + final protoKeepAliveDestroyed = Completer(); + final receivePort = RawReceivePort((msg) { + if (msg is SendPort) { + isolateSendPort.complete(msg); + } else if (msg == 'Protocols created') { + protosCreated.complete(); + } else if (msg == 'protoKeepAlive destroyed') { + protoKeepAliveDestroyed.complete(); + } + }); + + var isExited = false; + late final RawReceivePort exitPort; + exitPort = RawReceivePort((_) { + isExited = true; + exitPort.close(); + }); + + final isolate = Isolate.spawn((sendPort) { + final protoKeepAlive = + ObjCProtocolBuilder().build(keepIsolateAlive: true); + final protoDontKeepAlive = + ObjCProtocolBuilder().build(keepIsolateAlive: false); + sendPort.send('Protocols created'); + + final isolatePort = RawReceivePort((msg) { + if (msg == 'Destroy protoKeepAlive') { + protoKeepAlive.ref.release(); + sendPort.send('protoKeepAlive destroyed'); + } + }) + ..keepIsolateAlive = false; + + sendPort.send(isolatePort.sendPort); + }, receivePort.sendPort, onExit: exitPort.sendPort); + + await protosCreated.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Both blocks are still alive. + expect(isExited, isFalse); + + (await isolateSendPort.future).send('Destroy protoKeepAlive'); + await protoKeepAliveDestroyed.future; + + doGC(); + await Future.delayed(Duration.zero); // Let dispose message arrive. + doGC(); + await Future.delayed(Duration.zero); // Let exit message arrive. + + // Only protoDontKeepAlive is alive. + expect(isExited, isTrue); + + receivePort.close(); + }, skip: !canDoGC); }); } diff --git a/pkgs/objective_c/CHANGELOG.md b/pkgs/objective_c/CHANGELOG.md index 7fee7a54e..983ee4cf4 100644 --- a/pkgs/objective_c/CHANGELOG.md +++ b/pkgs/objective_c/CHANGELOG.md @@ -1,3 +1,7 @@ +## 7.0.0-wip + +- Use ffigen 18.0.0 + ## 6.0.0 - Use ffigen 17.0.0 diff --git a/pkgs/objective_c/ffigen_c.yaml b/pkgs/objective_c/ffigen_c.yaml index c1861c194..022ee7ecc 100644 --- a/pkgs/objective_c/ffigen_c.yaml +++ b/pkgs/objective_c/ffigen_c.yaml @@ -70,6 +70,9 @@ structs: rename: '_ObjC(.*)': 'ObjC$1' '_Dart_FinalizableHandle': 'Dart_FinalizableHandle_' +macros: + include: + - 'ILLEGAL_PORT' preamble: | // Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a diff --git a/pkgs/objective_c/lib/src/c_bindings_generated.dart b/pkgs/objective_c/lib/src/c_bindings_generated.dart index 2ee9adbd7..bdd63b847 100644 --- a/pkgs/objective_c/lib/src/c_bindings_generated.dart +++ b/pkgs/objective_c/lib/src/c_bindings_generated.dart @@ -203,6 +203,8 @@ typedef Dart_FinalizableHandle = ffi.Pointer; final class Dart_FinalizableHandle_ extends ffi.Opaque {} +const int ILLEGAL_PORT = 0; + final class ObjCBlockDesc extends ffi.Struct { @ffi.UnsignedLong() external int reserved; diff --git a/pkgs/objective_c/lib/src/internal.dart b/pkgs/objective_c/lib/src/internal.dart index 01a96f328..1a1d4f97d 100644 --- a/pkgs/objective_c/lib/src/internal.dart +++ b/pkgs/objective_c/lib/src/internal.dart @@ -389,18 +389,24 @@ BlockPtr _newBlock(VoidPtr invoke, VoidPtr target, const int _blockHasCopyDispose = 1 << 25; /// Only for use by ffigen bindings. -BlockPtr newClosureBlock(VoidPtr invoke, Function fn) => _newBlock( - invoke, - _registerBlockClosure(fn), - _closureBlockDesc, - _blockClosureDisposer.sendPort.nativePort, - _blockHasCopyDispose); +BlockPtr newClosureBlock(VoidPtr invoke, Function fn, bool keepIsolateAlive) => + _newBlock( + invoke, + _registerBlockClosure(fn, keepIsolateAlive), + _closureBlockDesc, + _blockClosureDisposer.sendPort.nativePort, + _blockHasCopyDispose); /// Only for use by ffigen bindings. BlockPtr newPointerBlock(VoidPtr invoke, VoidPtr target) => _newBlock(invoke, target, _pointerBlockDesc, 0, 0); -final _blockClosureRegistry = {}; +typedef _RegEntry = ({ + Function closure, + RawReceivePort? keepAlivePort, +}); + +final _blockClosureRegistry = {}; int _blockClosureRegistryLastId = 0; @@ -409,15 +415,19 @@ final _blockClosureDisposer = () { return RawReceivePort((dynamic msg) { final id = msg as int; assert(_blockClosureRegistry.containsKey(id)); - _blockClosureRegistry.remove(id); + final entry = _blockClosureRegistry.remove(id)!; + entry.keepAlivePort?.close(); }, 'ObjCBlockClosureDisposer') ..keepIsolateAlive = false; }(); -VoidPtr _registerBlockClosure(Function closure) { +VoidPtr _registerBlockClosure(Function closure, bool keepIsolateAlive) { ++_blockClosureRegistryLastId; assert(!_blockClosureRegistry.containsKey(_blockClosureRegistryLastId)); - _blockClosureRegistry[_blockClosureRegistryLastId] = closure; + _blockClosureRegistry[_blockClosureRegistryLastId] = ( + closure: closure, + keepAlivePort: keepIsolateAlive ? RawReceivePort() : null, + ); return VoidPtr.fromAddress(_blockClosureRegistryLastId); } @@ -425,7 +435,7 @@ VoidPtr _registerBlockClosure(Function closure) { Function getBlockClosure(BlockPtr block) { var id = block.ref.target.address; assert(_blockClosureRegistry.containsKey(id)); - return _blockClosureRegistry[id]!; + return _blockClosureRegistry[id]!.closure; } typedef NewWaiterFn = NativeFunction; diff --git a/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart b/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart index 560c1e0ef..42c43d59f 100644 --- a/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart +++ b/pkgs/objective_c/lib/src/objective_c_bindings_generated.dart @@ -309,10 +309,11 @@ class DartProxy extends NSProxy { return objc.ObjCObjectBase(_ret, retain: false, release: true); } - /// newFromBuilder: - static DartProxy newFromBuilder_(DartProxyBuilder builder) { - final _ret = _objc_msgSend_1sotr3r( - _class_DOBJCDartProxy, _sel_newFromBuilder_, builder.ref.pointer); + /// newFromBuilder:withDisposePort: + static DartProxy newFromBuilder_withDisposePort_( + DartProxyBuilder builder, int port) { + final _ret = _objc_msgSend_dbvvll(_class_DOBJCDartProxy, + _sel_newFromBuilder_withDisposePort_, builder.ref.pointer, port); return DartProxy.castFromPointer(_ret, retain: false, release: true); } @@ -322,16 +323,22 @@ class DartProxy extends NSProxy { return DartProxy.castFromPointer(_ret, retain: true, release: true); } + /// dealloc + void dealloc() { + _objc_msgSend_1pl9qdv(this.ref.pointer, _sel_dealloc); + } + /// forwardInvocation: void forwardInvocation_(NSInvocation invocation) { _objc_msgSend_xtuoz7( this.ref.pointer, _sel_forwardInvocation_, invocation.ref.pointer); } - /// initFromBuilder: - DartProxy initFromBuilder_(DartProxyBuilder builder) { - final _ret = _objc_msgSend_1sotr3r(this.ref.retainAndReturnPointer(), - _sel_initFromBuilder_, builder.ref.pointer); + /// initFromBuilder:withDisposePort: + DartProxy initFromBuilder_withDisposePort_( + DartProxyBuilder builder, int port) { + final _ret = _objc_msgSend_dbvvll(this.ref.retainAndReturnPointer(), + _sel_initFromBuilder_withDisposePort_, builder.ref.pointer, port); return DartProxy.castFromPointer(_ret, retain: false, release: true); } @@ -926,20 +933,26 @@ interface class NSCoding extends objc.ObjCProtocolBase { /// Builds an object that implements the NSCoding protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSCoding implement( {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSCoding.encodeWithCoder_.implement(builder, encodeWithCoder_); NSCoding.initWithCoder_.implement(builder, initWithCoder_); - return NSCoding.castFrom(builder.build()); + return NSCoding.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSCoding protocol to an existing /// [objc.ObjCProtocolBuilder]. static void addToBuilder(objc.ObjCProtocolBuilder builder, {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { NSCoding.encodeWithCoder_.implement(builder, encodeWithCoder_); NSCoding.initWithCoder_.implement(builder, initWithCoder_); } @@ -947,13 +960,18 @@ interface class NSCoding extends objc.ObjCProtocolBase { /// Builds an object that implements the NSCoding protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSCoding implementAsListener( {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSCoding.encodeWithCoder_.implementAsListener(builder, encodeWithCoder_); NSCoding.initWithCoder_.implement(builder, initWithCoder_); - return NSCoding.castFrom(builder.build()); + return NSCoding.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSCoding protocol to an existing @@ -961,7 +979,8 @@ interface class NSCoding extends objc.ObjCProtocolBase { /// be. static void addToBuilderAsListener(objc.ObjCProtocolBuilder builder, {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { NSCoding.encodeWithCoder_.implementAsListener(builder, encodeWithCoder_); NSCoding.initWithCoder_.implement(builder, initWithCoder_); } @@ -969,13 +988,18 @@ interface class NSCoding extends objc.ObjCProtocolBase { /// Builds an object that implements the NSCoding protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as blocking listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSCoding implementAsBlocking( {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSCoding.encodeWithCoder_.implementAsBlocking(builder, encodeWithCoder_); NSCoding.initWithCoder_.implement(builder, initWithCoder_); - return NSCoding.castFrom(builder.build()); + return NSCoding.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSCoding protocol to an existing @@ -983,7 +1007,8 @@ interface class NSCoding extends objc.ObjCProtocolBase { /// listeners will be. static void addToBuilderAsBlocking(objc.ObjCProtocolBuilder builder, {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { NSCoding.encodeWithCoder_.implementAsBlocking(builder, encodeWithCoder_); NSCoding.initWithCoder_.implement(builder, initWithCoder_); } @@ -1065,19 +1090,23 @@ interface class NSCopying extends objc.ObjCProtocolBase { /// Builds an object that implements the NSCopying protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSCopying implement( - {required objc.ObjCObjectBase Function(ffi.Pointer) - copyWithZone_}) { + {required objc.ObjCObjectBase Function(ffi.Pointer) copyWithZone_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSCopying.copyWithZone_.implement(builder, copyWithZone_); - return NSCopying.castFrom(builder.build()); + return NSCopying.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSCopying protocol to an existing /// [objc.ObjCProtocolBuilder]. static void addToBuilder(objc.ObjCProtocolBuilder builder, - {required objc.ObjCObjectBase Function(ffi.Pointer) - copyWithZone_}) { + {required objc.ObjCObjectBase Function(ffi.Pointer) copyWithZone_, + bool $keepIsolateAlive = true}) { NSCopying.copyWithZone_.implement(builder, copyWithZone_); } @@ -3393,14 +3422,19 @@ interface class NSFastEnumeration extends objc.ObjCProtocolBase { /// Builds an object that implements the NSFastEnumeration protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSFastEnumeration implement( {required int Function(ffi.Pointer, ffi.Pointer>, int) - countByEnumeratingWithState_objects_count_}) { + countByEnumeratingWithState_objects_count_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSFastEnumeration.countByEnumeratingWithState_objects_count_ .implement(builder, countByEnumeratingWithState_objects_count_); - return NSFastEnumeration.castFrom(builder.build()); + return NSFastEnumeration.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSFastEnumeration protocol to an existing @@ -3408,7 +3442,8 @@ interface class NSFastEnumeration extends objc.ObjCProtocolBase { static void addToBuilder(objc.ObjCProtocolBuilder builder, {required int Function(ffi.Pointer, ffi.Pointer>, int) - countByEnumeratingWithState_objects_count_}) { + countByEnumeratingWithState_objects_count_, + bool $keepIsolateAlive = true}) { NSFastEnumeration.countByEnumeratingWithState_objects_count_ .implement(builder, countByEnumeratingWithState_objects_count_); } @@ -4002,17 +4037,20 @@ interface class NSItemProviderReading extends objc.ObjCProtocolBase /// Builds an object that implements the NSItemProviderReading protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. - static NSItemProviderReading implement() { + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. + static NSItemProviderReading implement({bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); - return NSItemProviderReading.castFrom(builder.build()); + return NSItemProviderReading.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSItemProviderReading protocol to an existing /// [objc.ObjCProtocolBuilder]. - static void addToBuilder( - objc.ObjCProtocolBuilder builder, - ) {} + static void addToBuilder(objc.ObjCProtocolBuilder builder, + {bool $keepIsolateAlive = true}) {} } enum NSItemProviderRepresentationVisibility { @@ -4059,10 +4097,14 @@ interface class NSItemProviderWriting extends objc.ObjCProtocolBase /// Builds an object that implements the NSItemProviderWriting protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSItemProviderWriting implement( {NSItemProviderRepresentationVisibility Function(NSString)? itemProviderVisibilityForRepresentationWithTypeIdentifier_, - NSArray Function()? writableTypeIdentifiersForItemProvider}) { + NSArray Function()? writableTypeIdentifiersForItemProvider, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSItemProviderWriting .itemProviderVisibilityForRepresentationWithTypeIdentifier_ @@ -4070,7 +4112,8 @@ interface class NSItemProviderWriting extends objc.ObjCProtocolBase itemProviderVisibilityForRepresentationWithTypeIdentifier_); NSItemProviderWriting.writableTypeIdentifiersForItemProvider .implement(builder, writableTypeIdentifiersForItemProvider); - return NSItemProviderWriting.castFrom(builder.build()); + return NSItemProviderWriting.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSItemProviderWriting protocol to an existing @@ -4078,7 +4121,8 @@ interface class NSItemProviderWriting extends objc.ObjCProtocolBase static void addToBuilder(objc.ObjCProtocolBuilder builder, {NSItemProviderRepresentationVisibility Function(NSString)? itemProviderVisibilityForRepresentationWithTypeIdentifier_, - NSArray Function()? writableTypeIdentifiersForItemProvider}) { + NSArray Function()? writableTypeIdentifiersForItemProvider, + bool $keepIsolateAlive = true}) { NSItemProviderWriting .itemProviderVisibilityForRepresentationWithTypeIdentifier_ .implement(builder, @@ -4491,20 +4535,26 @@ interface class NSMutableCopying extends objc.ObjCProtocolBase { /// Builds an object that implements the NSMutableCopying protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSMutableCopying implement( {required objc.ObjCObjectBase Function(ffi.Pointer) - mutableCopyWithZone_}) { + mutableCopyWithZone_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSMutableCopying.mutableCopyWithZone_ .implement(builder, mutableCopyWithZone_); - return NSMutableCopying.castFrom(builder.build()); + return NSMutableCopying.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSMutableCopying protocol to an existing /// [objc.ObjCProtocolBuilder]. static void addToBuilder(objc.ObjCProtocolBuilder builder, {required objc.ObjCObjectBase Function(ffi.Pointer) - mutableCopyWithZone_}) { + mutableCopyWithZone_, + bool $keepIsolateAlive = true}) { NSMutableCopying.mutableCopyWithZone_ .implement(builder, mutableCopyWithZone_); } @@ -7175,6 +7225,9 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { /// Builds an object that implements the NSObject protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSObjectProtocol implement( {required objc.ObjCObjectBase Function() autorelease, required objc.ObjCObjectBase Function() class1, @@ -7201,7 +7254,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { required int Function() retainCount, required objc.ObjCObjectBase Function() self1, required objc.ObjCObjectBase Function() superclass, - required ffi.Pointer Function() zone}) { + required ffi.Pointer Function() zone, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSObjectProtocol.autorelease.implement(builder, autorelease); NSObjectProtocol.class1.implement(builder, class1); @@ -7227,7 +7281,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { NSObjectProtocol.self1.implement(builder, self1); NSObjectProtocol.superclass.implement(builder, superclass); NSObjectProtocol.zone.implement(builder, zone); - return NSObjectProtocol.castFrom(builder.build()); + return NSObjectProtocol.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSObject protocol to an existing @@ -7258,7 +7313,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { required int Function() retainCount, required objc.ObjCObjectBase Function() self1, required objc.ObjCObjectBase Function() superclass, - required ffi.Pointer Function() zone}) { + required ffi.Pointer Function() zone, + bool $keepIsolateAlive = true}) { NSObjectProtocol.autorelease.implement(builder, autorelease); NSObjectProtocol.class1.implement(builder, class1); NSObjectProtocol.conformsToProtocol_ @@ -7288,6 +7344,9 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { /// Builds an object that implements the NSObject protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSObjectProtocol implementAsListener( {required objc.ObjCObjectBase Function() autorelease, required objc.ObjCObjectBase Function() class1, @@ -7314,7 +7373,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { required int Function() retainCount, required objc.ObjCObjectBase Function() self1, required objc.ObjCObjectBase Function() superclass, - required ffi.Pointer Function() zone}) { + required ffi.Pointer Function() zone, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSObjectProtocol.autorelease.implement(builder, autorelease); NSObjectProtocol.class1.implement(builder, class1); @@ -7340,7 +7400,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { NSObjectProtocol.self1.implement(builder, self1); NSObjectProtocol.superclass.implement(builder, superclass); NSObjectProtocol.zone.implement(builder, zone); - return NSObjectProtocol.castFrom(builder.build()); + return NSObjectProtocol.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSObject protocol to an existing @@ -7372,7 +7433,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { required int Function() retainCount, required objc.ObjCObjectBase Function() self1, required objc.ObjCObjectBase Function() superclass, - required ffi.Pointer Function() zone}) { + required ffi.Pointer Function() zone, + bool $keepIsolateAlive = true}) { NSObjectProtocol.autorelease.implement(builder, autorelease); NSObjectProtocol.class1.implement(builder, class1); NSObjectProtocol.conformsToProtocol_ @@ -7402,6 +7464,9 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { /// Builds an object that implements the NSObject protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as blocking listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSObjectProtocol implementAsBlocking( {required objc.ObjCObjectBase Function() autorelease, required objc.ObjCObjectBase Function() class1, @@ -7428,7 +7493,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { required int Function() retainCount, required objc.ObjCObjectBase Function() self1, required objc.ObjCObjectBase Function() superclass, - required ffi.Pointer Function() zone}) { + required ffi.Pointer Function() zone, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSObjectProtocol.autorelease.implement(builder, autorelease); NSObjectProtocol.class1.implement(builder, class1); @@ -7454,7 +7520,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { NSObjectProtocol.self1.implement(builder, self1); NSObjectProtocol.superclass.implement(builder, superclass); NSObjectProtocol.zone.implement(builder, zone); - return NSObjectProtocol.castFrom(builder.build()); + return NSObjectProtocol.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSObject protocol to an existing @@ -7486,7 +7553,8 @@ interface class NSObjectProtocol extends objc.ObjCProtocolBase { required int Function() retainCount, required objc.ObjCObjectBase Function() self1, required objc.ObjCObjectBase Function() superclass, - required ffi.Pointer Function() zone}) { + required ffi.Pointer Function() zone, + bool $keepIsolateAlive = true}) { NSObjectProtocol.autorelease.implement(builder, autorelease); NSObjectProtocol.class1.implement(builder, class1); NSObjectProtocol.conformsToProtocol_ @@ -8722,20 +8790,26 @@ interface class NSSecureCoding extends objc.ObjCProtocolBase /// Builds an object that implements the NSSecureCoding protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSSecureCoding implement( {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSSecureCoding.encodeWithCoder_.implement(builder, encodeWithCoder_); NSSecureCoding.initWithCoder_.implement(builder, initWithCoder_); - return NSSecureCoding.castFrom(builder.build()); + return NSSecureCoding.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSSecureCoding protocol to an existing /// [objc.ObjCProtocolBuilder]. static void addToBuilder(objc.ObjCProtocolBuilder builder, {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { NSSecureCoding.encodeWithCoder_.implement(builder, encodeWithCoder_); NSSecureCoding.initWithCoder_.implement(builder, initWithCoder_); } @@ -8743,14 +8817,19 @@ interface class NSSecureCoding extends objc.ObjCProtocolBase /// Builds an object that implements the NSSecureCoding protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSSecureCoding implementAsListener( {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSSecureCoding.encodeWithCoder_ .implementAsListener(builder, encodeWithCoder_); NSSecureCoding.initWithCoder_.implement(builder, initWithCoder_); - return NSSecureCoding.castFrom(builder.build()); + return NSSecureCoding.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSSecureCoding protocol to an existing @@ -8758,7 +8837,8 @@ interface class NSSecureCoding extends objc.ObjCProtocolBase /// be. static void addToBuilderAsListener(objc.ObjCProtocolBuilder builder, {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { NSSecureCoding.encodeWithCoder_ .implementAsListener(builder, encodeWithCoder_); NSSecureCoding.initWithCoder_.implement(builder, initWithCoder_); @@ -8767,14 +8847,19 @@ interface class NSSecureCoding extends objc.ObjCProtocolBase /// Builds an object that implements the NSSecureCoding protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as blocking listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSSecureCoding implementAsBlocking( {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSSecureCoding.encodeWithCoder_ .implementAsBlocking(builder, encodeWithCoder_); NSSecureCoding.initWithCoder_.implement(builder, initWithCoder_); - return NSSecureCoding.castFrom(builder.build()); + return NSSecureCoding.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSSecureCoding protocol to an existing @@ -8782,7 +8867,8 @@ interface class NSSecureCoding extends objc.ObjCProtocolBase /// listeners will be. static void addToBuilderAsBlocking(objc.ObjCProtocolBuilder builder, {required void Function(NSCoder) encodeWithCoder_, - required Dartinstancetype? Function(NSCoder) initWithCoder_}) { + required Dartinstancetype? Function(NSCoder) initWithCoder_, + bool $keepIsolateAlive = true}) { NSSecureCoding.encodeWithCoder_ .implementAsBlocking(builder, encodeWithCoder_); NSSecureCoding.initWithCoder_.implement(builder, initWithCoder_); @@ -9173,18 +9259,24 @@ interface class NSStreamDelegate extends objc.ObjCProtocolBase /// Builds an object that implements the NSStreamDelegate protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSStreamDelegate implement( - {void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) { + {void Function(NSStream, NSStreamEvent)? stream_handleEvent_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSStreamDelegate.stream_handleEvent_ .implement(builder, stream_handleEvent_); - return NSStreamDelegate.castFrom(builder.build()); + return NSStreamDelegate.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSStreamDelegate protocol to an existing /// [objc.ObjCProtocolBuilder]. static void addToBuilder(objc.ObjCProtocolBuilder builder, - {void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) { + {void Function(NSStream, NSStreamEvent)? stream_handleEvent_, + bool $keepIsolateAlive = true}) { NSStreamDelegate.stream_handleEvent_ .implement(builder, stream_handleEvent_); } @@ -9192,19 +9284,25 @@ interface class NSStreamDelegate extends objc.ObjCProtocolBase /// Builds an object that implements the NSStreamDelegate protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSStreamDelegate implementAsListener( - {void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) { + {void Function(NSStream, NSStreamEvent)? stream_handleEvent_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSStreamDelegate.stream_handleEvent_ .implementAsListener(builder, stream_handleEvent_); - return NSStreamDelegate.castFrom(builder.build()); + return NSStreamDelegate.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSStreamDelegate protocol to an existing /// [objc.ObjCProtocolBuilder]. All methods that can be implemented as listeners will /// be. static void addToBuilderAsListener(objc.ObjCProtocolBuilder builder, - {void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) { + {void Function(NSStream, NSStreamEvent)? stream_handleEvent_, + bool $keepIsolateAlive = true}) { NSStreamDelegate.stream_handleEvent_ .implementAsListener(builder, stream_handleEvent_); } @@ -9212,19 +9310,25 @@ interface class NSStreamDelegate extends objc.ObjCProtocolBase /// Builds an object that implements the NSStreamDelegate protocol. To implement /// multiple protocols, use [addToBuilder] or [objc.ObjCProtocolBuilder] directly. All /// methods that can be implemented as blocking listeners will be. + /// + /// If `$keepIsolateAlive` is true, this protocol will keep this isolate + /// alive until it is garbage collected by both Dart and ObjC. static NSStreamDelegate implementAsBlocking( - {void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) { + {void Function(NSStream, NSStreamEvent)? stream_handleEvent_, + bool $keepIsolateAlive = true}) { final builder = objc.ObjCProtocolBuilder(); NSStreamDelegate.stream_handleEvent_ .implementAsBlocking(builder, stream_handleEvent_); - return NSStreamDelegate.castFrom(builder.build()); + return NSStreamDelegate.castFrom( + builder.build(keepIsolateAlive: $keepIsolateAlive)); } /// Adds the implementation of the NSStreamDelegate protocol to an existing /// [objc.ObjCProtocolBuilder]. All methods that can be implemented as blocking /// listeners will be. static void addToBuilderAsBlocking(objc.ObjCProtocolBuilder builder, - {void Function(NSStream, NSStreamEvent)? stream_handleEvent_}) { + {void Function(NSStream, NSStreamEvent)? stream_handleEvent_, + bool $keepIsolateAlive = true}) { NSStreamDelegate.stream_handleEvent_ .implementAsBlocking(builder, stream_handleEvent_); } @@ -11717,13 +11821,18 @@ abstract final class ObjCBlock_NSArray_ffiVoid { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock)> fromFunction( - NSArray Function(ffi.Pointer) fn) => + NSArray Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock)>( objc.newClosureBlock( _ObjCBlock_NSArray_ffiVoid_closureCallable, (ffi.Pointer arg0) => - fn(arg0).ref.retainAndAutorelease()), + fn(arg0).ref.retainAndAutorelease(), + keepIsolateAlive), retain: false, release: true); } @@ -11814,16 +11923,20 @@ abstract final class ObjCBlock_NSItemProviderRepresentationVisibility_ffiVoid_NS /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock, NSString)> fromFunction( NSItemProviderRepresentationVisibility Function( ffi.Pointer, NSString) - fn) => + fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock, NSString)>( objc.newClosureBlock( _ObjCBlock_NSItemProviderRepresentationVisibility_ffiVoid_NSString_closureCallable, (ffi.Pointer arg0, ffi.Pointer arg1) => - fn(arg0, NSString.castFromPointer(arg1, retain: true, release: true)) - .value), + fn(arg0, NSString.castFromPointer(arg1, retain: true, release: true)).value, + keepIsolateAlive), retain: false, release: true); } @@ -11904,13 +12017,18 @@ abstract final class ObjCBlock_NSString_ffiVoid { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock)> fromFunction( - NSString Function(ffi.Pointer) fn) => + NSString Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock)>( objc.newClosureBlock( _ObjCBlock_NSString_ffiVoid_closureCallable, (ffi.Pointer arg0) => - fn(arg0).ref.retainAndAutorelease()), + fn(arg0).ref.retainAndAutorelease(), + keepIsolateAlive), retain: false, release: true); } @@ -11989,12 +12107,17 @@ abstract final class ObjCBlock_NSUInteger_ffiVoid { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock)> - fromFunction(int Function(ffi.Pointer) fn) => + fromFunction(int Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock)>( objc.newClosureBlock( _ObjCBlock_NSUInteger_ffiVoid_closureCallable, - (ffi.Pointer arg0) => fn(arg0)), + (ffi.Pointer arg0) => fn(arg0), + keepIsolateAlive), retain: false, release: true); } @@ -12113,19 +12236,24 @@ abstract final class ObjCBlock_NSUInteger_ffiVoid_NSFastEnumerationState_objcObj /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc.ObjCBlock< - ffi.UnsignedLong Function( - ffi.Pointer, - ffi.Pointer, - ffi.Pointer>, - ffi.UnsignedLong)> fromFunction(int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer>, int) fn) => - objc.ObjCBlock, ffi.Pointer, ffi.Pointer>, ffi.UnsignedLong)>( - objc.newClosureBlock( - _ObjCBlock_NSUInteger_ffiVoid_NSFastEnumerationState_objcObjCObject_NSUInteger_closureCallable, - (ffi.Pointer arg0, ffi.Pointer arg1, ffi.Pointer> arg2, int arg3) => - fn(arg0, arg1, arg2, arg3)), - retain: false, - release: true); + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc + .ObjCBlock, ffi.Pointer, ffi.Pointer>, ffi.UnsignedLong)> + fromFunction(int Function(ffi.Pointer, ffi.Pointer, ffi.Pointer>, int) fn, + {bool keepIsolateAlive = true}) => + objc.ObjCBlock, ffi.Pointer, ffi.Pointer>, ffi.UnsignedLong)>( + objc.newClosureBlock( + _ObjCBlock_NSUInteger_ffiVoid_NSFastEnumerationState_objcObjCObject_NSUInteger_closureCallable, + (ffi.Pointer arg0, + ffi.Pointer arg1, + ffi.Pointer> arg2, + int arg3) => + fn(arg0, arg1, arg2, arg3), + keepIsolateAlive), + retain: false, + release: true); } /// Call operator for `objc.ObjCBlock, ffi.Pointer, ffi.Pointer>, ffi.UnsignedLong)>`. @@ -12214,11 +12342,15 @@ abstract final class ObjCBlock_NSZone_ffiVoid { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock Function(ffi.Pointer)> - fromFunction(ffi.Pointer Function(ffi.Pointer) fn) => + fromFunction(ffi.Pointer Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock Function(ffi.Pointer)>( objc.newClosureBlock(_ObjCBlock_NSZone_ffiVoid_closureCallable, - (ffi.Pointer arg0) => fn(arg0)), + (ffi.Pointer arg0) => fn(arg0), keepIsolateAlive), retain: false, release: true); } @@ -12289,11 +12421,15 @@ abstract final class ObjCBlock_bool_ffiVoid { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock)> fromFunction( - bool Function(ffi.Pointer) fn) => + bool Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock)>( objc.newClosureBlock(_ObjCBlock_bool_ffiVoid_closureCallable, - (ffi.Pointer arg0) => fn(arg0)), + (ffi.Pointer arg0) => fn(arg0), keepIsolateAlive), retain: false, release: true); } @@ -12375,18 +12511,21 @@ abstract final class ObjCBlock_bool_ffiVoid_Protocol { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc.ObjCBlock, Protocol)> - fromFunction(bool Function(ffi.Pointer, Protocol) fn) => - objc.ObjCBlock, Protocol)>( - objc.newClosureBlock( - _ObjCBlock_bool_ffiVoid_Protocol_closureCallable, - (ffi.Pointer arg0, ffi.Pointer arg1) => - fn( - arg0, - Protocol.castFromPointer(arg1, - retain: true, release: true))), - retain: false, - release: true); + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc.ObjCBlock< + ffi.Bool Function(ffi.Pointer, Protocol)> fromFunction( + bool Function(ffi.Pointer, Protocol) fn, + {bool keepIsolateAlive = true}) => + objc.ObjCBlock, Protocol)>( + objc.newClosureBlock( + _ObjCBlock_bool_ffiVoid_Protocol_closureCallable, + (ffi.Pointer arg0, ffi.Pointer arg1) => + fn(arg0, Protocol.castFromPointer(arg1, retain: true, release: true)), + keepIsolateAlive), + retain: false, + release: true); } /// Call operator for `objc.ObjCBlock, Protocol)>`. @@ -12472,18 +12611,21 @@ abstract final class ObjCBlock_bool_ffiVoid_objcObjCObject { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc.ObjCBlock, ffi.Pointer)> - fromFunction( - bool Function(ffi.Pointer, objc.ObjCObjectBase) fn) => - objc.ObjCBlock< - ffi.Bool Function( - ffi.Pointer, ffi.Pointer)>( - objc.newClosureBlock( - _ObjCBlock_bool_ffiVoid_objcObjCObject_closureCallable, - (ffi.Pointer arg0, ffi.Pointer arg1) => - fn(arg0, objc.ObjCObjectBase(arg1, retain: true, release: true))), - retain: false, - release: true); + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc.ObjCBlock< + ffi.Bool Function(ffi.Pointer, ffi.Pointer)> fromFunction( + bool Function(ffi.Pointer, objc.ObjCObjectBase) fn, + {bool keepIsolateAlive = true}) => + objc.ObjCBlock, ffi.Pointer)>( + objc.newClosureBlock( + _ObjCBlock_bool_ffiVoid_objcObjCObject_closureCallable, + (ffi.Pointer arg0, ffi.Pointer arg1) => + fn(arg0, objc.ObjCObjectBase(arg1, retain: true, release: true)), + keepIsolateAlive), + retain: false, + release: true); } /// Call operator for `objc.ObjCBlock, ffi.Pointer)>`. @@ -12570,16 +12712,19 @@ abstract final class ObjCBlock_bool_ffiVoid_objcObjCSelector { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc - .ObjCBlock, ffi.Pointer)> - fromFunction(bool Function(ffi.Pointer, ffi.Pointer) fn) => - objc.ObjCBlock< - ffi.Bool Function( - ffi.Pointer, ffi.Pointer)>( + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc.ObjCBlock< + ffi.Bool Function(ffi.Pointer, ffi.Pointer)> + fromFunction(bool Function(ffi.Pointer, ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => + objc.ObjCBlock, ffi.Pointer)>( objc.newClosureBlock( _ObjCBlock_bool_ffiVoid_objcObjCSelector_closureCallable, (ffi.Pointer arg0, ffi.Pointer arg1) => - fn(arg0, arg1)), + fn(arg0, arg1), + keepIsolateAlive), retain: false, release: true); } @@ -12773,18 +12918,20 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock?, NSError)>, ffi.Pointer, NSDictionary)> - fromFunction(void Function(objc.ObjCBlock?, NSError)>, objc.ObjCObjectBase, NSDictionary) fn) => + fromFunction(void Function(objc.ObjCBlock?, NSError)>, objc.ObjCObjectBase, NSDictionary) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock?, NSError)>, ffi.Pointer, NSDictionary)>( objc.newClosureBlock( _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_closureCallable, - (ffi.Pointer arg0, - ffi.Pointer arg1, - ffi.Pointer arg2) => - fn( - ObjCBlock_ffiVoid_idNSSecureCoding_NSError.castFromPointer(arg0, retain: true, release: true), - objc.ObjCObjectBase(arg1, retain: true, release: true), - NSDictionary.castFromPointer(arg2, retain: true, release: true))), + (ffi.Pointer arg0, ffi.Pointer arg1, ffi.Pointer arg2) => fn( + ObjCBlock_ffiVoid_idNSSecureCoding_NSError.castFromPointer(arg0, retain: true, release: true), + objc.ObjCObjectBase(arg1, retain: true, release: true), + NSDictionary.castFromPointer(arg2, retain: true, release: true)), + keepIsolateAlive), retain: false, release: true); @@ -12795,8 +12942,8 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO /// but only supports void functions, and is not run synchronously. See /// NativeCallable.listener for more details. /// - /// Note that unlike the default behavior of NativeCallable.listener, listener - /// blocks do not keep the isolate alive. + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock< ffi.Void Function( objc.ObjCBlock< @@ -12808,7 +12955,8 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO ffi.Void Function(ffi.Pointer?, NSError)>, objc.ObjCObjectBase, NSDictionary) - fn) { + fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_listenerCallable .nativeFunction @@ -12821,7 +12969,8 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO retain: false, release: true), objc.ObjCObjectBase(arg1, retain: false, release: true), NSDictionary.castFromPointer(arg2, - retain: false, release: true))); + retain: false, release: true)), + keepIsolateAlive); final wrapper = _ObjectiveCBindings_wrapListenerBlock_1b3bb6a(raw); objc.objectRelease(raw.cast()); return objc.ObjCBlock< @@ -12838,8 +12987,9 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO /// caller until the callback is handled by the Dart isolate that created /// the block. Async functions are not supported. /// - /// This block does not keep the owner isolate alive. If the owner isolate has - /// shut down, and the block is invoked by native code, it may block + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. If the owner isolate + /// has shut down, and the block is invoked by native code, it may block /// indefinitely, or have other undefined behavior. static objc.ObjCBlock< ffi.Void Function( @@ -12852,7 +13002,8 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO ffi.Void Function(ffi.Pointer?, NSError)>, objc.ObjCObjectBase, NSDictionary) - fn) { + fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_blockingCallable .nativeFunction @@ -12865,7 +13016,8 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO retain: false, release: true), objc.ObjCObjectBase(arg1, retain: false, release: true), NSDictionary.castFromPointer(arg2, - retain: false, release: true))); + retain: false, release: true)), + keepIsolateAlive); final rawListener = objc.newClosureBlock( _ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCObject_NSDictionary_blockingListenerCallable .nativeFunction @@ -12878,7 +13030,8 @@ abstract final class ObjCBlock_ffiVoid_NSItemProviderCompletionHandler_objcObjCO retain: false, release: true), objc.ObjCObjectBase(arg1, retain: false, release: true), NSDictionary.castFromPointer(arg2, - retain: false, release: true))); + retain: false, release: true)), + keepIsolateAlive); final wrapper = objc.wrapBlockingBlock( _ObjectiveCBindings_wrapBlockingBlock_1b3bb6a, raw, rawListener); objc.objectRelease(raw.cast()); @@ -13017,11 +13170,15 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock)> fromFunction( - void Function(ffi.Pointer) fn) => + void Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock)>( objc.newClosureBlock(_ObjCBlock_ffiVoid_ffiVoid_closureCallable, - (ffi.Pointer arg0) => fn(arg0)), + (ffi.Pointer arg0) => fn(arg0), keepIsolateAlive), retain: false, release: true); @@ -13032,13 +13189,15 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid { /// but only supports void functions, and is not run synchronously. See /// NativeCallable.listener for more details. /// - /// Note that unlike the default behavior of NativeCallable.listener, listener - /// blocks do not keep the isolate alive. + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock)> listener( - void Function(ffi.Pointer) fn) { + void Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_listenerCallable.nativeFunction.cast(), - (ffi.Pointer arg0) => fn(arg0)); + (ffi.Pointer arg0) => fn(arg0), + keepIsolateAlive); final wrapper = _ObjectiveCBindings_wrapListenerBlock_ovsamd(raw); objc.objectRelease(raw.cast()); return objc.ObjCBlock)>(wrapper, @@ -13051,18 +13210,22 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid { /// caller until the callback is handled by the Dart isolate that created /// the block. Async functions are not supported. /// - /// This block does not keep the owner isolate alive. If the owner isolate has - /// shut down, and the block is invoked by native code, it may block + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. If the owner isolate + /// has shut down, and the block is invoked by native code, it may block /// indefinitely, or have other undefined behavior. static objc.ObjCBlock)> blocking( - void Function(ffi.Pointer) fn) { + void Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_blockingCallable.nativeFunction.cast(), - (ffi.Pointer arg0) => fn(arg0)); + (ffi.Pointer arg0) => fn(arg0), + keepIsolateAlive); final rawListener = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_blockingListenerCallable.nativeFunction .cast(), - (ffi.Pointer arg0) => fn(arg0)); + (ffi.Pointer arg0) => fn(arg0), + keepIsolateAlive); final wrapper = objc.wrapBlockingBlock( _ObjectiveCBindings_wrapBlockingBlock_ovsamd, raw, rawListener); objc.objectRelease(raw.cast()); @@ -13210,15 +13373,19 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSCoder { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock< ffi.Void Function(ffi.Pointer, NSCoder)> fromFunction( - void Function(ffi.Pointer, NSCoder) fn) => + void Function(ffi.Pointer, NSCoder) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock, NSCoder)>( objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSCoder_closureCallable, - (ffi.Pointer arg0, ffi.Pointer arg1) => fn( - arg0, - NSCoder.castFromPointer(arg1, retain: true, release: true))), + (ffi.Pointer arg0, ffi.Pointer arg1) => + fn(arg0, NSCoder.castFromPointer(arg1, retain: true, release: true)), + keepIsolateAlive), retain: false, release: true); @@ -13229,15 +13396,17 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSCoder { /// but only supports void functions, and is not run synchronously. See /// NativeCallable.listener for more details. /// - /// Note that unlike the default behavior of NativeCallable.listener, listener - /// blocks do not keep the isolate alive. + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock, NSCoder)> - listener(void Function(ffi.Pointer, NSCoder) fn) { + listener(void Function(ffi.Pointer, NSCoder) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSCoder_listenerCallable.nativeFunction .cast(), (ffi.Pointer arg0, ffi.Pointer arg1) => fn( - arg0, NSCoder.castFromPointer(arg1, retain: false, release: true))); + arg0, NSCoder.castFromPointer(arg1, retain: false, release: true)), + keepIsolateAlive); final wrapper = _ObjectiveCBindings_wrapListenerBlock_18v1jvf(raw); objc.objectRelease(raw.cast()); return objc.ObjCBlock, NSCoder)>( @@ -13252,22 +13421,26 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSCoder { /// caller until the callback is handled by the Dart isolate that created /// the block. Async functions are not supported. /// - /// This block does not keep the owner isolate alive. If the owner isolate has - /// shut down, and the block is invoked by native code, it may block + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. If the owner isolate + /// has shut down, and the block is invoked by native code, it may block /// indefinitely, or have other undefined behavior. static objc.ObjCBlock, NSCoder)> - blocking(void Function(ffi.Pointer, NSCoder) fn) { + blocking(void Function(ffi.Pointer, NSCoder) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingCallable.nativeFunction .cast(), (ffi.Pointer arg0, ffi.Pointer arg1) => fn( - arg0, NSCoder.castFromPointer(arg1, retain: false, release: true))); + arg0, NSCoder.castFromPointer(arg1, retain: false, release: true)), + keepIsolateAlive); final rawListener = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSCoder_blockingListenerCallable .nativeFunction .cast(), (ffi.Pointer arg0, ffi.Pointer arg1) => fn( - arg0, NSCoder.castFromPointer(arg1, retain: false, release: true))); + arg0, NSCoder.castFromPointer(arg1, retain: false, release: true)), + keepIsolateAlive); final wrapper = objc.wrapBlockingBlock( _ObjectiveCBindings_wrapBlockingBlock_18v1jvf, raw, rawListener); objc.objectRelease(raw.cast()); @@ -13446,17 +13619,21 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock, NSStream, ffi.UnsignedLong)> fromFunction( - void Function(ffi.Pointer, NSStream, NSStreamEvent) fn) => + void Function(ffi.Pointer, NSStream, NSStreamEvent) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock, NSStream, ffi.UnsignedLong)>( objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_closureCallable, - (ffi.Pointer arg0, ffi.Pointer arg1, - int arg2) => + (ffi.Pointer arg0, ffi.Pointer arg1, int arg2) => fn( arg0, NSStream.castFromPointer(arg1, retain: true, release: true), - NSStreamEvent.fromValue(arg2))), + NSStreamEvent.fromValue(arg2)), + keepIsolateAlive), retain: false, release: true); @@ -13467,12 +13644,12 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent { /// but only supports void functions, and is not run synchronously. See /// NativeCallable.listener for more details. /// - /// Note that unlike the default behavior of NativeCallable.listener, listener - /// blocks do not keep the isolate alive. + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock< ffi.Void Function(ffi.Pointer, NSStream, ffi.UnsignedLong)> - listener( - void Function(ffi.Pointer, NSStream, NSStreamEvent) fn) { + listener(void Function(ffi.Pointer, NSStream, NSStreamEvent) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_listenerCallable .nativeFunction @@ -13482,7 +13659,8 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent { fn( arg0, NSStream.castFromPointer(arg1, retain: false, release: true), - NSStreamEvent.fromValue(arg2))); + NSStreamEvent.fromValue(arg2)), + keepIsolateAlive); final wrapper = _ObjectiveCBindings_wrapListenerBlock_hoampi(raw); objc.objectRelease(raw.cast()); return objc.ObjCBlock< @@ -13496,13 +13674,14 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent { /// caller until the callback is handled by the Dart isolate that created /// the block. Async functions are not supported. /// - /// This block does not keep the owner isolate alive. If the owner isolate has - /// shut down, and the block is invoked by native code, it may block + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. If the owner isolate + /// has shut down, and the block is invoked by native code, it may block /// indefinitely, or have other undefined behavior. static objc.ObjCBlock< ffi.Void Function(ffi.Pointer, NSStream, ffi.UnsignedLong)> - blocking( - void Function(ffi.Pointer, NSStream, NSStreamEvent) fn) { + blocking(void Function(ffi.Pointer, NSStream, NSStreamEvent) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingCallable .nativeFunction @@ -13512,7 +13691,8 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent { fn( arg0, NSStream.castFromPointer(arg1, retain: false, release: true), - NSStreamEvent.fromValue(arg2))); + NSStreamEvent.fromValue(arg2)), + keepIsolateAlive); final rawListener = objc.newClosureBlock( _ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent_blockingListenerCallable .nativeFunction @@ -13522,7 +13702,8 @@ abstract final class ObjCBlock_ffiVoid_ffiVoid_NSStream_NSStreamEvent { fn( arg0, NSStream.castFromPointer(arg1, retain: false, release: true), - NSStreamEvent.fromValue(arg2))); + NSStreamEvent.fromValue(arg2)), + keepIsolateAlive); final wrapper = objc.wrapBlockingBlock( _ObjectiveCBindings_wrapBlockingBlock_hoampi, raw, rawListener); objc.objectRelease(raw.cast()); @@ -13688,17 +13869,21 @@ abstract final class ObjCBlock_ffiVoid_idNSSecureCoding_NSError { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock?, NSError)> fromFunction( - void Function(NSSecureCoding?, NSError) fn) => + void Function(NSSecureCoding?, NSError) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock?, NSError)>( objc.newClosureBlock( _ObjCBlock_ffiVoid_idNSSecureCoding_NSError_closureCallable, (ffi.Pointer arg0, ffi.Pointer arg1) => fn( arg0.address == 0 ? null - : NSSecureCoding.castFromPointer(arg0, - retain: true, release: true), - NSError.castFromPointer(arg1, retain: true, release: true))), + : NSSecureCoding.castFromPointer(arg0, retain: true, release: true), + NSError.castFromPointer(arg1, retain: true, release: true)), + keepIsolateAlive), retain: false, release: true); @@ -13709,11 +13894,12 @@ abstract final class ObjCBlock_ffiVoid_idNSSecureCoding_NSError { /// but only supports void functions, and is not run synchronously. See /// NativeCallable.listener for more details. /// - /// Note that unlike the default behavior of NativeCallable.listener, listener - /// blocks do not keep the isolate alive. + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc .ObjCBlock?, NSError)> - listener(void Function(NSSecureCoding?, NSError) fn) { + listener(void Function(NSSecureCoding?, NSError) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_idNSSecureCoding_NSError_listenerCallable .nativeFunction @@ -13725,7 +13911,8 @@ abstract final class ObjCBlock_ffiVoid_idNSSecureCoding_NSError { ? null : NSSecureCoding.castFromPointer(arg0, retain: false, release: true), - NSError.castFromPointer(arg1, retain: false, release: true))); + NSError.castFromPointer(arg1, retain: false, release: true)), + keepIsolateAlive); final wrapper = _ObjectiveCBindings_wrapListenerBlock_pfv6jd(raw); objc.objectRelease(raw.cast()); return objc.ObjCBlock< @@ -13739,12 +13926,14 @@ abstract final class ObjCBlock_ffiVoid_idNSSecureCoding_NSError { /// caller until the callback is handled by the Dart isolate that created /// the block. Async functions are not supported. /// - /// This block does not keep the owner isolate alive. If the owner isolate has - /// shut down, and the block is invoked by native code, it may block + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. If the owner isolate + /// has shut down, and the block is invoked by native code, it may block /// indefinitely, or have other undefined behavior. static objc .ObjCBlock?, NSError)> - blocking(void Function(NSSecureCoding?, NSError) fn) { + blocking(void Function(NSSecureCoding?, NSError) fn, + {bool keepIsolateAlive = true}) { final raw = objc.newClosureBlock( _ObjCBlock_ffiVoid_idNSSecureCoding_NSError_blockingCallable .nativeFunction @@ -13756,7 +13945,8 @@ abstract final class ObjCBlock_ffiVoid_idNSSecureCoding_NSError { ? null : NSSecureCoding.castFromPointer(arg0, retain: false, release: true), - NSError.castFromPointer(arg1, retain: false, release: true))); + NSError.castFromPointer(arg1, retain: false, release: true)), + keepIsolateAlive); final rawListener = objc.newClosureBlock( _ObjCBlock_ffiVoid_idNSSecureCoding_NSError_blockingListenerCallable .nativeFunction @@ -13768,7 +13958,8 @@ abstract final class ObjCBlock_ffiVoid_idNSSecureCoding_NSError { ? null : NSSecureCoding.castFromPointer(arg0, retain: false, release: true), - NSError.castFromPointer(arg1, retain: false, release: true))); + NSError.castFromPointer(arg1, retain: false, release: true)), + keepIsolateAlive); final wrapper = objc.wrapBlockingBlock( _ObjectiveCBindings_wrapBlockingBlock_pfv6jd, raw, rawListener); objc.objectRelease(raw.cast()); @@ -13863,10 +14054,13 @@ abstract final class ObjCBlock_instancetype_ffiVoid_NSCoder { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc - .ObjCBlock?> Function(ffi.Pointer, NSCoder)> + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc.ObjCBlock?> Function(ffi.Pointer, NSCoder)> fromFunction( - Dartinstancetype? Function(ffi.Pointer, NSCoder) fn) => + Dartinstancetype? Function(ffi.Pointer, NSCoder) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock?> Function(ffi.Pointer, NSCoder)>( objc.newClosureBlock( _ObjCBlock_instancetype_ffiVoid_NSCoder_closureCallable, @@ -13874,7 +14068,8 @@ abstract final class ObjCBlock_instancetype_ffiVoid_NSCoder { fn(arg0, NSCoder.castFromPointer(arg1, retain: true, release: true)) ?.ref .retainAndReturnPointer() ?? - ffi.nullptr), + ffi.nullptr, + keepIsolateAlive), retain: false, release: true); } @@ -14002,8 +14197,13 @@ abstract final class ObjCBlock_instancetype_ffiVoid_NSData_NSString_NSError { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc.ObjCBlock? Function(ffi.Pointer, NSData, NSString, ffi.Pointer>)> - fromFunction(Dartinstancetype? Function(ffi.Pointer, NSData, NSString, ffi.Pointer>) fn) => + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc + .ObjCBlock? Function(ffi.Pointer, NSData, NSString, ffi.Pointer>)> + fromFunction(Dartinstancetype? Function(ffi.Pointer, NSData, NSString, ffi.Pointer>) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock? Function(ffi.Pointer, NSData, NSString, ffi.Pointer>)>( objc.newClosureBlock( _ObjCBlock_instancetype_ffiVoid_NSData_NSString_NSError_closureCallable, @@ -14011,8 +14211,8 @@ abstract final class ObjCBlock_instancetype_ffiVoid_NSData_NSString_NSError { ffi.Pointer arg1, ffi.Pointer arg2, ffi.Pointer> arg3) => - fn(arg0, NSData.castFromPointer(arg1, retain: true, release: true), NSString.castFromPointer(arg2, retain: true, release: true), arg3)?.ref.retainAndAutorelease() ?? - ffi.nullptr), + fn(arg0, NSData.castFromPointer(arg1, retain: true, release: true), NSString.castFromPointer(arg2, retain: true, release: true), arg3)?.ref.retainAndAutorelease() ?? ffi.nullptr, + keepIsolateAlive), retain: false, release: true); } @@ -14113,15 +14313,20 @@ abstract final class ObjCBlock_objcObjCObject_ffiVoid { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc .ObjCBlock Function(ffi.Pointer)> - fromFunction(objc.ObjCObjectBase Function(ffi.Pointer) fn) => + fromFunction(objc.ObjCObjectBase Function(ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock< ffi.Pointer Function(ffi.Pointer)>( objc.newClosureBlock( _ObjCBlock_objcObjCObject_ffiVoid_closureCallable, (ffi.Pointer arg0) => - fn(arg0).ref.retainAndAutorelease()), + fn(arg0).ref.retainAndAutorelease(), + keepIsolateAlive), retain: false, release: true); } @@ -14216,16 +14421,20 @@ abstract final class ObjCBlock_objcObjCObject_ffiVoid_NSZone { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc - .ObjCBlock> Function(ffi.Pointer, ffi.Pointer)> - fromFunction(objc.ObjCObjectBase Function(ffi.Pointer, ffi.Pointer) fn) => + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc.ObjCBlock> Function(ffi.Pointer, ffi.Pointer)> + fromFunction(objc.ObjCObjectBase Function(ffi.Pointer, ffi.Pointer) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock< objc.Retained> Function( ffi.Pointer, ffi.Pointer)>( objc.newClosureBlock( _ObjCBlock_objcObjCObject_ffiVoid_NSZone_closureCallable, (ffi.Pointer arg0, ffi.Pointer arg1) => - fn(arg0, arg1).ref.retainAndReturnPointer()), + fn(arg0, arg1).ref.retainAndReturnPointer(), + keepIsolateAlive), retain: false, release: true); } @@ -14330,17 +14539,22 @@ abstract final class ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector { /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer)> - fromFunction(objc.ObjCObjectBase Function(ffi.Pointer, ffi.Pointer) fn) => - objc.ObjCBlock< - ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>( - objc.newClosureBlock( - _ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_closureCallable, - (ffi.Pointer arg0, ffi.Pointer arg1) => - fn(arg0, arg1).ref.retainAndAutorelease()), - retain: false, - release: true); + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer)> fromFunction( + objc.ObjCObjectBase Function( + ffi.Pointer, ffi.Pointer) + fn, + {bool keepIsolateAlive = true}) => + objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer)>( + objc.newClosureBlock( + _ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_closureCallable, + (ffi.Pointer arg0, ffi.Pointer arg1) => + fn(arg0, arg1).ref.retainAndAutorelease(), + keepIsolateAlive), + retain: false, + release: true); } /// Call operator for `objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer)>`. @@ -14455,8 +14669,12 @@ abstract final class ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_objcObjCO /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. static objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)> - fromFunction(objc.ObjCObjectBase Function(ffi.Pointer, ffi.Pointer, objc.ObjCObjectBase) fn) => + fromFunction(objc.ObjCObjectBase Function(ffi.Pointer, ffi.Pointer, objc.ObjCObjectBase) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>( objc.newClosureBlock( _ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_objcObjCObject_closureCallable, @@ -14465,7 +14683,8 @@ abstract final class ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_objcObjCO ffi.Pointer arg2) => fn(arg0, arg1, objc.ObjCObjectBase(arg2, retain: true, release: true)) .ref - .retainAndAutorelease()), + .retainAndAutorelease(), + keepIsolateAlive), retain: false, release: true); } @@ -14598,8 +14817,13 @@ abstract final class ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_objcObjCO /// This block must be invoked by native code running on the same thread as /// the isolate that registered it. Invoking the block on the wrong thread /// will result in a crash. - static objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)> - fromFunction(objc.ObjCObjectBase Function(ffi.Pointer, ffi.Pointer, objc.ObjCObjectBase, objc.ObjCObjectBase) fn) => + /// + /// If `keepIsolateAlive` is true, this block will keep this isolate alive + /// until it is garbage collected by both Dart and ObjC. + static objc + .ObjCBlock Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)> + fromFunction(objc.ObjCObjectBase Function(ffi.Pointer, ffi.Pointer, objc.ObjCObjectBase, objc.ObjCObjectBase) fn, + {bool keepIsolateAlive = true}) => objc.ObjCBlock Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, ffi.Pointer)>( objc.newClosureBlock( _ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_objcObjCObject_objcObjCObject_closureCallable, @@ -14607,9 +14831,8 @@ abstract final class ObjCBlock_objcObjCObject_ffiVoid_objcObjCSelector_objcObjCO ffi.Pointer arg1, ffi.Pointer arg2, ffi.Pointer arg3) => - fn(arg0, arg1, objc.ObjCObjectBase(arg2, retain: true, release: true), objc.ObjCObjectBase(arg3, retain: true, release: true)) - .ref - .retainAndAutorelease()), + fn(arg0, arg1, objc.ObjCObjectBase(arg2, retain: true, release: true), objc.ObjCObjectBase(arg3, retain: true, release: true)).ref.retainAndAutorelease(), + keepIsolateAlive), retain: false, release: true); } @@ -16177,6 +16400,20 @@ final _objc_msgSend_d3i1uyStret = objc.msgSendStretPointer .asFunction< void Function(ffi.Pointer, ffi.Pointer, ffi.Pointer, int)>(); +final _objc_msgSend_dbvvll = objc.msgSendPointer + .cast< + ffi.NativeFunction< + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + ffi.Int64)>>() + .asFunction< + ffi.Pointer Function( + ffi.Pointer, + ffi.Pointer, + ffi.Pointer, + int)>(); final _objc_msgSend_degb40 = objc.msgSendPointer .cast< ffi.NativeFunction< @@ -17074,7 +17311,8 @@ late final _sel_initFileURLWithPath_isDirectory_relativeToURL_ = objc.registerName("initFileURLWithPath:isDirectory:relativeToURL:"); late final _sel_initFileURLWithPath_relativeToURL_ = objc.registerName("initFileURLWithPath:relativeToURL:"); -late final _sel_initFromBuilder_ = objc.registerName("initFromBuilder:"); +late final _sel_initFromBuilder_withDisposePort_ = + objc.registerName("initFromBuilder:withDisposePort:"); late final _sel_initToBuffer_capacity_ = objc.registerName("initToBuffer:capacity:"); late final _sel_initToFileAtPath_append_ = @@ -17349,7 +17587,8 @@ late final _sel_mutableCopyWithZone_ = objc.registerName("mutableCopyWithZone:"); late final _sel_name = objc.registerName("name"); late final _sel_new = objc.registerName("new"); -late final _sel_newFromBuilder_ = objc.registerName("newFromBuilder:"); +late final _sel_newFromBuilder_withDisposePort_ = + objc.registerName("newFromBuilder:withDisposePort:"); late final _sel_newlineCharacterSet = objc.registerName("newlineCharacterSet"); late final _sel_nextObject = objc.registerName("nextObject"); late final _sel_nonBaseCharacterSet = objc.registerName("nonBaseCharacterSet"); diff --git a/pkgs/objective_c/lib/src/protocol_builder.dart b/pkgs/objective_c/lib/src/protocol_builder.dart index d9fbaa9ee..8360e852d 100644 --- a/pkgs/objective_c/lib/src/protocol_builder.dart +++ b/pkgs/objective_c/lib/src/protocol_builder.dart @@ -3,6 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:ffi'; +import 'dart:isolate'; import 'c_bindings_generated.dart' as c; import 'internal.dart' @@ -27,7 +28,16 @@ class ObjCProtocolBuilder { /// /// This can be called multiple times to construct multiple object instances /// that all implement the same protocol methods using the same functions. - objc.DartProxy build() => objc.DartProxy.newFromBuilder_(_builder); + objc.DartProxy build({bool keepIsolateAlive = true}) { + var disposePort = c.ILLEGAL_PORT; + if (keepIsolateAlive) { + late final RawReceivePort keepAlivePort; + keepAlivePort = RawReceivePort((_) => keepAlivePort.close()); + disposePort = keepAlivePort.sendPort.nativePort; + } + return objc.DartProxy.newFromBuilder_withDisposePort_( + _builder, disposePort); + } } /// A method in an ObjC protocol. diff --git a/pkgs/objective_c/pubspec.yaml b/pkgs/objective_c/pubspec.yaml index f93b9f517..c1c73188b 100644 --- a/pkgs/objective_c/pubspec.yaml +++ b/pkgs/objective_c/pubspec.yaml @@ -4,7 +4,7 @@ name: objective_c description: 'A library to access Objective C from Flutter that acts as a support library for package:ffigen.' -version: 6.0.0 +version: 7.0.0-wip repository: https://github.com/dart-lang/native/tree/main/pkgs/objective_c issue_tracker: https://github.com/dart-lang/native/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Aobjective_c @@ -28,7 +28,7 @@ dev_dependencies: args: ^2.6.0 coverage: ^1.11.0 dart_flutter_team_lints: ^2.0.0 - ffigen: ^17.0.0 + ffigen: ^18.0.0 flutter_lints: ^3.0.0 flutter_test: sdk: flutter diff --git a/pkgs/objective_c/src/proxy.h b/pkgs/objective_c/src/proxy.h index 2857172b1..465ed8de8 100644 --- a/pkgs/objective_c/src/proxy.h +++ b/pkgs/objective_c/src/proxy.h @@ -7,6 +7,8 @@ #import +#include "include/dart_api_dl.h" + @interface DOBJCDartProxyBuilder : NSObject + (instancetype)new; - (instancetype)init; @@ -16,11 +18,14 @@ @end @interface DOBJCDartProxy : NSProxy -+ (instancetype)newFromBuilder:(__strong DOBJCDartProxyBuilder*)builder; -- (instancetype)initFromBuilder:(__strong DOBJCDartProxyBuilder*)builder; ++ (instancetype)newFromBuilder:(__strong DOBJCDartProxyBuilder*)builder + withDisposePort:(Dart_Port)port; +- (instancetype)initFromBuilder:(__strong DOBJCDartProxyBuilder*)builder + withDisposePort:(Dart_Port)port; - (BOOL)respondsToSelector:(SEL)sel; - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel; - (void)forwardInvocation:(__strong NSInvocation *)invocation; +- (void)dealloc; @end #endif // OBJECTIVE_C_SRC_PROXY_H_ diff --git a/pkgs/objective_c/src/proxy.m b/pkgs/objective_c/src/proxy.m index 3307f3e28..0d5170a70 100644 --- a/pkgs/objective_c/src/proxy.m +++ b/pkgs/objective_c/src/proxy.m @@ -57,19 +57,23 @@ - (NSDictionary*)copyMethods NS_RETURNS_RETAINED { @implementation DOBJCDartProxy { NSDictionary *methods; + Dart_Port dispose_port; } - (DOBJCProxyMethod*)getMethod:(SEL)sel { return [methods objectForKey:[NSValue valueWithPointer:sel]]; } -+ (instancetype)newFromBuilder:(DOBJCDartProxyBuilder*)builder { - return [[self alloc] initFromBuilder:builder]; ++ (instancetype)newFromBuilder:(DOBJCDartProxyBuilder*)builder + withDisposePort:(Dart_Port)port { + return [[self alloc] initFromBuilder:builder withDisposePort:port]; } -- (instancetype)initFromBuilder:(DOBJCDartProxyBuilder*)builder { +- (instancetype)initFromBuilder:(DOBJCDartProxyBuilder*)builder + withDisposePort:(Dart_Port)port { if (self) { methods = [builder copyMethods]; + dispose_port = port; } return self; } @@ -91,4 +95,10 @@ - (void)forwardInvocation:(NSInvocation *)invocation { } } +- (void)dealloc { + if (dispose_port != ILLEGAL_PORT) { + Dart_PostInteger_DL(dispose_port, 0); + } +} + @end