-
Notifications
You must be signed in to change notification settings - Fork 64
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ffigen] Protocol polish #2060
[ffigen] Protocol polish #2060
Changes from 9 commits
eb56de1
c884353
5bdd287
6e0fbdd
14d63d7
07e10f5
5c47c03
9ccb563
50253b3
aeed8b0
cc01f7d
52ab114
a2b1686
a45198a
2ee487c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,22 +7,42 @@ | |
#import <Foundation/NSDictionary.h> | ||
#import <Foundation/NSInvocation.h> | ||
#import <Foundation/NSValue.h> | ||
#import <objc/runtime.h> | ||
|
||
#if !__has_feature(objc_arc) | ||
#error "This file must be compiled with ARC enabled" | ||
#endif | ||
|
||
@implementation DOBJCDartProtocolBuilder { | ||
NSMutableDictionary *methods; | ||
@interface DOBJCDartProtocolClass : NSObject | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you have a specific reason to separate this from the builder itself? Consider a simpler setup where I also tried to follow Google Objective-C Style Guide which we otherwise seemed to have ignored. It is good to have more comments and somewhat cleaner code. @class DOBJCDartProtocol;
/**
* Class responsible for creating Objective-C classes in runtime.
* See also `...` in Dart.
*/
@interface DOBJCDartProtocolBuilder : NSObject
/**
* Initialize the builder using the given @c debugName.
*
* @param debugName prefix to use when creating an Objective-C class,
* "DOBJCDartProtocol" will be used if @c debugName is @c nil
*/
- (instancetype)initWithDebugName: (NSString*)debugName;
/**
* Use @c block to implement selector @c sel.
*
* This method can only be called before the first instance is created
* via @c newInstanceWithDisposePort.
*
* @param sel Selector which will be implemented.
* @param block Block to redirect method to.
*/
- (void)implementMethod:(SEL) sel withBlock:(void*)block;
/**
* Create an instance of the class built by this builder.
*
* Finalizes and registers Objective-C class. No new methods can be implemented
* after the first instance is created.
*
* @param port Optional port to notify when newly created instance is
* deallocated. Can be @c ILLEGAL_PORT.
*/
- (DOBJCDartProtocol*)newInstanceWithDisposePort:(Dart_Port)port;
- (void) dealloc;
@end
@interface DOBJCDartProtocol : NSObject
- (instancetype)initFromBuilder: (DOBJCDartProtocolBuilder*)builder withDisposePort:(Dart_Port)port;
- (id)getBlockImplementingSelector:(SEL)sel;
- (void)dealloc;
@end
@implementation DOBJCDartProtocolBuilder {
BOOL _finalized;
Class _cls;
@public NSMutableDictionary *_methods;
}
static _Atomic int64_t gNextProtocolId = 0;
- (instancetype)initWithDebugName: (NSString *)debugName {
// Note: no need for if (self) if you don't do `self = [super init]`.
if (!debugName) {
debugName = @"DOBJCDartProtocol";
}
int64_t id = atomic_fetch_add(&gNextProtocolId, 1);
debugName = [NSString stringWithFormat:@"%@_%lld", debugName, id];
_cls = objc_allocateClassPair(objc_lookUpClass("DOBJCDartProtocol"), [debugName UTF8String], /*extra_bytes=*/0);
_methods = [NSMutableDictionary new];
_finalized = NO;
return self;
}
- (DOBJCDartProtocol*)newInstanceWithDisposePort:(Dart_Port)port {
if (!_finalized) {
objc_registerClassPair(_cls);
_finalized = YES;
}
DOBJCDartProtocol* obj = [_cls alloc];
return [obj initFromBuilder:self withDisposePort:port];
}
- (void) dealloc {
objc_disposeClassPair(_cls);
}
@end
@implementation DOBJCDartProtocol {
DOBJCDartProtocolBuilder* _builder;
Dart_Port _dispose_port;
}
- (instancetype)initFromBuilder: (DOBJCDartProtocolBuilder*)builder withDisposePort:(Dart_Port)port {
_builder = builder;
_dispose_port = port;
return self;
}
- (void)dealloc {
if (_dispose_port != ILLEGAL_PORT) {
Dart_PostInteger_DL(_dispose_port, 0);
}
}
- (id)getBlockImplementingSelector:(SEL)sel {
return [_builder->_methods objectForKey:[NSValue valueWithPointer:sel]];
}
@end There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done, more or less. In general, all else being equal, I prefer to orchestrate in Dart (because it's a better language ;) ). But yeah, creating the class and instantiating the implementation objects on the ObjC side simplifies things a little, and the My formatting is always a little weird because I haven't managed to get clang format to work on these files (or rather, it makes nonsensical formatting decisions, like ignoring like length).
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! Choices look reasonable. I do also prefer orchestrating in Dart - however I usually apply the rule of "keeping the logic concentrated in one place". So if I am already writing native code and native code will look more natural - then I will shift most of the logic into native code and make Dart code a thin wrapper. This makes the code easier to understand - otherwise the logic gets split and you need to jump back and forth to piece it together.
Makes sense. |
||
- (instancetype)initWithClass: (Class)cls; | ||
@end | ||
|
||
@implementation DOBJCDartProtocolClass { | ||
Class clazz; | ||
} | ||
|
||
- (instancetype)initWithClass: (Class)cls { | ||
if (self) { | ||
clazz = cls; | ||
} | ||
return self; | ||
} | ||
|
||
+ (instancetype)new { | ||
return [[self alloc] init]; | ||
- (void)dealloc { | ||
objc_disposeClassPair(clazz); | ||
} | ||
|
||
- (instancetype)init { | ||
@end | ||
|
||
@implementation DOBJCDartProtocolBuilder { | ||
NSMutableDictionary *methods; | ||
DOBJCDartProtocolClass* clazz; | ||
} | ||
|
||
- (instancetype)initWithClass: (void*)cls { | ||
if (self) { | ||
methods = [NSMutableDictionary new]; | ||
clazz = [[DOBJCDartProtocolClass alloc] initWithClass: (__bridge Class)cls]; | ||
} | ||
return self; | ||
} | ||
|
@@ -37,13 +57,19 @@ - (void)implementMethod:(SEL)sel withBlock:(void*)block { | |
[self implement:sel withBlock:(__bridge id)block]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} | ||
|
||
- (NSDictionary*)copyMethods NS_RETURNS_RETAINED { | ||
return [methods copy]; | ||
- (NSDictionary*)getMethods { | ||
return methods; | ||
} | ||
|
||
- (DOBJCDartProtocolClass*)getClass { | ||
return clazz; | ||
} | ||
|
||
@end | ||
|
||
@implementation DOBJCDartProtocol { | ||
NSDictionary *methods; | ||
DOBJCDartProtocolClass* clazz; | ||
Dart_Port dispose_port; | ||
} | ||
|
||
|
@@ -55,7 +81,8 @@ - (instancetype)initDOBJCDartProtocolFromDartProtocolBuilder: | |
(DOBJCDartProtocolBuilder*)builder | ||
withDisposePort:(Dart_Port)port { | ||
if (self) { | ||
methods = [builder copyMethods]; | ||
methods = [builder getMethods]; | ||
clazz = [builder getClass]; | ||
dispose_port = port; | ||
} | ||
return self; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: a more accurate name for
bypassCache
is probablyforceClassListReload
or something like this.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done