diff --git a/DBDebugToolkit/Classes/Network/DBNetworkToolkit.m b/DBDebugToolkit/Classes/Network/DBNetworkToolkit.m index 8647bfb..9a1c37a 100644 --- a/DBDebugToolkit/Classes/Network/DBNetworkToolkit.m +++ b/DBDebugToolkit/Classes/Network/DBNetworkToolkit.m @@ -28,6 +28,7 @@ @interface DBNetworkToolkit () @property (nonatomic, copy) NSMutableArray *requests; @property (nonatomic, strong) NSMapTable *runningRequestsModels; +@property (nonatomic, strong) NSOperationQueue *operationQueue; @end @@ -38,6 +39,7 @@ @implementation DBNetworkToolkit - (instancetype)init { self = [super init]; if (self) { + [self setupOperationQueue]; [self resetLoggedData]; } @@ -58,6 +60,11 @@ + (void)setupURLProtocol { [NSURLProtocol registerClass:[DBURLProtocol class]]; } +- (void)setupOperationQueue { + self.operationQueue = [NSOperationQueue new]; + self.operationQueue.maxConcurrentOperationCount = 1; +} + #pragma mark - Logging settings - (void)setLoggingEnabled:(BOOL)loggingEnabled { @@ -70,9 +77,11 @@ - (void)setLoggingEnabled:(BOOL)loggingEnabled { } - (void)resetLoggedData { - _requests = [NSMutableArray array]; - _runningRequestsModels = [NSMapTable strongToWeakObjectsMapTable]; - [self removeOldSavedRequests]; + [self.operationQueue addOperationWithBlock:^{ + _requests = [NSMutableArray array]; + _runningRequestsModels = [NSMapTable strongToWeakObjectsMapTable]; + [self removeOldSavedRequests]; + }]; } #pragma mark - Saving request data @@ -94,19 +103,23 @@ - (NSString *)savedRequestsPath { } - (void)saveRequest:(NSURLRequest *)request { - DBRequestModel *requestModel = [DBRequestModel requestModelWithRequest:request]; - requestModel.delegate = self; - [self.runningRequestsModels setObject:requestModel forKey:request.description]; - [self.requests addObject:requestModel]; - [self.delegate networkDebugToolkitDidUpdateRequestsList:self]; + [self.operationQueue addOperationWithBlock:^{ + DBRequestModel *requestModel = [DBRequestModel requestModelWithRequest:request]; + requestModel.delegate = self; + [self.runningRequestsModels setObject:requestModel forKey:request.description]; + [self.requests addObject:requestModel]; + [self.delegate networkDebugToolkitDidUpdateRequestsList:self]; + }]; } - (void)saveRequestOutcome:(DBRequestOutcome *)requestOutcome forRequest:(NSURLRequest *)request { - DBRequestModel *requestModel = [self.runningRequestsModels objectForKey:request.description]; - [requestModel saveOutcome:requestOutcome]; - [requestModel saveBodyWithData:request.HTTPBody inputStream:request.HTTPBodyStream]; - [self.runningRequestsModels removeObjectForKey:request.description]; - [self didUpdateRequestModel:requestModel]; + [self.operationQueue addOperationWithBlock:^{ + DBRequestModel *requestModel = [self.runningRequestsModels objectForKey:request.description]; + [requestModel saveOutcome:requestOutcome]; + [requestModel saveBodyWithData:request.HTTPBody inputStream:request.HTTPBodyStream]; + [self.runningRequestsModels removeObjectForKey:request.description]; + [self didUpdateRequestModel:requestModel]; + }]; } - (NSArray *)savedRequests { @@ -120,8 +133,10 @@ - (void)requestModelDidFinishSynchronization:(DBRequestModel *)requestModel { } - (void)didUpdateRequestModel:(DBRequestModel *)requestModel { - NSInteger requestIndex = [self.requests indexOfObject:requestModel]; - [self.delegate networkDebugToolkit:self didUpdateRequestAtIndex:requestIndex]; + [self.operationQueue addOperationWithBlock:^{ + NSInteger requestIndex = [self.requests indexOfObject:requestModel]; + [self.delegate networkDebugToolkit:self didUpdateRequestAtIndex:requestIndex]; + }]; } @end diff --git a/DBDebugToolkit/Classes/Network/DBNetworkViewController.m b/DBDebugToolkit/Classes/Network/DBNetworkViewController.m index b10a95c..eb95114 100644 --- a/DBDebugToolkit/Classes/Network/DBNetworkViewController.m +++ b/DBDebugToolkit/Classes/Network/DBNetworkViewController.m @@ -25,6 +25,7 @@ #import "NSBundle+DBDebugToolkit.h" #import "DBNetworkSettingsTableViewController.h" #import "DBRequestDetailsViewController.h" +#import "NSOperationQueue+DBMainQueueOperation.h" static NSString *const DBNetworkViewControllerRequestCellIdentifier = @"DBRequestTableViewCell"; @@ -32,10 +33,11 @@ @interface DBNetworkViewController () + +typedef void(^DBMainQueueOperationBlock)(void); + +/** + `DBMainQueueOperation` is a `NSOperation` subclass running a given block on a main queue. + */ +@interface DBMainQueueOperation : NSOperation + +/** + Initializes `DBMainQueueOperation` object with a block. + + @param block The block that will be invoked on the main queue. + */ +- (instancetype)initWithMainQueueOperationBlock:(DBMainQueueOperationBlock)block; + +/** + Creates and returns a new `DBMainQueueOperation` instance encapsulating a given block. + + @param block The block that will be invoked on the main queue. + */ ++ (instancetype)mainQueueOperationWithBlock:(DBMainQueueOperationBlock)block; + +@end diff --git a/DBDebugToolkit/Classes/Network/MainQueueOperation/DBMainQueueOperation.m b/DBDebugToolkit/Classes/Network/MainQueueOperation/DBMainQueueOperation.m new file mode 100644 index 0000000..33c1806 --- /dev/null +++ b/DBDebugToolkit/Classes/Network/MainQueueOperation/DBMainQueueOperation.m @@ -0,0 +1,97 @@ +// The MIT License +// +// Copyright (c) 2016 Dariusz Bukowski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "DBMainQueueOperation.h" + +typedef NS_ENUM(NSUInteger, DBMainQueueOperationState) { + DBMainQueueOperationStateNotStarted, + DBMainQueueOperationStateStarted, + DBMainQueueOperationStateFinished +}; + +@interface DBMainQueueOperation () + +@property (nonatomic, assign) DBMainQueueOperationState state; +@property (nonatomic, copy) DBMainQueueOperationBlock block; + +@end + +@implementation DBMainQueueOperation + +#pragma mark - Initialization + +- (instancetype)initWithMainQueueOperationBlock:(DBMainQueueOperationBlock)block { + self = [super init]; + if (self) { + self.block = block; + self.state = DBMainQueueOperationStateNotStarted; + } + + return self; +} + ++ (instancetype)mainQueueOperationWithBlock:(DBMainQueueOperationBlock)block { + return [[self alloc] initWithMainQueueOperationBlock:block]; +} + +#pragma mark - NSOperation methods + +- (void)start { + if (self.isCancelled) { + [self willChangeValueForKey:@"isFinished"]; + self.state = DBMainQueueOperationStateFinished; + [self didChangeValueForKey:@"isFinished"]; + return; + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [self willChangeValueForKey:@"isExecuting"]; + self.state = DBMainQueueOperationStateStarted; + [self didChangeValueForKey:@"isExecuting"]; + + if (self.block) { + self.block(); + } + + [self willChangeValueForKey:@"isFinished"]; + [self willChangeValueForKey:@"isExecuting"]; + + self.state = DBMainQueueOperationStateFinished; + + [self didChangeValueForKey:@"isFinished"]; + [self didChangeValueForKey:@"isExecuting"]; + }); +} + +- (BOOL)isFinished { + return self.state == DBMainQueueOperationStateFinished; +} + +- (BOOL)isExecuting { + return self.state == DBMainQueueOperationStateStarted; +} + +- (BOOL)isAsynchronous { + return NO; +} + +@end diff --git a/DBDebugToolkit/Classes/Network/MainQueueOperation/NSOperationQueue+DBMainQueueOperation.h b/DBDebugToolkit/Classes/Network/MainQueueOperation/NSOperationQueue+DBMainQueueOperation.h new file mode 100644 index 0000000..6745040 --- /dev/null +++ b/DBDebugToolkit/Classes/Network/MainQueueOperation/NSOperationQueue+DBMainQueueOperation.h @@ -0,0 +1,38 @@ +// The MIT License +// +// Copyright (c) 2016 Dariusz Bukowski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "DBMainQueueOperation.h" + +/** + `NSOperationQueue` category that provides a helper method for adding a single main queue operation. + */ +@interface NSOperationQueue (DBMainQueueOperation) + +/** + Adds a single main queue operation encapsulating a given block. + + @param block The block that will be invoked on the main queue. + */ +- (void)addMainQueueOperationWithBlock:(DBMainQueueOperationBlock)block; + +@end diff --git a/DBDebugToolkit/Classes/Network/MainQueueOperation/NSOperationQueue+DBMainQueueOperation.m b/DBDebugToolkit/Classes/Network/MainQueueOperation/NSOperationQueue+DBMainQueueOperation.m new file mode 100644 index 0000000..cef4076 --- /dev/null +++ b/DBDebugToolkit/Classes/Network/MainQueueOperation/NSOperationQueue+DBMainQueueOperation.m @@ -0,0 +1,32 @@ +// The MIT License +// +// Copyright (c) 2016 Dariusz Bukowski +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "NSOperationQueue+DBMainQueueOperation.h" + +@implementation NSOperationQueue (DBMainQueueOperation) + +- (void)addMainQueueOperationWithBlock:(DBMainQueueOperationBlock)block { + DBMainQueueOperation *operation = [DBMainQueueOperation mainQueueOperationWithBlock:block]; + [self addOperation:operation]; +} + +@end diff --git a/Example/Pods/Pods.xcodeproj/project.pbxproj b/Example/Pods/Pods.xcodeproj/project.pbxproj index b81155d..4369bce 100644 --- a/Example/Pods/Pods.xcodeproj/project.pbxproj +++ b/Example/Pods/Pods.xcodeproj/project.pbxproj @@ -137,6 +137,10 @@ 64B548E3AB2256AB9C146256D3B22CB8 /* DBRequestTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 67EDE0347F4D9BE11E27DB2B9717A5E2 /* DBRequestTableViewCell.xib */; }; 64C46AF200F2347115A0DF2799D6E403 /* EXPMatchers+beNil.h in Headers */ = {isa = PBXBuildFile; fileRef = 87A19FC30FAE97EDA655018A6AD2D54F /* EXPMatchers+beNil.h */; settings = {ATTRIBUTES = (Public, ); }; }; 660DF2113379816D613CB27674A39A5A /* DBMenuChartTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 49C9C3601900D5195FD887F307B833EA /* DBMenuChartTableViewCell.m */; }; + 665357C2206EB2BE0039283E /* DBMainQueueOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 665357C0206EB2BE0039283E /* DBMainQueueOperation.h */; }; + 665357C3206EB2BE0039283E /* DBMainQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 665357C1206EB2BE0039283E /* DBMainQueueOperation.m */; }; + 665357C7206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 665357C5206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.h */; }; + 665357C8206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 665357C6206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.m */; }; 674928482313C4839BB796BB5512C706 /* DBCoreDataFilterSettingsTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 13D6D34556E68BED6D8A4F8888488738 /* DBCoreDataFilterSettingsTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6DA8288AA319C90AD77F02AA3F2BEE86 /* DBPerformanceToolkit.h in Headers */ = {isa = PBXBuildFile; fileRef = 703728399E24BD01B9D22FEA16A228D5 /* DBPerformanceToolkit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 6E0697AF839202F074E453EBA81F9E22 /* DBCustomVariable.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DDB3779F28EF292225E2298C2394EFC /* DBCustomVariable.m */; }; @@ -505,6 +509,10 @@ 64A8DD727D1222D24419695D774DF8D3 /* DBNetworkToolkit.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = DBNetworkToolkit.m; sourceTree = ""; }; 65A4C129362F92A4AC55DECBC1525662 /* DBCrashReport.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = DBCrashReport.m; sourceTree = ""; }; 65DA28E34D6B2634B0D3632970B9AFD0 /* EXPMatchers+raiseWithReason.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "EXPMatchers+raiseWithReason.h"; path = "Expecta/Matchers/EXPMatchers+raiseWithReason.h"; sourceTree = ""; }; + 665357C0206EB2BE0039283E /* DBMainQueueOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DBMainQueueOperation.h; sourceTree = ""; }; + 665357C1206EB2BE0039283E /* DBMainQueueOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DBMainQueueOperation.m; sourceTree = ""; }; + 665357C5206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSOperationQueue+DBMainQueueOperation.h"; sourceTree = ""; }; + 665357C6206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSOperationQueue+DBMainQueueOperation.m"; sourceTree = ""; }; 67324AA26715C0742B62E59D0AAB374C /* EXPMatchers+beTruthy.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = "EXPMatchers+beTruthy.h"; path = "Expecta/Matchers/EXPMatchers+beTruthy.h"; sourceTree = ""; }; 67473F09A0FADF52D476EA88F48CFA54 /* EXPExpect.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = EXPExpect.h; path = Expecta/EXPExpect.h; sourceTree = ""; }; 67EDE0347F4D9BE11E27DB2B9717A5E2 /* DBRequestTableViewCell.xib */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.xib; path = DBRequestTableViewCell.xib; sourceTree = ""; }; @@ -1182,6 +1190,17 @@ path = URLProtocol; sourceTree = ""; }; + 665357C4206EB2CD0039283E /* MainQueueOperation */ = { + isa = PBXGroup; + children = ( + 665357C0206EB2BE0039283E /* DBMainQueueOperation.h */, + 665357C1206EB2BE0039283E /* DBMainQueueOperation.m */, + 665357C5206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.h */, + 665357C6206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.m */, + ); + path = MainQueueOperation; + sourceTree = ""; + }; 673D44BD40F44B9A5BBE927F247B6599 /* DBDebugToolkit */ = { isa = PBXGroup; children = ( @@ -1450,6 +1469,7 @@ D3BA2A7F212DC29F7295B77450CBEC7B /* Network */ = { isa = PBXGroup; children = ( + 665357C4206EB2CD0039283E /* MainQueueOperation */, 6D4ADB81BBDB01BC57052989A50C0628 /* DBBodyPreviewViewController.h */, FD55AD560F518C40EA25DE6978768083 /* DBBodyPreviewViewController.m */, 6357D213325FF9862EF2563BF9C556DF /* DBNetworkSettingsTableViewController.h */, @@ -1631,8 +1651,10 @@ E479705D0AED1B4E31E1C1ECC2F3151A /* NSBundle+DBDebugToolkit.h in Headers */, 1728F9F397284A63D26E796D37557675 /* NSObject+DBDebugToolkit.h in Headers */, D9CDD7F491CF3334D997BC677D9A9DA6 /* NSPersistentStoreCoordinator+DBCoreDataToolkit.h in Headers */, + 665357C2206EB2BE0039283E /* DBMainQueueOperation.h in Headers */, C0FB72B76CB035FE0CE3CB6BBE5FF802 /* NSURLSessionConfiguration+DBURLProtocol.h in Headers */, 01A5C4F6987ADAFF12C15787E2069262 /* UIColor+DBUserInterfaceToolkit.h in Headers */, + 665357C7206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.h in Headers */, 1865AA59C3155E8F7DF47F3DC766036B /* UILabel+DBDebugToolkit.h in Headers */, E440079B1CD43DFF45E6DF8A0C39CFD1 /* UIView+DBUserInterfaceToolkit.h in Headers */, F8AB62C63005A31E05F307F2DDF8C6C9 /* UIView+Snapshot.h in Headers */, @@ -1988,6 +2010,7 @@ 2ED8F168191253613C0ABC9BBC0C189E /* DBCustomActionsTableViewController.m in Sources */, 5C852410D970AFB1B6448048EE7A164C /* DBCustomLocationViewController.m in Sources */, 6E0697AF839202F074E453EBA81F9E22 /* DBCustomVariable.m in Sources */, + 665357C8206EB3020039283E /* NSOperationQueue+DBMainQueueOperation.m in Sources */, CF2B82151B06C98A9DCE5C5D75ED6158 /* DBCustomVariablesTableViewController.m in Sources */, C265D42FB2C45F1CA132D1CC93466F20 /* DBDebugToolkit-dummy.m in Sources */, 60AE36D0EC5EFC789FBC083E7917129A /* DBDebugToolkit.m in Sources */, @@ -1998,6 +2021,7 @@ 0BEF5A77B860C38BC963D88D19A20605 /* DBFontFamiliesTableViewController.m in Sources */, C1D4FC04CB48C0DCB633B55A02DD389D /* DBFontPreviewViewController.m in Sources */, 2B66F79DDC5C79ABD182C02B6EDB5C3B /* DBFPSCalculator.m in Sources */, + 665357C3206EB2BE0039283E /* DBMainQueueOperation.m in Sources */, C8A3C5D99FA5B9E09F369547A56A2D4D /* DBImageViewViewController.m in Sources */, A132B81953974E4EE646D6C8B55D305B /* DBKeychainToolkit.m in Sources */, AAD0C01A340B7F8AD2F5C5830C9E5361 /* DBLocationTableViewController.m in Sources */,