diff --git a/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfiguration.m b/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfiguration.m index 4abbc3857..6e2f5ebe5 100644 --- a/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfiguration.m +++ b/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfiguration.m @@ -20,6 +20,15 @@ @interface NSURLSessionConfiguration (PNConfigurationProtected) #pragma mark - Misc +/** + @brief Retrieve reference on list of previusly created configuration instances. + + @since 4.4.1 + + @return Dictionary where each configuration mapped to it's identifier. + */ ++ (NSMutableDictionary *)pn_configurations; + /** @brief Allow to filter up passed list of prtocol classes from names which can intersect with \c Apple's protocols. @@ -57,24 +66,25 @@ @implementation NSURLSessionConfiguration (PNConfiguration) #pragma mark - Initialization and Configuration -+ (instancetype)pn_ephemeralSessionConfiguration { ++ (instancetype)pn_ephemeralSessionConfigurationWithIdentifier:(NSString *)identifier; { - static NSURLSessionConfiguration *_sharedSessionConfiguration; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ + NSMutableDictionary *sessionConfigurations = [self pn_configurations]; + if (sessionConfigurations[identifier] == nil) { - _sharedSessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; - _sharedSessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData; - _sharedSessionConfiguration.URLCache = nil; - _sharedSessionConfiguration.HTTPAdditionalHeaders = [self pn_defaultHeaders]; - }); + NSURLSessionConfiguration *sessionConfiguration; + sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; + sessionConfiguration.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData; + sessionConfiguration.URLCache = nil; + sessionConfiguration.HTTPAdditionalHeaders = [self pn_defaultHeaders]; + sessionConfigurations[identifier] = sessionConfiguration; + } - return _sharedSessionConfiguration; + return sessionConfigurations[identifier]; } + (NSDictionary *)pn_HTTPAdditionalHeaders { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; + NSURLSessionConfiguration *configuration = [self pn_configurations].allValues.firstObject; NSMutableDictionary *headers = [configuration.HTTPAdditionalHeaders mutableCopy]; [headers removeObjectsForKeys:@[@"Accept", @"Accept-Encoding", @"User-Agent", @"Connection"]]; @@ -83,77 +93,100 @@ + (instancetype)pn_ephemeralSessionConfiguration { + (void)pn_setHTTPAdditionalHeaders:(NSDictionary *)HTTPAdditionalHeaders { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; - NSMutableDictionary *headers = [HTTPAdditionalHeaders mutableCopy]; - [headers removeObjectsForKeys:@[@"Accept", @"Accept-Encoding", @"User-Agent", @"Connection"]]; - if (headers.count) { - - [headers addEntriesFromDictionary:configuration.HTTPAdditionalHeaders]; + NSArray *configurations = [self pn_configurations].allValues; + NSMutableDictionary *customHeaders = [HTTPAdditionalHeaders mutableCopy]; + [customHeaders removeObjectsForKeys:@[@"Accept", @"Accept-Encoding", @"User-Agent", @"Connection"]]; + + // Compose resulting HTTP headers holder. + NSMutableDictionary *headers = [[self pn_defaultHeaders] mutableCopy]; + [headers addEntriesFromDictionary:customHeaders]; + + for (NSURLSessionConfiguration *configuration in configurations) { + configuration.HTTPAdditionalHeaders = headers; } - else { configuration.HTTPAdditionalHeaders = [self pn_defaultHeaders]; } } + (NSURLRequestNetworkServiceType)pn_networkServiceType { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; + NSURLSessionConfiguration *configuration = [self pn_configurations].allValues.firstObject; return configuration.networkServiceType; } + (void)pn_setNetworkServiceType:(NSURLRequestNetworkServiceType)networkServiceType { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; - configuration.networkServiceType = networkServiceType; + for (NSURLSessionConfiguration *configuration in [self pn_configurations].allValues) { + + configuration.networkServiceType = networkServiceType; + } } + (BOOL)pn_allowsCellularAccess { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; + NSURLSessionConfiguration *configuration = [self pn_configurations].allValues.firstObject; return configuration.allowsCellularAccess; } + (void)pn_setAllowsCellularAccess:(BOOL)allowsCellularAccess { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; - configuration.allowsCellularAccess = allowsCellularAccess; + for (NSURLSessionConfiguration *configuration in [self pn_configurations].allValues) { + + configuration.allowsCellularAccess = allowsCellularAccess; + } } + (NSArray *)pn_protocolClasses { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; + NSURLSessionConfiguration *configuration = [self pn_configurations].allValues.firstObject; return [self pn_filteredProtocolClasses:configuration.protocolClasses]; } + (void)pn_setProtocolClasses:(NSArray *)protocolClasses { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; + NSArray *classes = [self pn_configurations].allValues.firstObject.protocolClasses; // Append user-provided protocol classes to system-provided. - NSMutableArray *currentProtocolClasses = [NSMutableArray arrayWithArray:configuration.protocolClasses]; + NSMutableArray *currentProtocolClasses = [NSMutableArray arrayWithArray:classes]; [currentProtocolClasses removeObjectsInArray:[self pn_protocolClasses]]; [currentProtocolClasses addObjectsFromArray:[self pn_filteredProtocolClasses:protocolClasses]]; - configuration.protocolClasses = [currentProtocolClasses copy]; + + classes = [currentProtocolClasses copy]; + for (NSURLSessionConfiguration *configuration in [self pn_configurations].allValues) { + + configuration.protocolClasses = classes; + } } + (NSDictionary *)pn_connectionProxyDictionary { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; + NSURLSessionConfiguration *configuration = [self pn_configurations].allValues.firstObject; return configuration.connectionProxyDictionary; } + (void)pn_setConnectionProxyDictionary:(NSDictionary *)connectionProxyDictionary { - NSURLSessionConfiguration *configuration = [self pn_ephemeralSessionConfiguration]; - configuration.connectionProxyDictionary = connectionProxyDictionary; + for (NSURLSessionConfiguration *configuration in [self pn_configurations].allValues) { + + configuration.connectionProxyDictionary = connectionProxyDictionary; + } } #pragma mark - Misc ++ (NSMutableDictionary *)pn_configurations { + + static NSMutableDictionary *_sharedSessionConfigurations; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ _sharedSessionConfigurations = [NSMutableDictionary new]; }); + + return _sharedSessionConfigurations; +} + + (NSArray *)pn_filteredProtocolClasses:(NSArray *)protocolClasses { NSArray *protocols = (protocolClasses.count ? protocolClasses : nil); diff --git a/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfigurationPrivate.h b/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfigurationPrivate.h index cf1a8beae..11d6f9c82 100644 --- a/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfigurationPrivate.h +++ b/PubNub/Misc/Categories/NSURLSessionConfiguration+PNConfigurationPrivate.h @@ -25,9 +25,11 @@ NS_ASSUME_NONNULL_BEGIN @since 4.4.0 + @param identifier Unique identifier to identify session configuration among other. + @return Configured and ready to use \c NSURLSession configuration instance. */ -+ (instancetype)pn_ephemeralSessionConfiguration; ++ (instancetype)pn_ephemeralSessionConfigurationWithIdentifier:(NSString *)identifier; #pragma mark - diff --git a/PubNub/Network/PNNetwork.m b/PubNub/Network/PNNetwork.m index a3defedc8..34108b39c 100644 --- a/PubNub/Network/PNNetwork.m +++ b/PubNub/Network/PNNetwork.m @@ -91,6 +91,13 @@ @interface PNNetwork () */ @property (nonatomic, strong) PNConfiguration *configuration; +/** + @brief Stores reference on unique \b PubNub network manager instance identifier. + + @since 4.4.1 + */ +@property (nonatomic, copy) NSString *identifier; + /** @brief Stores whether \b PubNub network manager configured for long-poll request processing or not. @discussion This property taken into account when manager need to invalidate underlying \a NSURLSession and @@ -176,16 +183,13 @@ changed at any moment (invalidated instances can't be used and SDK should instan @param maximumConnections Maximum simultaneously connections (requests) which can be opened. @param longPollEnabled Whether \b PubNub network manager should be configured for long-poll requests or not. This option affect the way how network manager handle reset. - @param queue Reference on GCD queue which should be used for callbacks and as working queue for - underlying logic. @return 4.0 @since Initialized and ready to use \b PubNub network manager. */ - (instancetype)initForClient:(PubNub *)client requestTimeout:(NSTimeInterval)timeout - maximumConnections:(NSInteger)maximumConnections longPoll:(BOOL)longPollEnabled - workingQueue:(dispatch_queue_t)queue; + maximumConnections:(NSInteger)maximumConnections longPoll:(BOOL)longPollEnabled; #pragma mark - Request helper @@ -473,15 +477,12 @@ + (void)ddSetLogLevel:(DDLogLevel)logLevel { + (instancetype)networkForClient:(PubNub *)client requestTimeout:(NSTimeInterval)timeout maximumConnections:(NSInteger)maximumConnections longPoll:(BOOL)longPollEnabled { - dispatch_queue_t queue = dispatch_queue_create("com.pubnub.network", DISPATCH_QUEUE_CONCURRENT); - return [[self alloc] initForClient:client requestTimeout:timeout - maximumConnections:maximumConnections longPoll:longPollEnabled - workingQueue:queue]; + return [[self alloc] initForClient:client requestTimeout:timeout maximumConnections:maximumConnections + longPoll:longPollEnabled]; } - (instancetype)initForClient:(PubNub *)client requestTimeout:(NSTimeInterval)timeout - maximumConnections:(NSInteger)maximumConnections longPoll:(BOOL)longPollEnabled - workingQueue:(dispatch_queue_t)queue { + maximumConnections:(NSInteger)maximumConnections longPoll:(BOOL)longPollEnabled { // Check whether initialization was successful or not. if ((self = [super init])) { @@ -489,7 +490,8 @@ - (instancetype)initForClient:(PubNub *)client requestTimeout:(NSTimeInterval)ti _client = client; _configuration = client.configuration; _forLongPollRequests = longPollEnabled; - _processingQueue = queue; + _identifier = [[NSString stringWithFormat:@"com.pubnub.network.%p", self] copy]; + _processingQueue = dispatch_queue_create([_identifier UTF8String], DISPATCH_QUEUE_CONCURRENT);; _serializer = [PNNetworkResponseSerializer new]; _baseURL = [self requestBaseURL]; _lock = OS_SPINLOCK_INIT; @@ -785,7 +787,8 @@ - (NSURLSessionConfiguration *)configurationWithRequestTimeout:(NSTimeInterval)t // Prepare base configuration with predefined timeout values and maximum connections // to same host (basically how many requests can be handled at once). - NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration pn_ephemeralSessionConfiguration]; + NSURLSessionConfiguration *configuration = nil; + configuration = [NSURLSessionConfiguration pn_ephemeralSessionConfigurationWithIdentifier:self.identifier]; configuration.HTTPShouldUsePipelining = !self.forLongPollRequests; configuration.timeoutIntervalForRequest = timeout; configuration.HTTPMaximumConnectionsPerHost = maximumConnections; diff --git a/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/iOS Tests (ObjC).xcscheme b/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/iOS Tests (ObjC).xcscheme index 5991c11eb..33e0b22c8 100644 --- a/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/iOS Tests (ObjC).xcscheme +++ b/Tests/PubNub Tests.xcodeproj/xcshareddata/xcschemes/iOS Tests (ObjC).xcscheme @@ -126,7 +126,7 @@