Skip to content

Commit 301e724

Browse files
authored
[ffigen] Direct protocol method implementation using blocks (#2019)
1 parent 8ca82ba commit 301e724

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

pkgs/ffigen/test/native_objc_test/protocol_test.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,22 @@ void main() {
340340
consumer.callBlockingMethodOnRandomThread_(asMyProtocol);
341341
expect(await listenerCompleter.future, 98765);
342342
});
343+
344+
test('Direct method implementation using block', () async {
345+
final consumer = ProtocolConsumer.new1();
346+
347+
final builder = ObjCProtocolBuilder();
348+
MyProtocol.instanceMethod_withDouble_.implementWithBlock(
349+
builder,
350+
ObjCBlock_NSString_ffiVoid_NSString_ffiDouble.fromFunction(
351+
(Pointer<Void> _, NSString s, double x) =>
352+
'DirectImpl: ${s.toDartString()}: $x'.toNSString()));
353+
final myProtocol = MyProtocol.castFrom(builder.build());
354+
355+
// Required instance method.
356+
final result = consumer.callInstanceMethod_(myProtocol);
357+
expect(result.toDartString(), 'DirectImpl: Hello from ObjC: 3.14');
358+
});
343359
});
344360

345361
group('Manual DartProxy implementation', () {

pkgs/objective_c/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
## 7.0.0-wip
22

33
- Use ffigen 18.0.0
4+
- `ObjCProtocolBuilder` supports implementing protocol methods directly using a
5+
block.
46

57
## 6.0.0
68

pkgs/objective_c/lib/src/protocol_builder.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,19 @@ class ObjCProtocolMethod<T extends Function> {
6363
/// the wrong thread will result in a crash.
6464
void implement(ObjCProtocolBuilder builder, T? function) {
6565
if (function != null) {
66-
builder.implementMethod(_sel, _sig, _createBlock(function));
66+
implementWithBlock(builder, _createBlock(function));
6767
}
6868
}
6969

70+
/// Implement this method on the protocol [builder] using an ObjC [block].
71+
///
72+
/// **IMPORTANT**: The [block] must have the same signature as the method,
73+
/// but with an extra `void*` argument as the first parameter, before all the
74+
/// method parameters. Most users should use one of the other `implement`
75+
/// methods, which handles this signature change automatically.
76+
void implementWithBlock(ObjCProtocolBuilder builder, ObjCBlockBase block) =>
77+
builder.implementMethod(_sel, _sig, block);
78+
7079
bool get isAvailable => _signature != null;
7180

7281
objc.NSMethodSignature get _sig {
@@ -100,7 +109,7 @@ class ObjCProtocolListenableMethod<T extends Function>
100109
/// See NativeCallable.listener for more details.
101110
void implementAsListener(ObjCProtocolBuilder builder, T? function) {
102111
if (function != null) {
103-
builder.implementMethod(_sel, _sig, _createListenerBlock(function));
112+
implementWithBlock(builder, _createListenerBlock(function));
104113
}
105114
}
106115

@@ -112,7 +121,7 @@ class ObjCProtocolListenableMethod<T extends Function>
112121
/// the method. Async functions are not supported.
113122
void implementAsBlocking(ObjCProtocolBuilder builder, T? function) {
114123
if (function != null) {
115-
builder.implementMethod(_sel, _sig, _createBlockingBlock(function));
124+
implementWithBlock(builder, _createBlockingBlock(function));
116125
}
117126
}
118127
}

0 commit comments

Comments
 (0)