|
@@ -57,7 +57,8 @@ static const NSTimeInterval kDefaultChannelDestroyDelay = 30;
|
|
|
}
|
|
|
|
|
|
- (void)dealloc {
|
|
|
- if ([_wrappedCalls objectEnumerator].allObjects.count != 0) {
|
|
|
+ // Disconnect GRPCWrappedCall objects created but not yet removed
|
|
|
+ if (_wrappedCalls.allObjects.count != 0) {
|
|
|
NSEnumerator *enumerator = [_wrappedCalls objectEnumerator];
|
|
|
GRPCWrappedCall *wrappedCall;
|
|
|
while ((wrappedCall = [enumerator nextObject])) {
|
|
@@ -111,13 +112,17 @@ callOptions:(GRPCCallOptions *)callOptions {
|
|
|
return;
|
|
|
}
|
|
|
@synchronized(self) {
|
|
|
- if ([_wrappedCalls objectEnumerator].allObjects.count == 0) {
|
|
|
+ // Detect if all objects weakly referenced in _wrappedCalls are (implicitly) removed. In such
|
|
|
+ // case the channel is no longer referenced by a grpc_call object and can be destroyed after
|
|
|
+ // a certain delay.
|
|
|
+ if (_wrappedCalls.allObjects.count == 0) {
|
|
|
NSDate *now = [NSDate date];
|
|
|
+ NSAssert(now != nil, @"Unable to create NSDate object 'now'.");
|
|
|
_lastTimedDestroy = now;
|
|
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)_destroyDelay * NSEC_PER_SEC),
|
|
|
_timerQueue, ^{
|
|
|
@synchronized(self) {
|
|
|
- if (self->_lastTimedDestroy == now) {
|
|
|
+ if (now != nil && self->_lastTimedDestroy == now) {
|
|
|
self->_wrappedChannel = nil;
|
|
|
self->_lastTimedDestroy = nil;
|
|
|
}
|
|
@@ -128,17 +133,15 @@ callOptions:(GRPCCallOptions *)callOptions {
|
|
|
}
|
|
|
|
|
|
- (void)disconnect {
|
|
|
- NSHashTable<GRPCWrappedCall *> *copiedWrappedCalls = nil;
|
|
|
+ NSArray<GRPCWrappedCall *> *copiedWrappedCalls = nil;
|
|
|
@synchronized(self) {
|
|
|
if (_wrappedChannel != nil) {
|
|
|
_wrappedChannel = nil;
|
|
|
- copiedWrappedCalls = [_wrappedCalls copy];
|
|
|
+ copiedWrappedCalls = _wrappedCalls.allObjects;
|
|
|
[_wrappedCalls removeAllObjects];
|
|
|
}
|
|
|
}
|
|
|
- NSEnumerator *enumerator = [copiedWrappedCalls objectEnumerator];
|
|
|
- GRPCWrappedCall *wrappedCall;
|
|
|
- while ((wrappedCall = [enumerator nextObject])) {
|
|
|
+ for (GRPCWrappedCall *wrappedCall in copiedWrappedCalls) {
|
|
|
[wrappedCall channelDisconnected];
|
|
|
}
|
|
|
}
|
|
@@ -155,9 +158,9 @@ callOptions:(GRPCCallOptions *)callOptions {
|
|
|
}
|
|
|
|
|
|
if ((self = [super init])) {
|
|
|
- _channelConfiguration = channelConfiguration;
|
|
|
+ _channelConfiguration = [channelConfiguration copy];
|
|
|
_destroyDelay = destroyDelay;
|
|
|
- _wrappedCalls = [[NSHashTable alloc] initWithOptions:NSHashTableWeakMemory capacity:1];
|
|
|
+ _wrappedCalls = [NSHashTable weakObjectsHashTable];
|
|
|
_wrappedChannel = nil;
|
|
|
_lastTimedDestroy = nil;
|
|
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
|
|
@@ -187,7 +190,7 @@ callOptions:(GRPCCallOptions *)callOptions {
|
|
|
|
|
|
@interface GRPCChannelPool ()
|
|
|
|
|
|
-- (instancetype)initInstance NS_DESIGNATED_INITIALIZER;
|
|
|
+- (instancetype)initPrivate NS_DESIGNATED_INITIALIZER;
|
|
|
|
|
|
@end
|
|
|
|
|
@@ -198,13 +201,13 @@ callOptions:(GRPCCallOptions *)callOptions {
|
|
|
+ (instancetype)sharedInstance {
|
|
|
dispatch_once(&gInitChannelPool, ^{
|
|
|
gChannelPool =
|
|
|
- [[GRPCChannelPool alloc] initInstance];
|
|
|
+ [[GRPCChannelPool alloc] initPrivate];
|
|
|
NSAssert(gChannelPool != nil, @"Cannot initialize global channel pool.");
|
|
|
});
|
|
|
return gChannelPool;
|
|
|
}
|
|
|
|
|
|
-- (instancetype)initInstance {
|
|
|
+- (instancetype)initPrivate {
|
|
|
if ((self = [super init])) {
|
|
|
_channelPool = [NSMutableDictionary dictionary];
|
|
|
|
|
@@ -242,15 +245,15 @@ callOptions:(GRPCCallOptions *)callOptions {
|
|
|
}
|
|
|
|
|
|
- (void)disconnectAllChannels {
|
|
|
- NSDictionary *copiedPooledChannels;
|
|
|
+ NSArray<GRPCPooledChannel *> *copiedPooledChannels;
|
|
|
@synchronized(self) {
|
|
|
- copiedPooledChannels = [NSDictionary dictionaryWithDictionary:_channelPool];
|
|
|
+ copiedPooledChannels = _channelPool.allValues;
|
|
|
}
|
|
|
|
|
|
// Disconnect pooled channels.
|
|
|
- [copiedPooledChannels enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
|
|
|
- [obj disconnect];
|
|
|
- }];
|
|
|
+ for (GRPCPooledChannel *pooledChannel in copiedPooledChannels) {
|
|
|
+ [pooledChannel disconnect];
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- (void)connectivityChange:(NSNotification *)note {
|
|
@@ -262,7 +265,7 @@ callOptions:(GRPCCallOptions *)callOptions {
|
|
|
@implementation GRPCChannelPool (Test)
|
|
|
|
|
|
- (instancetype)initTestPool {
|
|
|
- return [self initInstance];
|
|
|
+ return [self initPrivate];
|
|
|
}
|
|
|
|
|
|
@end
|