├── Pod ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── iOS │ ├── Conditions │ │ ├── OPPhotosCondition.h │ │ ├── OPAudioCondition.h │ │ ├── OPVideoCondition.h │ │ ├── OPLocationCondition.h │ │ ├── OPOperationConditionUserNotification.h │ │ ├── OPRemoteNotificationCondition.h │ │ ├── OPAudioCondition.m │ │ ├── OPVideoCondition.m │ │ ├── OPPhotosCondition.m │ │ └── OPOperationConditionUserNotification.m │ ├── Observers │ │ ├── OPNetworkObserver.h │ │ ├── OPBackgroundObserver.h │ │ ├── OPBackgroundObserver.m │ │ └── OPNetworkObserver.m │ ├── Categories │ │ ├── UIUserNotificationSettings+Operative.h │ │ └── UIUserNotificationSettings+Operative.m │ └── Operations │ │ ├── Misc │ │ ├── OPMediaPermissionOperation.h │ │ ├── OPLocationOperation.h │ │ ├── OPMediaPermissionOperation.m │ │ └── OPLocationOperation.m │ │ └── UI │ │ ├── OPAlertOperation.h │ │ └── OPAlertOperation.m │ ├── Core │ ├── Categories │ │ ├── NSOperation+Operative.h │ │ ├── NSMutableDictionary+Operative.h │ │ ├── NSMutableDictionary+Operative.m │ │ ├── NSError+Operative.h │ │ ├── NSError+Operative.m │ │ └── NSOperation+Operative.m │ ├── Conditions │ │ ├── OPOperationConditionEvaluator.h │ │ ├── OPNoCancelledDependenciesCondition.h │ │ ├── OPReachabilityCondition.h │ │ ├── OPNegatedCondition.h │ │ ├── OPSilentCondition.h │ │ ├── OPSilentCondition.m │ │ ├── OPOperationConditionMutuallyExclusive.h │ │ ├── OPNoCancelledDependenciesCondition.m │ │ ├── OPOperationConditionMutuallyExclusive.m │ │ ├── OPOperationConditionEvaluator.m │ │ ├── OPOperationCondition.h │ │ ├── OPNegatedCondition.m │ │ └── OPReachabilityCondition.m │ ├── Observers │ │ ├── OPTimeoutObserver.h │ │ ├── OPOperationObserver.h │ │ ├── OPBlockObserver.h │ │ ├── OPBlockObserver.m │ │ └── OPTimeoutObserver.m │ ├── Operations │ │ ├── Misc │ │ │ ├── OPDelayOperation.h │ │ │ ├── OPBlockOperation.m │ │ │ ├── OPDelayOperation.m │ │ │ ├── OPBlockOperation.h │ │ │ ├── OPGroupOperation.h │ │ │ └── OPGroupOperation.m │ │ ├── Networking │ │ │ ├── OPURLSessionTaskOperation.h │ │ │ └── OPURLSessionTaskOperation.m │ │ └── OPOperation.h │ └── Operation Queue │ │ ├── OPExclusivityController.h │ │ ├── OPOperationQueue.h │ │ └── OPExclusivityController.m │ └── Operative.h ├── _Carthage.xcodeproj ├── Example ├── .gitignore ├── Tests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── Tests-Info.plist │ ├── Tests.m │ ├── BlockObserversTests.m │ └── CategoriesTests.m ├── Operative │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── GroupOperationTest.h │ ├── Operative-Prefix.pch │ ├── main.m │ ├── GroupOperationTest.m │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── OPViewController.h │ ├── OPAppDelegate.h │ ├── Main.storyboard │ ├── Operative-Info.plist │ ├── OPAppDelegate.m │ └── OPViewController.m ├── Operative.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── Operative-Example.xcscheme └── Podfile ├── LICENSE ├── .gitignore ├── README.md ├── .travis.yml └── Operative.podspec /Pod/Assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Pod/Classes/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_Carthage.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj -------------------------------------------------------------------------------- /Example/.gitignore: -------------------------------------------------------------------------------- 1 | Pods 2 | *.xcworkspace 3 | Podfile.lock -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Operative/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/Operative.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Operative/GroupOperationTest.h: -------------------------------------------------------------------------------- 1 | // 2 | // GroupOperationTest.h 3 | // Operative 4 | // 5 | // Created by Tom Wilson on 20/06/2015. 6 | // Copyright (c) 2015 Tom Wilson. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface GroupOperationTest : OPGroupOperation 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | 3 | # Cannot use frameworks until min deployment set to 8.0 4 | # use_frameworks! 5 | 6 | target 'Operative_Example', :exclusive => true do 7 | pod "Operative", :path => "../" 8 | end 9 | 10 | target 'Operative_Tests', :exclusive => true do 11 | pod "Operative", :path => "../" 12 | end 13 | -------------------------------------------------------------------------------- /Example/Operative/Operative-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/Operative/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Operative 4 | // 5 | // Created by Tom Wilson on 06/16/2015. 6 | // Copyright (c) 2014 Tom Wilson. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "OPAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([OPAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Operative/GroupOperationTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // GroupOperationTest.m 3 | // Operative 4 | // 5 | // Created by Tom Wilson on 20/06/2015. 6 | // Copyright (c) 2015 Tom Wilson. All rights reserved. 7 | // 8 | 9 | #import "GroupOperationTest.h" 10 | 11 | @implementation GroupOperationTest 12 | 13 | - (instancetype) init 14 | { 15 | self = [super init]; 16 | if (self) 17 | { 18 | OPBlockOperation *block; 19 | for (int i = 0; i < 10; i++) 20 | { 21 | OPBlockOperation *previous = nil; 22 | if (block) 23 | previous = block; 24 | 25 | block = [[OPBlockOperation alloc] initWithBlock:^(void(^completion)(void)) { 26 | NSLog(@"Operation %i", i); 27 | completion(); 28 | }]; 29 | 30 | if (previous) 31 | { 32 | [block addDependency:previous]; 33 | } 34 | 35 | [self addOperation:block]; 36 | } 37 | } 38 | return self; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Example/Operative/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Tom Wilson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | # OS X 6 | .DS_Store 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | 23 | # Bundler 24 | .bundle 25 | .clang-format 26 | 27 | # AppCode 28 | .idea 29 | 30 | ## Other 31 | *.xccheckout 32 | profile 33 | *.moved-aside 34 | *.xcuserstate 35 | *.xcscmblueprint 36 | 37 | ## Obj-C/Swift specific 38 | *.hmap 39 | *.ipa 40 | 41 | # vim 42 | *.swp 43 | 44 | # CocoaPods 45 | # 46 | # We recommend against adding the Pods directory to your .gitignore. However 47 | # you should judge for yourself, the pros and cons are mentioned at: 48 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 49 | # 50 | # Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | # Carthage/Checkouts 56 | 57 | Carthage/Build 58 | Carthage.pkg 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Operative 2 | 3 | [![CI Status](http://img.shields.io/travis/Kabal/Operative.svg?style=flat)](https://travis-ci.org/Kabal/Operative) 4 | [![Version](https://img.shields.io/cocoapods/v/Operative.svg?style=flat)](http://cocoapods.org/pods/Operative) 5 | [![License](https://img.shields.io/cocoapods/l/Operative.svg?style=flat)](http://cocoapods.org/pods/Operative) 6 | [![Platform](https://img.shields.io/cocoapods/p/Operative.svg?style=flat)](http://cocoapods.org/pods/Operative) 7 | 8 | Objective-C port of the Swift code provided for the WWDC presentation "Advanced NSOperations" 9 | 10 | Not really tested yet.. probably has bugs. 11 | 12 | TODO: 13 | - Not all of the 'Conditions' are ported yet 14 | - Better example app 15 | - Tests!?! 16 | 17 | 18 | ## Usage 19 | 20 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 21 | 22 | ## Requirements 23 | 24 | ## Installation 25 | 26 | Operative is available through [CocoaPods](http://cocoapods.org). To install 27 | it, simply add the following line to your Podfile: 28 | 29 | ```ruby 30 | pod "Operative" 31 | ``` 32 | 33 | ## Author 34 | 35 | Tom Wilson, tom@toms-stuff.net 36 | 37 | ## License 38 | 39 | Operative is available under the MIT license. See the LICENSE file for more info. 40 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * http://www.objc.io/issue-6/travis-ci.html 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | language: objective-c 6 | osx_image: beta-xcode6.3 7 | cache: cocoapods 8 | podfile: Example/Podfile 9 | env: 10 | global: 11 | - LC_CTYPE=en.US.UTF-8 12 | - LANG=en_US.UTF_8 13 | matrix: 14 | - DESTINATION="OS=8.3,name=iPhone 6 Plus" SCHEME="Operative-Example" SDK=iphonesimulator8.3 BUILD_EXAMPLE="YES" POD_LINT="YES" 15 | before_install: 16 | - gem install cocoapods # Since Travis is not always on latest version 17 | - pod install --project-directory=Example 18 | install: 19 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 20 | script: 21 | - set -o pipefail 22 | - if [ $BUILD_EXAMPLE == "YES" ]; then 23 | xcodebuild -workspace "Example/Operative.xcworkspace" -scheme "Operative-Example" -sdk "$SDK" -destination "$DESTINATION" 24 | -configuration Debug ONLY_ACTIVE_ARCH=NO test | xcpretty -c; 25 | fi 26 | - if [ $BUILD_EXAMPLE == "YES" ]; then 27 | xcodebuild -workspace "Example/Operative.xcworkspace" -scheme "Operative-Example" -sdk "$SDK" -destination "$DESTINATION" 28 | -configuration Release ONLY_ACTIVE_ARCH=NO test | xcpretty -c; 29 | fi 30 | - if [ $POD_LINT == "YES" ]; then 31 | pod lib lint --quick; 32 | fi 33 | -------------------------------------------------------------------------------- /Example/Operative/OPViewController.h: -------------------------------------------------------------------------------- 1 | // OPViewController.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | @import UIKit; 23 | 24 | @interface OPViewController : UIViewController 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // OperativeTests.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | @interface Tests : XCTestCase 25 | 26 | @end 27 | 28 | @implementation Tests 29 | 30 | @end -------------------------------------------------------------------------------- /Example/Operative/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Example/Operative/OPAppDelegate.h: -------------------------------------------------------------------------------- 1 | // OPAppDelegate.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | @import UIKit; 23 | 24 | @interface OPAppDelegate : UIResponder 25 | 26 | @property (strong, nonatomic) UIWindow *window; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPPhotosCondition.h: -------------------------------------------------------------------------------- 1 | // OPPhotosCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | /** 25 | * A condition for verifying access to the user's Photos library. 26 | */ 27 | @interface OPPhotosCondition : NSObject 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPAudioCondition.h: -------------------------------------------------------------------------------- 1 | // OPAudioCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | /** 25 | * A condition for verifying microphone permission using AVMediaTypeAudio 26 | */ 27 | @interface OPAudioCondition : NSObject 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPVideoCondition.h: -------------------------------------------------------------------------------- 1 | // OPVideoCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | 23 | #import "OPOperationCondition.h" 24 | 25 | /** 26 | * A condition for verifying camera permission using AVMediaTypeVideo. 27 | */ 28 | @interface OPVideoCondition : NSObject 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Categories/NSOperation+Operative.h: -------------------------------------------------------------------------------- 1 | // NSOperation+Operative.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | 25 | @interface NSOperation (Operative) 26 | 27 | - (void)addCompletionBlock:(void (^)(void))block; 28 | 29 | - (void)addDependencies:(NSArray *)dependencies; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Categories/NSMutableDictionary+Operative.h: -------------------------------------------------------------------------------- 1 | // NSMutableDictionary+Operative.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | 25 | @interface NSMutableDictionary (Operative) 26 | 27 | + (NSMutableDictionary *)sequence:(id )sequence keyMapper:(id (^)(id obj))keyMapper; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Observers/OPNetworkObserver.h: -------------------------------------------------------------------------------- 1 | // OPNetworkObserver.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationObserver.h" 23 | 24 | 25 | /** 26 | * An `OPOperationObserver` that will cause the network activity indicator 27 | * to appear as long as the `OPOperation` to which it is attached is executing. 28 | */ 29 | @interface OPNetworkObserver : NSObject 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPOperationConditionEvaluator.h: -------------------------------------------------------------------------------- 1 | // OPOperationConditionEvaluator.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperation.h" 23 | 24 | 25 | @interface OPOperationConditionEvaluator : NSObject 26 | 27 | + (void)evaluateConditions:(NSArray *)conditions 28 | operation:(OPOperation *)operation 29 | completion:(void (^)(NSArray *failures))completion; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPNoCancelledDependenciesCondition.h: -------------------------------------------------------------------------------- 1 | // OPNoCancelledDependenciesCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | /** 25 | * A condition that specifies that every dependency must have succeeded. 26 | * If any dependency was cancelled, the target operation will be cancelled as 27 | * well. 28 | */ 29 | @interface OPNoCancelledDependenciesCondition : NSObject 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Categories/UIUserNotificationSettings+Operative.h: -------------------------------------------------------------------------------- 1 | // UIUserNotificationSettings+Operative.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | 23 | #if TARGET_OS_IPHONE 24 | 25 | #import 26 | 27 | 28 | @interface UIUserNotificationSettings (Operative) 29 | 30 | - (BOOL)containsSettings:(UIUserNotificationSettings *)settings; 31 | 32 | - (UIUserNotificationSettings *)settingsByMerging:(UIUserNotificationSettings *)settings; 33 | 34 | @end 35 | 36 | #endif -------------------------------------------------------------------------------- /Pod/Classes/iOS/Operations/Misc/OPMediaPermissionOperation.h: -------------------------------------------------------------------------------- 1 | // OPMediaPermissionOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperation.h" 23 | 24 | /** 25 | * `OPMediaPermissionOperation` is an `OPOperation` subclass to request 26 | * permission to use the device's video or audio media type. 27 | * 28 | - returns: An instance of `OPMediaPermissionOperation` 29 | */ 30 | @interface OPMediaPermissionOperation : OPOperation 31 | 32 | - (instancetype)initWithMediaType:(NSString *)mediaType NS_DESIGNATED_INITIALIZER; 33 | 34 | - (instancetype)init NS_UNAVAILABLE; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Example/Operative/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Categories/NSMutableDictionary+Operative.m: -------------------------------------------------------------------------------- 1 | // NSMutableDictionary+Operative.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "NSMutableDictionary+Operative.h" 23 | 24 | 25 | @implementation NSMutableDictionary (Operative) 26 | 27 | + (NSMutableDictionary *)sequence:(id )sequence keyMapper:(id (^)(id obj))keyMapper 28 | { 29 | NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; 30 | for (id obj in sequence) { 31 | id key = keyMapper(obj); 32 | if (key) { 33 | dict[key] = obj; 34 | } 35 | } 36 | return dict; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Observers/OPTimeoutObserver.h: -------------------------------------------------------------------------------- 1 | // OPTimeoutObserver.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationObserver.h" 23 | 24 | 25 | /** 26 | * `OPTimeoutObserver` is a way to make an `OPOperation` automatically 27 | * time out and cancel after a specified time interval. 28 | * 29 | * - returns: An instance of an `OPTimeoutObserver` 30 | */ 31 | @interface OPTimeoutObserver : NSObject 32 | 33 | - (instancetype)initWithTimeout:(NSTimeInterval)timeout NS_DESIGNATED_INITIALIZER; 34 | 35 | /** 36 | * Unused `-init` method. 37 | * @see -initWithTimeout: 38 | */ 39 | - (instancetype)init NS_UNAVAILABLE; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Observers/OPBackgroundObserver.h: -------------------------------------------------------------------------------- 1 | // OPBackgroundObserver.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | #import "OPOperationObserver.h" 25 | 26 | 27 | /** 28 | * `OPBackgroundObserver` is an `OPOperationObserver` that will automatically begin 29 | * and end a background task if the application transitions to the background. 30 | * This would be useful if you had a vital `OPOperation` whose execution *must* complete, 31 | * regardless of the activation state of the app. Some kinds network connections 32 | * may fall in to this category, for example. 33 | */ 34 | @interface OPBackgroundObserver : NSObject 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Categories/NSError+Operative.h: -------------------------------------------------------------------------------- 1 | // NSError+Operative.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | 25 | extern NSString *const kOPOperationErrorDomain; 26 | extern NSString *const kOPOperationConditionKey; 27 | extern NSString *const kOPOperationNegatedConditionKey; 28 | 29 | typedef NS_ENUM(NSUInteger, OPOperationErrorCode) { 30 | OPOperationErrorCodeConditionFailed = 1, 31 | OPOperationErrorCodeExecutionFailed 32 | }; 33 | 34 | 35 | @interface NSError (Operative) 36 | 37 | + (instancetype)errorWithCode:(OPOperationErrorCode)code; 38 | 39 | + (instancetype)errorWithCode:(OPOperationErrorCode)code userInfo:(NSDictionary *)userInfo; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Example/Operative/Operative-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | NSLocationWhenInUseUsageDescription 28 | Tracking your every waking movement. 29 | UIMainStoryboardFile 30 | Main 31 | UIMainStoryboardFile~ipad 32 | Main_iPad 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Categories/NSError+Operative.m: -------------------------------------------------------------------------------- 1 | // NSError+Operative.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "NSError+Operative.h" 23 | 24 | 25 | NSString *const kOPOperationErrorDomain = @"OPOperationErrors"; 26 | NSString *const kOPOperationConditionKey = @"OPOperationCondition"; 27 | NSString *const kOPOperationNegatedConditionKey = @"OPOperationNegatedCondition"; 28 | 29 | 30 | @implementation NSError (Operative) 31 | 32 | + (instancetype)errorWithCode:(OPOperationErrorCode)code 33 | { 34 | return [NSError errorWithCode:code userInfo:nil]; 35 | } 36 | 37 | + (instancetype)errorWithCode:(OPOperationErrorCode)code userInfo:(NSDictionary *)userInfo 38 | { 39 | return [NSError errorWithDomain:kOPOperationErrorDomain code:code userInfo:userInfo]; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPReachabilityCondition.h: -------------------------------------------------------------------------------- 1 | // OPReachabilityCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | 25 | /** 26 | * This is a condition that performs a very high-level reachability check. 27 | * It does *not* perform a long-running reachability check, nor does it 28 | * respond to changes in reachability. Reachability is evaluated once when 29 | * the operation to which this is attached is asked about its readiness. 30 | */ 31 | @interface OPReachabilityCondition : NSObject 32 | 33 | - (instancetype)initWithHost:(NSURL *)host NS_DESIGNATED_INITIALIZER; 34 | 35 | /** 36 | * Unused `-init` method. 37 | * @see -initWithHost: 38 | */ 39 | - (instancetype)init NS_UNAVAILABLE; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Observers/OPOperationObserver.h: -------------------------------------------------------------------------------- 1 | // OPOperationObserver.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | @class OPOperation; 25 | 26 | @protocol OPOperationObserver 27 | 28 | // Invoked immediately prior to the `OPOperation`'s `-execute` method. 29 | - (void)operationDidStart:(OPOperation *)operation; 30 | 31 | // Invoked when `OPOperation`'s `-produceOperation:` is executed. 32 | - (void)operation:(OPOperation *)operation didProduceOperation:(NSOperation *)newOperation; 33 | 34 | /** 35 | * Invoked as an `OPOperation` finishes, along with any errors produced during 36 | * execution (or readiness evaluation). 37 | */ 38 | - (void)operation:(OPOperation *)operation didFinishWithErrors:(NSArray *)errors; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Categories/NSOperation+Operative.m: -------------------------------------------------------------------------------- 1 | // NSOperation+Operative.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "NSOperation+Operative.h" 23 | 24 | 25 | @implementation NSOperation (Operative) 26 | 27 | - (void)addCompletionBlock:(void (^)(void))block 28 | { 29 | // If we already have a completion block 30 | if ([self completionBlock]) { 31 | // Construct a new block that calls the existing block 32 | void (^existing)(void) = [self.completionBlock copy]; 33 | 34 | self.completionBlock = ^{ 35 | existing(); 36 | block(); 37 | }; 38 | } else { 39 | [self setCompletionBlock:block]; 40 | } 41 | } 42 | 43 | - (void)addDependencies:(NSArray *)dependencies 44 | { 45 | for (NSOperation *dependency in dependencies) { 46 | [self addDependency:dependency]; 47 | } 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Operative.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint Operative.podspec' to ensure this is a 3 | # valid spec and remove all comments before submitting the spec. 4 | # 5 | # Any lines starting with a # are optional, but encouraged 6 | # 7 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 8 | # 9 | 10 | Pod::Spec.new do |s| 11 | s.name = "Operative" 12 | s.version = "0.1.0" 13 | s.summary = "Advanced NSOperations. Objective-C Port of the sample code in the Apple WWDC 2015 presentation \"Advanced NSOperations\"" 14 | s.description = <<-DESC 15 | 16 | Provides a NSOperation sublass with a more advanced state machine. 17 | 18 | Some features provided: 19 | - Easily perform asynchronous 'work' in an operation - even displaying UI such as UIAlertController's 20 | - Optionally support 'exclusiviity' guarantees across mulitple instances of the same operation class, even across multiple queues! 21 | - Operation delegate - be informed when an operation starts, finishes, or produces sub-operations 22 | 23 | DESC 24 | s.homepage = "https://github.com/Kabal/Operative" 25 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2" 26 | s.license = 'MIT' 27 | s.author = { "Tom Wilson" => "tom@toms-stuff.net" } 28 | s.source = { :git => "https://github.com/Kabal/Operative.git", :tag => s.version.to_s } 29 | s.social_media_url = 'https://twitter.com/tomwilson' 30 | 31 | s.ios.deployment_target = '8.0' 32 | s.osx.deployment_target = '10.10' 33 | s.requires_arc = true 34 | 35 | s.source_files = 'Pod/Classes/Operative.h' 36 | s.ios.source_files = 'Pod/Classes/{Core,iOS}/**/*' 37 | s.osx.source_files = 'Pod/Classes/{Core,OSX}/**/*' 38 | 39 | # s.public_header_files = 'Pod/Classes/**/*.h' 40 | 41 | s.ios.frameworks = 'UIKit', 'AVFoundation' 42 | 43 | # s.dependency 'AFNetworking', '~> 2.3' 44 | end 45 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Operations/Misc/OPLocationOperation.h: -------------------------------------------------------------------------------- 1 | // OPLocationOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | 23 | #import "OPOperation.h" 24 | 25 | #import 26 | 27 | 28 | /** 29 | * `OPLocationOperation` is an `OPOperation` subclass to do a "one-shot" 30 | * request to get the user's current location, with a desired accuracy. 31 | * This operation will prompt for `WhenInUse` location authorization, 32 | * if the app does not already have it. 33 | * 34 | * - returns: An instance of `OPLocationOperation` 35 | */ 36 | @interface OPLocationOperation : OPOperation 37 | 38 | - (instancetype)initWithAccuracy:(CLLocationAccuracy)accuracy 39 | locationHandler:(void (^)(CLLocation *location))locationHandler NS_DESIGNATED_INITIALIZER; 40 | 41 | /** 42 | * Unused `-init` method. 43 | * @see -initWithAccuracy:locationHandler: 44 | */ 45 | - (instancetype)init NS_UNAVAILABLE; 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPNegatedCondition.h: -------------------------------------------------------------------------------- 1 | // OPNegatedCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | 25 | NS_ASSUME_NONNULL_BEGIN 26 | 27 | 28 | /** 29 | * A simple condition that negates the evaluation of another condition. 30 | * This is useful (for example) if you want to only execute an operation if the 31 | * network is NOT reachable. 32 | */ 33 | @interface OPNegatedCondition : NSObject 34 | 35 | /** 36 | * Initializes an `OPNegatedCondition` object with the provided condition. 37 | * 38 | * This is the designated initializer. 39 | * 40 | * @param condition The condition which should be negated. 41 | * 42 | * @return The newly-initialized `OPNegatedCondition` 43 | */ 44 | - (instancetype)initWithCondition:(id )condition NS_DESIGNATED_INITIALIZER; 45 | 46 | /** 47 | * Unused `-init` method. 48 | * @see - initWithCondition: 49 | */ 50 | - (instancetype)init NS_UNAVAILABLE; 51 | 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPLocationCondition.h: -------------------------------------------------------------------------------- 1 | // OPLocationCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | 25 | typedef NS_ENUM(NSUInteger, OPLocationConditionUsage) { 26 | OPLocationConditionWhenInUse, 27 | OPLocationConditionAlways, 28 | }; 29 | 30 | 31 | /** 32 | * A condition for verifying access to the user's location. 33 | * 34 | * - returns: An `NSObject` conforming to the `OPOperationCondition` protocol 35 | */ 36 | @interface OPLocationCondition : NSObject 37 | 38 | /** 39 | * Designated initializer, otherwise calling `-init` will return an 40 | * `OPLocationCondition` with a default usage of 41 | * `OPLocationConditionWhenInUse`. 42 | * 43 | * @param usage A value defining the required location usage permission in 44 | * order to satisfy the condition. 45 | * 46 | * @return An `OPLocationCondition` object with the required location usage 47 | * permission defined. 48 | */ 49 | - (instancetype)initWithUsage:(OPLocationConditionUsage)usage NS_DESIGNATED_INITIALIZER; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Observers/OPBlockObserver.h: -------------------------------------------------------------------------------- 1 | // OPBlockObserver.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationObserver.h" 23 | 24 | 25 | /** 26 | * The `OPBlockObserver` is a way to attach arbitrary blocks to significant 27 | * events in an `OPOperation`'s lifecycle. 28 | */ 29 | @interface OPBlockObserver : NSObject 30 | 31 | @property (copy, nonatomic) void (^startHandler)(OPOperation *operation); 32 | 33 | @property (copy, nonatomic) void (^produceHander)(OPOperation *operation, NSOperation *newOperation); 34 | 35 | @property (copy, nonatomic) void (^finishHandler)(OPOperation *operation, NSArray *errors); 36 | 37 | - (instancetype)initWithStartHandler:(void (^)(OPOperation *operation))startHandler 38 | produceHandler:(void (^)(OPOperation *operation, NSOperation *newOperation))produceHandler 39 | finishHandler:(void (^)(OPOperation *operation, NSArray *errors))finishHandler NS_DESIGNATED_INITIALIZER; 40 | 41 | - (instancetype)initWithFinishHandler:(void(^)(OPOperation *operation, NSArray *errors))finishHandler; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPSilentCondition.h: -------------------------------------------------------------------------------- 1 | // OPSilentCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | 25 | NS_ASSUME_NONNULL_BEGIN 26 | 27 | /** 28 | * A simple condition that causes another condition to not enqueue its 29 | * dependency. This is useful (for example) when you want to verify that you 30 | * have access to the user's location, but you do not want to prompt them for 31 | * permission if you do not already have it. 32 | */ 33 | @interface OPSilentCondition : NSObject 34 | 35 | /** 36 | * Initializes an `OPSilentCondition` object with the provided condition. 37 | * 38 | * This is the designated initializer. 39 | * 40 | * @param condition The condition which should be silent. 41 | * 42 | * @return The newly-initialized `OPSilentCondition` 43 | */ 44 | - (instancetype)initWithCondition:(id )condition NS_DESIGNATED_INITIALIZER; 45 | 46 | /** 47 | * Unused `-init` method. 48 | * @see -initWithCondition: 49 | */ 50 | - (instancetype)init NS_UNAVAILABLE; 51 | 52 | @end 53 | 54 | NS_ASSUME_NONNULL_END 55 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Misc/OPDelayOperation.h: -------------------------------------------------------------------------------- 1 | // OPDelayOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperation.h" 23 | 24 | /** 25 | * `OPDelayOperation` is an `OPOperation` that will simply wait for a given time 26 | * interval, or until a specific `NSDate`. 27 | * 28 | * It is important to note that this operation does **not** use the `sleep()` 29 | * function, since that is inefficient and blocks the thread on which it is called. 30 | * Instead, this operation uses `dispatch_after` to know when the appropriate amount 31 | * of time has passed. 32 | * 33 | * If the interval is negative, or the `NSDate` is in the past, then this operation 34 | * immediately finishes. 35 | * 36 | * - returns: An instance of an `OPDelayOperation` 37 | */ 38 | @interface OPDelayOperation : OPOperation 39 | 40 | - (instancetype)initWithTimeInterval:(NSTimeInterval)interval NS_DESIGNATED_INITIALIZER; 41 | 42 | - (instancetype)initWithDate:(NSDate *)date; 43 | 44 | /** 45 | * Unused `-init` method. 46 | * @see -initWithTimeInterval: 47 | * @see -initWithDate: 48 | */ 49 | - (instancetype)init NS_UNAVAILABLE; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPOperationConditionUserNotification.h: -------------------------------------------------------------------------------- 1 | // OPOperationConditionUserNotification.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #if TARGET_OS_IPHONE 23 | 24 | #import 25 | #import "OPOperationCondition.h" 26 | 27 | typedef NS_ENUM(NSUInteger, OPOperationConditionUserNotificationBehavior) { 28 | OPOperationConditionBehaviorMerge, 29 | OPOperationConditionBehaviorReplace, 30 | }; 31 | 32 | extern NSString * const kCurrentSettings; 33 | extern NSString * const kDesiredSettings; 34 | 35 | @interface OPOperationConditionUserNotification : NSObject 36 | 37 | - (instancetype)initWithSettings:(UIUserNotificationSettings *)settings 38 | application:(UIApplication *)application 39 | behavior:(OPOperationConditionUserNotificationBehavior)behavior NS_DESIGNATED_INITIALIZER; 40 | 41 | - (instancetype)initWithSettings:(UIUserNotificationSettings *)settings application:(UIApplication *)application; 42 | 43 | /** 44 | * Unused `-init` method. 45 | * @see -initWithSettings:application:behavior 46 | */ 47 | - (instancetype)init NS_UNAVAILABLE; 48 | 49 | @end 50 | 51 | #endif -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPRemoteNotificationCondition.h: -------------------------------------------------------------------------------- 1 | // OPRemoteNotificationCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | 25 | /** 26 | * A condition for verifying that the app has the ability to receive push notifications. 27 | */ 28 | @interface OPRemoteNotificationCondition : NSObject 29 | 30 | /** 31 | * Class method called upon by `UIApplication` when a remote notification 32 | * push token has been received. 33 | * Either this method or -didFailToRegister: should be called during 34 | * the remote notification registration process. 35 | * 36 | * @param token `NSData` object received upon successful remote notification registration 37 | */ 38 | + (void)didReceiveNotificationToken:(NSData *)token; 39 | 40 | /** 41 | * Class method called upon by `UIApplication` when a remote notification 42 | * registration process failed with an error. 43 | * Either this method or -didReceiveNotificationToken: should be called during 44 | * the remote notification registration process. 45 | * 46 | * @param error `NSError` object describing the failed registration 47 | */ 48 | + (void)didFailToRegister:(NSError *)error; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Misc/OPBlockOperation.m: -------------------------------------------------------------------------------- 1 | // OPBlockOperation.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPBlockOperation.h" 23 | 24 | 25 | @interface OPBlockOperation () 26 | 27 | @property (copy, nonatomic) OPOperationBlock block; 28 | 29 | @end 30 | 31 | @implementation OPBlockOperation 32 | 33 | 34 | #pragma mark - Overrides 35 | #pragma mark - 36 | 37 | - (void)execute 38 | { 39 | if ([self block]) { 40 | self.block(^{ 41 | [self finish]; 42 | }); 43 | } else { 44 | [self finish]; 45 | } 46 | } 47 | 48 | 49 | #pragma mark - Lifecycle 50 | #pragma mark - 51 | 52 | - (instancetype)initWithBlock:(OPOperationBlock)block 53 | { 54 | self = [super init]; 55 | if (!self) { 56 | return nil; 57 | } 58 | 59 | _block = [block copy]; 60 | 61 | return self; 62 | } 63 | 64 | - (instancetype)initWithMainQueueBlock:(void (^)(void))mainQueueBlock 65 | { 66 | OPOperationBlock block = ^(void(^continuation)()) { 67 | dispatch_async(dispatch_get_main_queue(), ^{ 68 | mainQueueBlock(); 69 | continuation(); 70 | }); 71 | }; 72 | 73 | return [self initWithBlock:block]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /Pod/Classes/Operative.h: -------------------------------------------------------------------------------- 1 | // Operative.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #ifndef Pods_Operative_h 23 | #define Pods_Operative_h 24 | 25 | // Core 26 | #import "OPOperation.h" 27 | #import "OPOperationQueue.h" 28 | #import "OPOperationObserver.h" 29 | 30 | // Operations 31 | #import "OPBlockOperation.h" 32 | #import "OPURLSessionTaskOperation.h" 33 | #import "OPGroupOperation.h" 34 | #import "OPDelayOperation.h" 35 | 36 | #if TARGET_OS_IPHONE 37 | #import "OPMediaPermissionOperation.h" 38 | #import "OPLocationOperation.h" 39 | #import "OPAlertOperation.h" 40 | #endif 41 | 42 | // Conditions 43 | #import "OPOperationConditionMutuallyExclusive.h" 44 | #import "OPReachabilityCondition.h" 45 | 46 | #if TARGET_OS_IPHONE 47 | #import "OPLocationCondition.h" 48 | #import "OPOperationConditionUserNotification.h" 49 | #import "OPPhotosCondition.h" 50 | #import "OPRemoteNotificationCondition.h" 51 | #import "OPVideoCondition.h" 52 | #import "OPAudioCondition.h" 53 | #endif 54 | 55 | #import "OPSilentCondition.h" 56 | #import "OPNoCancelledDependenciesCondition.h" 57 | 58 | // Observers 59 | #import "OPBlockObserver.h" 60 | #import "OPTimeoutObserver.h" 61 | 62 | #if TARGET_OS_IPHONE 63 | #import "OPBackgroundObserver.h" 64 | #import "OPNetworkObserver.h" 65 | #endif 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operation Queue/OPExclusivityController.h: -------------------------------------------------------------------------------- 1 | // OPExclusivityController.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | #import "OPOperation.h" 24 | 25 | 26 | /** 27 | * `OPExclusivityController` is a singleton to keep track of all the in-flight 28 | * `OPOperation` instances that have declared themselves as requiring mutual exclusivity. 29 | * We use a singleton because mutual exclusivity must be enforced across the entire 30 | * app, regardless of the `OPOperationQueue` on which an `OPOperation` was executed. 31 | */ 32 | @interface OPExclusivityController : NSObject 33 | 34 | + (OPExclusivityController *)sharedExclusivityController; 35 | 36 | /** 37 | * Registers an operation as being mutually exclusive 38 | * 39 | * @param operation OPOperation object which requires exclusivity 40 | * @param categories Array of strings describing the name of the category of exclusivity 41 | */ 42 | - (void)addOperation:(OPOperation *)operation categories:(NSArray *)categories; 43 | 44 | /** 45 | * Unregisters an operation from being mutually exclusive. 46 | * 47 | * @param operation OPOperation object which requires exclusivity 48 | * @param categories Array of strings describing the name of the category of exclusivity 49 | */ 50 | - (void)removeOperation:(OPOperation *)operation categories:(NSArray *)categories; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Operations/Misc/OPMediaPermissionOperation.m: -------------------------------------------------------------------------------- 1 | // OPMediaPermissionOperation.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | @import AVFoundation; 23 | 24 | #import "OPMediaPermissionOperation.h" 25 | #import "OPOperationConditionMutuallyExclusive.h" 26 | 27 | @interface OPMediaPermissionOperation() 28 | 29 | @property (copy, nonatomic) NSString *mediaType; 30 | 31 | @end 32 | 33 | @implementation OPMediaPermissionOperation 34 | 35 | #pragma mark - Lifecycle 36 | #pragma mark - 37 | 38 | - (instancetype)initWithMediaType:(NSString *)mediaType 39 | { 40 | self = [super init]; 41 | if (!self) { 42 | return nil; 43 | } 44 | 45 | _mediaType = [mediaType copy]; 46 | 47 | [self addCondition:[OPOperationConditionMutuallyExclusive alertPresentationExclusivity]]; 48 | 49 | return self; 50 | } 51 | 52 | #pragma mark - Overrides 53 | #pragma mark - 54 | 55 | - (void)execute 56 | { 57 | AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:[self mediaType]]; 58 | if (status == AVAuthorizationStatusNotDetermined) { 59 | dispatch_async(dispatch_get_main_queue(), ^{ 60 | [AVCaptureDevice requestAccessForMediaType:[self mediaType] completionHandler:^(BOOL granted) { 61 | [self finish]; 62 | }]; 63 | }); 64 | } else { 65 | [self finish]; 66 | } 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPSilentCondition.m: -------------------------------------------------------------------------------- 1 | // OPSilentCondition.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | 23 | #import "OPSilentCondition.h" 24 | 25 | 26 | @interface OPSilentCondition () 27 | 28 | /** 29 | * Underlying condition which is evaluated. 30 | */ 31 | @property (strong, nonatomic, readonly) id condition; 32 | 33 | @end 34 | 35 | 36 | @implementation OPSilentCondition 37 | 38 | 39 | #pragma mark - Lifecycle 40 | #pragma mark - 41 | 42 | - (instancetype)initWithCondition:(id )condition 43 | { 44 | self = [super init]; 45 | 46 | _condition = condition; 47 | 48 | return self; 49 | } 50 | 51 | 52 | #pragma mark - OPOperationCondition Protocol 53 | #pragma mark - 54 | 55 | - (NSString *)name 56 | { 57 | return [NSString stringWithFormat:@"Silent<%@>", [self.condition name]]; 58 | } 59 | 60 | - (BOOL)isMutuallyExclusive 61 | { 62 | return [self.condition isMutuallyExclusive]; 63 | } 64 | 65 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 66 | { 67 | return nil; 68 | } 69 | 70 | - (void)evaluateConditionForOperation:(OPOperation *)operation 71 | completion:(void (^)(OPOperationConditionResultStatus result, NSError *error))completion 72 | { 73 | [self.condition evaluateConditionForOperation:operation 74 | completion:completion]; 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Misc/OPDelayOperation.m: -------------------------------------------------------------------------------- 1 | // OPDelayOperation.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPDelayOperation.h" 23 | 24 | 25 | @interface OPDelayOperation () 26 | 27 | @property (assign, nonatomic) NSTimeInterval delay; 28 | 29 | @end 30 | 31 | 32 | @implementation OPDelayOperation 33 | 34 | 35 | #pragma mark - Overrides 36 | #pragma mark - 37 | 38 | - (void)execute 39 | { 40 | if ([self delay] < 0) { 41 | [self finish]; 42 | return; 43 | } 44 | 45 | dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)([self delay] * NSEC_PER_SEC)); 46 | 47 | dispatch_after(when, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ 48 | // If we were cancelled, then -finish has already been called. 49 | if (![self isCancelled]) { 50 | [self finish]; 51 | } 52 | }); 53 | } 54 | 55 | - (void)cancel 56 | { 57 | [super cancel]; 58 | // Cancelling the operation means we don't want to wait anymore. 59 | [self finish]; 60 | } 61 | 62 | 63 | #pragma mark - Lifecycle 64 | #pragma mark - 65 | 66 | - (instancetype)initWithTimeInterval:(NSTimeInterval)interval 67 | { 68 | self = [super init]; 69 | if (!self) { 70 | return nil; 71 | } 72 | 73 | _delay = interval; 74 | 75 | return self; 76 | } 77 | 78 | - (instancetype)initWithDate:(NSDate *)date 79 | { 80 | return [self initWithTimeInterval:[date timeIntervalSinceNow]]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPAudioCondition.m: -------------------------------------------------------------------------------- 1 | // OPAudioCondition.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | @import AVFoundation; 23 | 24 | #import "OPAudioCondition.h" 25 | #import "OPMediaPermissionOperation.h" 26 | 27 | #import "NSError+Operative.h" 28 | 29 | @implementation OPAudioCondition 30 | 31 | #pragma mark - OPOperationCondition Protocol 32 | #pragma mark - 33 | 34 | - (NSString *)name 35 | { 36 | return @"Audio"; 37 | } 38 | 39 | - (BOOL)isMutuallyExclusive 40 | { 41 | return NO; 42 | } 43 | 44 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 45 | { 46 | return [[OPMediaPermissionOperation alloc] initWithMediaType:AVMediaTypeAudio]; 47 | } 48 | 49 | - (void)evaluateConditionForOperation:(OPOperation *)operation completion:(void (^)(OPOperationConditionResultStatus, NSError *))completion 50 | { 51 | NSArray *availableDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; 52 | AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]; 53 | 54 | if (status == AVAuthorizationStatusAuthorized || [availableDevices count] == 0) { 55 | completion(OPOperationConditionResultStatusSatisfied, nil); 56 | } else { 57 | NSDictionary *userInfo = @{ kOPOperationConditionKey : [self name] }; 58 | NSError *error = [NSError errorWithCode:OPOperationErrorCodeConditionFailed userInfo:userInfo]; 59 | completion(OPOperationConditionResultStatusFailed, error); 60 | } 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPVideoCondition.m: -------------------------------------------------------------------------------- 1 | // OPVideoCondition.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | @import AVFoundation; 23 | 24 | #import "OPVideoCondition.h" 25 | #import "OPMediaPermissionOperation.h" 26 | 27 | #import "NSError+Operative.h" 28 | 29 | @implementation OPVideoCondition 30 | 31 | #pragma mark - OPOperationCondition Protocol 32 | #pragma mark - 33 | 34 | - (NSString *)name 35 | { 36 | return @"Video"; 37 | } 38 | 39 | - (BOOL)isMutuallyExclusive 40 | { 41 | return NO; 42 | } 43 | 44 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 45 | { 46 | return [[OPMediaPermissionOperation alloc] initWithMediaType:AVMediaTypeVideo]; 47 | } 48 | 49 | - (void)evaluateConditionForOperation:(OPOperation *)operation completion:(void (^)(OPOperationConditionResultStatus, NSError *))completion 50 | { 51 | NSArray *availableDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; 52 | AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; 53 | 54 | if (status == AVAuthorizationStatusAuthorized || [availableDevices count] == 0) { 55 | completion(OPOperationConditionResultStatusSatisfied, nil); 56 | } else { 57 | NSDictionary *userInfo = @{ kOPOperationConditionKey : [self name] }; 58 | NSError *error = [NSError errorWithCode:OPOperationErrorCodeConditionFailed userInfo:userInfo]; 59 | completion(OPOperationConditionResultStatusFailed, error); 60 | } 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Operations/UI/OPAlertOperation.h: -------------------------------------------------------------------------------- 1 | // OPAlertOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #if TARGET_OS_IPHONE 23 | 24 | #import "OPOperation.h" 25 | 26 | #import 27 | 28 | 29 | @interface OPAlertOperation : OPOperation 30 | 31 | /** 32 | * Initializes an instance of OPAlertOperation with the contained 33 | * UIAlertController's UIAlertControllerStyle defaulted to 34 | * UIAlertControllerStyleActionSheet 35 | * 36 | * @see -initWithPresentationContext:preferredStyle 37 | * 38 | * @param presentationContext UIViewController from which the UIAlertController 39 | * will be present. If nil then this will default to 40 | * the rootViewController of the sharedApplication. 41 | * 42 | * @return An initialized OPAlertOperation 43 | */ 44 | - (instancetype)initWithPresentationContext:(UIViewController *)presentationContext; 45 | 46 | - (instancetype)initWithPresentationContext:(UIViewController *)presentationContext 47 | preferredStyle:(UIAlertControllerStyle)preferredStyle NS_DESIGNATED_INITIALIZER; 48 | 49 | /** 50 | * Unused `-init` method. 51 | * @see -initWithPresentationContext: 52 | */ 53 | - (instancetype)init NS_UNAVAILABLE; 54 | 55 | @property (copy, nonatomic) NSString *title; 56 | 57 | @property (copy, nonatomic) NSString *message; 58 | 59 | - (void)addAction:(NSString *)title 60 | style:(UIAlertActionStyle)style 61 | handler:(void (^)(OPAlertOperation *alertOperation))handler; 62 | 63 | @end 64 | 65 | #endif -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPOperationConditionMutuallyExclusive.h: -------------------------------------------------------------------------------- 1 | // OPOperationConditionMutuallyExclusive.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationCondition.h" 23 | 24 | 25 | @interface OPOperationConditionMutuallyExclusive : NSObject 26 | 27 | + (OPOperationConditionMutuallyExclusive *)mutuallyExclusiveWith:(Class)cls; 28 | 29 | /** 30 | * Class method that returns a mutually exclusive condition for a target 31 | * operation that may present an alert. 32 | * 33 | * @return `OPOperationConditionMutuallyExclusive` object with class of type 34 | * `OPAlertPresentation` 35 | * 36 | * @see OPAlertPresentation 37 | */ 38 | + (OPOperationConditionMutuallyExclusive *)alertPresentationExclusivity; 39 | 40 | - (instancetype)initWithClass:(Class)cls NS_DESIGNATED_INITIALIZER; 41 | 42 | /** 43 | * Unused `-init` method. 44 | * @see -initWithClass: 45 | */ 46 | - (instancetype)init NS_UNAVAILABLE; 47 | 48 | @end 49 | 50 | /** 51 | * Provides a simple class for usage in defining exclusivity for a target that 52 | * may display an alert (via system, `UIAlertController`, `UIAlertView`, etc.) 53 | * 54 | * When defining an operation with an alert view mutually exclusivity 55 | * condition, always use this class as opposed to `[UIAlertController class]` 56 | * or `[UIAlertView class]`. 57 | * 58 | * For simplicity, `OPOperationConditionMutuallyExclusive` has a class method 59 | * `+alertPresentationExclusivity` which returns a mutually exclusive condition 60 | * setup with `[OPAlertPresentation class]` 61 | * 62 | * @see alertPresentationExclusivity 63 | */ 64 | @interface OPAlertPresentation : NSObject 65 | @end 66 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPNoCancelledDependenciesCondition.m: -------------------------------------------------------------------------------- 1 | // OPNoCancelledDependenciesCondition.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPNoCancelledDependenciesCondition.h" 23 | #import "NSError+Operative.h" 24 | 25 | NSString * const kOPCancelledDependenciesKey = @"CancelledDependencies"; 26 | 27 | @implementation OPNoCancelledDependenciesCondition 28 | 29 | - (BOOL)isMutuallyExclusive { 30 | return NO; 31 | } 32 | 33 | - (NSString *)name { 34 | return @"NoCancelledDependencies"; 35 | } 36 | 37 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation { 38 | return nil; 39 | } 40 | 41 | - (void)evaluateConditionForOperation:(OPOperation *)operation 42 | completion:(void (^)(OPOperationConditionResultStatus result, NSError *error))completion 43 | { 44 | // Verify that all of the dependencies executed. 45 | NSArray *cancelled = [operation.dependencies filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"cancelled = YES"]]; 46 | 47 | // Satisfied until not 48 | OPOperationConditionResultStatus resultStatus = OPOperationConditionResultStatusSatisfied; 49 | 50 | NSError *error; 51 | 52 | if(cancelled.count != 0) { 53 | // At least one dependency was cancelled; the condition was not satisfied. 54 | NSDictionary *userInfo = @{ 55 | kOPOperationConditionKey: NSStringFromClass([self class]), 56 | kOPCancelledDependenciesKey: cancelled 57 | }; 58 | 59 | error = [NSError errorWithCode:OPOperationErrorCodeConditionFailed userInfo:userInfo]; 60 | resultStatus = OPOperationConditionResultStatusFailed; 61 | } 62 | 63 | completion(resultStatus, error); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operation Queue/OPOperationQueue.h: -------------------------------------------------------------------------------- 1 | // OPOperationQueue.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | 25 | @class OPOperationQueue; 26 | 27 | 28 | /** 29 | * The delegate of an `OPOperationQueue` can respond to `OPOperation` lifecycle 30 | * events by implementing these methods. 31 | * 32 | * In general, implementing `OPOperationQueueDelegate` is not necessary; 33 | * you would want to use an `OPOperationObserver` instead. 34 | * However, there are a couple of situations where using 35 | * `OPOperationQueueDelegate` can lead to simpler code. 36 | * For example, `OPGroupOperation` is the delegate of its own internal 37 | * `OPOperationQueue` and uses it to manage dependencies. 38 | */ 39 | @protocol OPOperationQueueDelegate 40 | 41 | @optional 42 | 43 | - (void)operationQueue:(OPOperationQueue *)operationQueue willAddOperation:(NSOperation *)operation; 44 | 45 | - (void)operationQueue:(OPOperationQueue *)operationQueue operationDidFinish:(NSOperation *)operation withErrors:(NSArray *)errors; 46 | 47 | @end 48 | 49 | 50 | /** 51 | * `OPOperationQueue` is an `NSOperationQueue` subclass that implements a large 52 | * number of "extra features" related to the `OPOperation` class: 53 | * 54 | * - Notifying a delegate of all operation completion 55 | * - Extracting generated dependencies from operation conditions 56 | * - Setting up dependencies to enforce mutual exclusivity 57 | */ 58 | @interface OPOperationQueue : NSOperationQueue 59 | 60 | @property (weak, nonatomic) id delegate; 61 | 62 | - (void)addOperation:(NSOperation *)operation; 63 | 64 | - (void)addOperations:(NSArray *)operations waitUntilFinished:(BOOL)wait; 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Networking/OPURLSessionTaskOperation.h: -------------------------------------------------------------------------------- 1 | // OPURLSessionOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperation.h" 23 | 24 | 25 | /** 26 | * `OPURLSessionTaskOperation` is an `OPOperation` that lifts an `NSURLSessionTask` 27 | * into an operation. 28 | * 29 | * Note that this operation does not participate in any of the delegate callbacks 30 | * of an `NSURLSession`, but instead uses Key-Value-Observing to know when the 31 | * task has been completed. By default the operation gets notified of errors that occur during 32 | * execution of the task. Upon completion, if the task has produced an error, 33 | * `-finishWithError:` will receive this error and the operation will accrue the error 34 | * from the task as an internal error. 35 | * 36 | * As an option, one can set the value of `shouldSuppressErrors` to YES 37 | * and the operation will not get notified about any errors that occurred during 38 | * execution of the task. 39 | * 40 | * @see shouldSuppressErrors 41 | * 42 | * - returns: An instance of an `OPURLSessionTaskOperation` 43 | */ 44 | @interface OPURLSessionTaskOperation : OPOperation 45 | 46 | - (instancetype)initWithTask:(NSURLSessionTask *)task NS_DESIGNATED_INITIALIZER; 47 | 48 | /** 49 | * Evaluated upon completion of the provided `NSURLSessionTask`, this value 50 | * dictates how errors occurring during the execution of the task are handled. 51 | * 52 | * If set to YES, completion of the task will not pass along any errors that 53 | * may have occurred during execution to the operation via -finishedWithError:. 54 | * 55 | * Defaults to NO 56 | */ 57 | @property (assign, nonatomic) BOOL shouldSuppressErrors; 58 | 59 | /** 60 | * Unused `-init` method. 61 | * @see -initWithTask: 62 | */ 63 | - (instancetype)init NS_UNAVAILABLE; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Misc/OPBlockOperation.h: -------------------------------------------------------------------------------- 1 | // OPBlockOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperation.h" 23 | 24 | 25 | /** 26 | * An operation block that takes a block as it's parameter 27 | * 28 | * @param ^completion: Block to be executed upon completion of an 29 | * `OPBlockOperation` 30 | */ 31 | typedef void (^OPOperationBlock)(void (^completion)(void)); 32 | 33 | 34 | /** 35 | * A subclass of `OPOperation` to execute a block. 36 | * - returns: An instance of an `OPBlockOperation` 37 | */ 38 | @interface OPBlockOperation : OPOperation 39 | 40 | /** 41 | * Designated Initialized for `OPBlockOperation` 42 | * 43 | * @param block: The block to run when the operation executes. This 44 | * block will be run on an arbitrary queue. The parameter passed to the 45 | * block **MUST** be invoked by your code, or else the `OPBlockOperation` 46 | * will never finish executing. If this parameter is `nil`, the operation 47 | * will immediately finish. 48 | * 49 | * @return An instance of an `OPBlockOperation` 50 | */ 51 | - (instancetype)initWithBlock:(OPOperationBlock)block NS_DESIGNATED_INITIALIZER; 52 | 53 | /** 54 | * A convenience initializer to execute a block on the main queue. 55 | * 56 | * @param mainQueueBlock: The block to execute on the main queue. Note 57 | * that this block does not have a "continuation" block to execute (unlike 58 | * the designated initializer). The operation will be automatically ended 59 | * after the `mainQueueBlock` is executed. 60 | * 61 | * @return An instance of an `OPBlockOperation` that will run on the main queue 62 | */ 63 | - (instancetype)initWithMainQueueBlock:(void (^)(void))mainQueueBlock; 64 | 65 | /** 66 | * Unused `-init` method. 67 | * @see -initWithBlock: 68 | * @see -initWithMainQueueBlock: 69 | */ 70 | - (instancetype)init NS_UNAVAILABLE; 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPOperationConditionMutuallyExclusive.m: -------------------------------------------------------------------------------- 1 | // OPOperationConditionMutuallyExclusive.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationConditionMutuallyExclusive.h" 23 | 24 | 25 | @interface OPOperationConditionMutuallyExclusive () 26 | 27 | @property (copy, nonatomic) Class cls; 28 | 29 | @end 30 | 31 | @implementation OPOperationConditionMutuallyExclusive 32 | 33 | - (NSString *)debugDescription { 34 | return [NSString stringWithFormat:@"%@ %@", [super debugDescription], [self name]]; 35 | } 36 | 37 | #pragma mark - OPOperationCondition Protocol 38 | #pragma mark - 39 | 40 | - (NSString *)name 41 | { 42 | return [NSString stringWithFormat:@"MutuallyExclusive<%@>", NSStringFromClass(self.cls)]; 43 | } 44 | 45 | - (BOOL)isMutuallyExclusive 46 | { 47 | return YES; 48 | } 49 | 50 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 51 | { 52 | return nil; 53 | } 54 | 55 | - (void)evaluateConditionForOperation:(OPOperation *)operation 56 | completion:(void (^)(OPOperationConditionResultStatus result, NSError *error))completion 57 | { 58 | completion(OPOperationConditionResultStatusSatisfied, nil); 59 | } 60 | 61 | 62 | #pragma mark - Lifecycle 63 | #pragma mark - 64 | 65 | + (OPOperationConditionMutuallyExclusive *)alertPresentationExclusivity 66 | { 67 | return [OPOperationConditionMutuallyExclusive mutuallyExclusiveWith:[OPAlertPresentation class]]; 68 | } 69 | 70 | + (OPOperationConditionMutuallyExclusive *)mutuallyExclusiveWith:(Class)cls 71 | { 72 | return [[OPOperationConditionMutuallyExclusive alloc] initWithClass:cls]; 73 | } 74 | 75 | - (instancetype)initWithClass:(Class)cls 76 | { 77 | self = [super init]; 78 | if (!self) { 79 | return nil; 80 | } 81 | 82 | _cls = [cls copy]; 83 | 84 | return self; 85 | } 86 | 87 | @end 88 | 89 | 90 | #pragma mark - OPAlertPresentation 91 | 92 | @implementation OPAlertPresentation 93 | @end 94 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Observers/OPBlockObserver.m: -------------------------------------------------------------------------------- 1 | // OPBlockObserver.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPBlockObserver.h" 23 | 24 | 25 | @interface OPBlockObserver () 26 | 27 | - (instancetype)init NS_DESIGNATED_INITIALIZER; 28 | 29 | @end 30 | 31 | 32 | @implementation OPBlockObserver 33 | 34 | 35 | #pragma mark - OPOperationObserver Protocol 36 | #pragma mark - 37 | 38 | - (void)operationDidStart:(OPOperation *)operation 39 | { 40 | if ([self startHandler]) { 41 | self.startHandler(operation); 42 | } 43 | } 44 | 45 | - (void)operation:(OPOperation *)operation didProduceOperation:(NSOperation *)newOperation 46 | { 47 | if ([self produceHander]) { 48 | self.produceHander(operation, newOperation); 49 | } 50 | } 51 | 52 | - (void)operation:(OPOperation *)operation didFinishWithErrors:(NSArray *)errors 53 | { 54 | if ([self finishHandler]) { 55 | self.finishHandler(operation, errors); 56 | } 57 | } 58 | 59 | 60 | #pragma mark - Lifecycle 61 | #pragma mark - 62 | 63 | - (instancetype)initWithStartHandler:(void (^)(OPOperation *operation))startHandler 64 | produceHandler:(void (^)(OPOperation *operation, NSOperation *newOperation))produceHandler 65 | finishHandler:(void (^)(OPOperation *operation, NSArray *errors))finishHandler; 66 | { 67 | self = [super init]; 68 | if (!self) { 69 | return nil; 70 | } 71 | 72 | _startHandler = [startHandler copy]; 73 | _produceHander = [produceHandler copy]; 74 | _finishHandler = [finishHandler copy]; 75 | 76 | return self; 77 | } 78 | 79 | - (instancetype)initWithFinishHandler:(void (^)(OPOperation *operation, NSArray *errors))finishHandler 80 | { 81 | return [self initWithStartHandler:nil produceHandler:nil finishHandler:finishHandler]; 82 | } 83 | 84 | - (instancetype)init 85 | { 86 | self = [super init]; 87 | if (!self) { 88 | return nil; 89 | } 90 | 91 | return self; 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /Example/Operative/OPAppDelegate.m: -------------------------------------------------------------------------------- 1 | // OPAppDelegate.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPAppDelegate.h" 23 | 24 | @implementation OPAppDelegate 25 | 26 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 27 | { 28 | // Override point for customization after application launch. 29 | return YES; 30 | } 31 | 32 | - (void)applicationWillResignActive:(UIApplication *)application 33 | { 34 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 35 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 36 | } 37 | 38 | - (void)applicationDidEnterBackground:(UIApplication *)application 39 | { 40 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 41 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 42 | } 43 | 44 | - (void)applicationWillEnterForeground:(UIApplication *)application 45 | { 46 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 47 | } 48 | 49 | - (void)applicationDidBecomeActive:(UIApplication *)application 50 | { 51 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 52 | } 53 | 54 | - (void)applicationWillTerminate:(UIApplication *)application 55 | { 56 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPOperationConditionEvaluator.m: -------------------------------------------------------------------------------- 1 | // OPOperationConditionEvaluator.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperationConditionEvaluator.h" 23 | #import "OPOperationCondition.h" 24 | #import "NSError+Operative.h" 25 | 26 | 27 | @implementation OPOperationConditionEvaluator 28 | 29 | + (void)evaluateConditions:(NSArray *)conditions 30 | operation:(OPOperation *)operation 31 | completion:(void (^)(NSArray *failures))completion; 32 | { 33 | // Check conditions. 34 | dispatch_group_t conditionGroup = dispatch_group_create(); 35 | 36 | NSMutableArray *results = [[NSMutableArray alloc] init]; 37 | [conditions enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 38 | [results addObject:[NSNull null]]; 39 | }]; 40 | 41 | // Ask each condition to evaluate and store its result in the "results" array. 42 | [conditions enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 43 | id condition = obj; 44 | 45 | dispatch_group_enter(conditionGroup); 46 | [condition evaluateConditionForOperation:operation completion:^(OPOperationConditionResultStatus result, NSError *error) { 47 | if (error) { 48 | results[idx] = error; 49 | } 50 | dispatch_group_leave(conditionGroup); 51 | }]; 52 | }]; 53 | 54 | // After all the conditions have evaluated, this block will execute 55 | dispatch_group_notify(conditionGroup, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ 56 | // Aggregate the errors that occurred, in order. 57 | NSMutableArray *failures = [[NSMutableArray alloc] init]; 58 | [results enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 59 | if ([obj isKindOfClass:[NSError class]]) { 60 | [failures addObject:obj]; 61 | } 62 | }]; 63 | 64 | // If any of the conditions caused this operation to be cancelled, check for that 65 | if ([operation isCancelled]) { 66 | [failures addObject:[NSError errorWithCode:OPOperationErrorCodeConditionFailed]]; 67 | } 68 | 69 | completion(failures); 70 | }); 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Categories/UIUserNotificationSettings+Operative.m: -------------------------------------------------------------------------------- 1 | // UIUserNotificationSettings+Operative.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #if TARGET_OS_IPHONE 23 | 24 | #import "UIUserNotificationSettings+Operative.h" 25 | #import "NSMutableDictionary+Operative.h" 26 | 27 | @implementation UIUserNotificationSettings (Operative) 28 | 29 | - (BOOL)containsSettings:(UIUserNotificationSettings *)settings; 30 | { 31 | if (((self.types & UIUserNotificationTypeBadge) == 0) && 32 | ((settings.types & UIUserNotificationTypeBadge) != 0)) { 33 | return NO; 34 | } else if (((self.types & UIUserNotificationTypeSound) == 0) && 35 | ((settings.types & UIUserNotificationTypeSound) != 0)) { 36 | return NO; 37 | } else if (((self.types & UIUserNotificationTypeAlert) == 0) && 38 | ((settings.types & UIUserNotificationTypeAlert) != 0)) { 39 | return NO; 40 | } 41 | 42 | NSSet *otherCategories = settings.categories ? settings.categories : [NSSet set]; 43 | NSSet *myCategories = self.categories ? self.categories : [NSSet set]; 44 | 45 | return [otherCategories isSubsetOfSet:myCategories]; 46 | } 47 | 48 | - (UIUserNotificationSettings *)settingsByMerging:(UIUserNotificationSettings *)settings; 49 | { 50 | UIUserNotificationType mergedTypes = settings.types & self.types; 51 | 52 | NSSet *myCategories = self.categories ? self.categories : [NSSet set]; 53 | 54 | NSMutableDictionary *existingCategoriesByIdentifier = [NSMutableDictionary sequence:myCategories keyMapper:^id(id obj) { 55 | UIUserNotificationCategory *type = obj; 56 | return type.identifier; 57 | }]; 58 | 59 | NSSet *newCategories = settings.categories ? settings.categories : [NSSet set]; 60 | NSMutableDictionary *newCategoriesByIdentifier = [NSMutableDictionary sequence:newCategories keyMapper:^id(id obj) { 61 | UIUserNotificationCategory *type = obj; 62 | return type.identifier; 63 | }]; 64 | 65 | [newCategoriesByIdentifier enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 66 | existingCategoriesByIdentifier[key] = obj; 67 | }]; 68 | 69 | NSSet *mergedCategories = [NSSet setWithArray:existingCategoriesByIdentifier.allValues]; 70 | return [UIUserNotificationSettings settingsForTypes:mergedTypes categories:mergedCategories]; 71 | } 72 | 73 | @end 74 | 75 | #endif -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPOperationCondition.h: -------------------------------------------------------------------------------- 1 | // OPOperationCondition.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperation.h" 23 | 24 | /** 25 | * An enum to indicate whether an `OPOperationCondition` was satisfied, 26 | * or if it failed with an error. 27 | */ 28 | typedef NS_ENUM(NSUInteger, OPOperationConditionResultStatus){ 29 | // Operation condition was satisfied 30 | OPOperationConditionResultStatusSatisfied, 31 | // Operation condition failed 32 | OPOperationConditionResultStatusFailed, 33 | }; 34 | 35 | 36 | /** 37 | * A protocol for defining conditions that must be satisfied in order for an 38 | * operation to begin execution. 39 | */ 40 | @protocol OPOperationCondition 41 | 42 | /** 43 | * The name of the condition. This is used in userInfo dictionaries of 44 | * `OPOperationConditionResultStatusFailed` errors as the value of the 45 | * `OPOperationConditionKey` key. 46 | */ 47 | @property (strong, nonatomic, readonly) NSString *name; 48 | 49 | /** 50 | * Specifies whether multiple instances of the conditionalized operation may 51 | * be executing simultaneously. 52 | */ 53 | @property (assign, nonatomic, readonly) BOOL isMutuallyExclusive; 54 | 55 | /** 56 | * Some conditions may have the ability to satisfy the condition if another 57 | * operation is executed first. Use this method to return an operation that 58 | * (for example) asks for permission to perform the operation. 59 | * 60 | * @param operation: The `OPOperation` to which the Condition has been added. 61 | * 62 | * @return An `NSOperation`, if a dependency should be automatically added. 63 | * Otherwise, `nil`. 64 | * 65 | * @note Only a single operation may be returned as a dependency. If you 66 | * find that you need to return multiple operations, then you should be 67 | * expressing that as multiple conditions. Alternatively, you could return 68 | * a single `OPGroupOperation` that executes multiple operations internally. 69 | */ 70 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation; 71 | 72 | /** 73 | * Evaluate the condition, to see if it has been satisfied or not. 74 | * 75 | * TODO:// Get these params doc'd correctly 76 | * @param operation - 77 | * @param completion - 78 | */ 79 | - (void)evaluateConditionForOperation:(OPOperation *)operation 80 | completion:(void (^)(OPOperationConditionResultStatus result, NSError *error))completion; 81 | 82 | @end 83 | 84 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Misc/OPGroupOperation.h: -------------------------------------------------------------------------------- 1 | // OPGroupOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPOperation.h" 23 | 24 | 25 | /** 26 | * A subclass of `OPOperation` that executes zero or more operations as part 27 | * of its own execution. This class of operation is very useful for abstracting 28 | * several smaller operations into a larger operation. 29 | * 30 | * Additionally, `OPGroupOperation`s are useful if you establish a chain of 31 | * dependencies, but part of the chain may "loop". For example, if you have an 32 | * operation that requires the user to be authenticated, you may consider 33 | * putting the "login" operation inside a group operation. That way, 34 | * the "login" operation may produce subsequent operations 35 | * (still within the outer `OPGroupOperation`) that will all be executed before 36 | * the rest of the operations in the initial chain of operations. 37 | * 38 | * - returns: An instance of `OPGroupOperation 39 | */ 40 | @interface OPGroupOperation : OPOperation 41 | 42 | /** 43 | * Initializes an `OPGroupOperation` object and adds the provided operations to 44 | * its internal queue 45 | * 46 | * @param operations An `NSArray` of operations to be group together into a 47 | * single executable operation. 48 | * 49 | * @return An `OPGroupOperation` object 50 | */ 51 | - (instancetype)initWithOperations:(NSArray *)operations NS_DESIGNATED_INITIALIZER; 52 | 53 | /** 54 | * Adds an operation to the group after instantiation 55 | * 56 | * @param operation Operation to add to the group 57 | */ 58 | - (void)addOperation:(NSOperation *)operation; 59 | 60 | /** 61 | * Add multiple operations to the group after instantiation 62 | * 63 | * @param operations Array of operations to add to the group 64 | */ 65 | - (void)addOperations:(NSArray *)operations; 66 | 67 | /** 68 | * Note that some part of execution has produced an error. 69 | * Errors aggregated through this method will be included in the final array 70 | * of errors reported to observers and to the `-finished:` method. 71 | * 72 | * @param error `NSError` to be aggregated 73 | */ 74 | - (void)aggregateError:(NSError *)error; 75 | 76 | /** 77 | * Method called upon finish of an operation within the group 78 | * To be overriden by subclass of `OPGroupOperation`. 79 | * 80 | * @param operation Operation that did finish. 81 | * @param errors Array of `NSErrors` during execution of operation or nil. 82 | */ 83 | - (void)operationDidFinish:(NSOperation *)operation withErrors:(NSArray *)errors; 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPPhotosCondition.m: -------------------------------------------------------------------------------- 1 | // OPPhotosCondition.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | @import Photos; 23 | 24 | #import "OPPhotosCondition.h" 25 | #import "OPOperationConditionMutuallyExclusive.h" 26 | 27 | #import "NSError+Operative.h" 28 | 29 | 30 | /** 31 | * A private `OPOperation` that will request access to the user's Photos, if it 32 | * has not already been granted. 33 | */ 34 | @interface OPPhotosPermissionOperation : OPOperation 35 | 36 | @end 37 | 38 | 39 | @implementation OPPhotosCondition 40 | 41 | 42 | #pragma mark - OPOperationCondition Protocol 43 | #pragma mark - 44 | 45 | - (NSString *)name 46 | { 47 | return @"Photos"; 48 | } 49 | 50 | - (BOOL)isMutuallyExclusive 51 | { 52 | return NO; 53 | } 54 | 55 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 56 | { 57 | return [[OPPhotosPermissionOperation alloc] init]; 58 | } 59 | 60 | - (void)evaluateConditionForOperation:(OPOperation *)operation 61 | completion:(void (^)(OPOperationConditionResultStatus, NSError *))completion 62 | { 63 | PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 64 | 65 | if (status == PHAuthorizationStatusAuthorized) { 66 | completion(OPOperationConditionResultStatusSatisfied, nil); 67 | } else { 68 | NSDictionary *userInfo = @{ kOPOperationConditionKey : [self name] }; 69 | NSError *error = [NSError errorWithCode:OPOperationErrorCodeConditionFailed userInfo:userInfo]; 70 | completion(OPOperationConditionResultStatusFailed, error); 71 | } 72 | } 73 | 74 | @end 75 | 76 | 77 | @implementation OPPhotosPermissionOperation 78 | 79 | 80 | #pragma mark - Lifecycle 81 | #pragma mark - 82 | 83 | - (instancetype)init 84 | { 85 | self = [super init]; 86 | if (!self) { 87 | return nil; 88 | } 89 | 90 | [self addCondition:[OPOperationConditionMutuallyExclusive alertPresentationExclusivity]]; 91 | 92 | return self; 93 | } 94 | 95 | 96 | #pragma mark - Overrides 97 | #pragma mark - 98 | 99 | - (void)execute 100 | { 101 | PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; 102 | if (status == PHAuthorizationStatusNotDetermined) { 103 | dispatch_async(dispatch_get_main_queue(), ^{ 104 | [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { 105 | [self finish]; 106 | }]; 107 | }); 108 | } else { 109 | [self finish]; 110 | } 111 | } 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Networking/OPURLSessionTaskOperation.m: -------------------------------------------------------------------------------- 1 | // OPURLSessionOperation.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of oftware. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPURLSessionTaskOperation.h" 23 | 24 | 25 | static void * OPURLSessionOperationKVOContext = &OPURLSessionOperationKVOContext; 26 | 27 | 28 | @interface OPURLSessionTaskOperation () 29 | 30 | @property (strong, nonatomic) NSURLSessionTask *task; 31 | 32 | @end 33 | 34 | 35 | @implementation OPURLSessionTaskOperation 36 | 37 | 38 | #pragma mark - Overrides 39 | #pragma mark - 40 | 41 | - (void)execute 42 | { 43 | NSAssert([self.task state] == NSURLSessionTaskStateSuspended, @"Task was resumed by something other than %@", self); 44 | 45 | [self.task addObserver:self 46 | forKeyPath:NSStringFromSelector(@selector(state)) 47 | options:(NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew) 48 | context:OPURLSessionOperationKVOContext]; 49 | 50 | [self.task resume]; 51 | } 52 | 53 | - (void)cancel 54 | { 55 | [self.task cancel]; 56 | [super cancel]; 57 | } 58 | 59 | 60 | #pragma mark - KVO 61 | #pragma mark - 62 | 63 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 64 | { 65 | if (context == OPURLSessionOperationKVOContext) { 66 | if (object == [self task] && [keyPath isEqualToString:NSStringFromSelector(@selector(state))]) { 67 | if ([object state] == NSURLSessionTaskStateCompleted) { 68 | @try { 69 | [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(state)) context:context]; 70 | } 71 | @catch (NSException *__unused exception) {} 72 | 73 | if ([self shouldSuppressErrors]) { 74 | [self finish]; 75 | } else { 76 | [self finishWithError:[self.task error]]; 77 | } 78 | } 79 | } 80 | } else { 81 | [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 82 | } 83 | } 84 | 85 | 86 | #pragma mark - Lifecycle 87 | #pragma mark - 88 | 89 | - (instancetype)initWithTask:(NSURLSessionTask *)task 90 | { 91 | self = [super init]; 92 | if (!self) { 93 | return nil; 94 | } 95 | 96 | NSAssert([task state] == NSURLSessionTaskStateSuspended, @"Tasks must be suspended."); 97 | 98 | _task = task; 99 | _shouldSuppressErrors = NO; 100 | 101 | return self; 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPNegatedCondition.m: -------------------------------------------------------------------------------- 1 | // OPNegatedCondition.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPNegatedCondition.h" 23 | #import "NSError+Operative.h" 24 | 25 | 26 | @interface OPNegatedCondition () 27 | 28 | /** 29 | * Underlying condition which is evaluated. 30 | */ 31 | @property (strong, nonatomic, readonly) id condition; 32 | 33 | @end 34 | 35 | 36 | @implementation OPNegatedCondition 37 | 38 | 39 | #pragma mark - Lifecycle 40 | #pragma mark - 41 | 42 | - (instancetype)initWithCondition:(id )condition 43 | { 44 | self = [super init]; 45 | 46 | _condition = condition; 47 | 48 | return self; 49 | } 50 | 51 | 52 | #pragma mark - OPOperationCondition Protocol 53 | #pragma mark - 54 | 55 | - (NSString *)name 56 | { 57 | return [NSString stringWithFormat:@"Not<%@>", [self.condition name]]; 58 | } 59 | 60 | - (BOOL)isMutuallyExclusive 61 | { 62 | return [self.condition isMutuallyExclusive]; 63 | } 64 | 65 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 66 | { 67 | return [self.condition dependencyForOperation:operation]; 68 | } 69 | 70 | - (void)evaluateConditionForOperation:(OPOperation *)operation 71 | completion:(void (^)(__unused OPOperationConditionResultStatus aResult, __unused NSError *anError))completion 72 | { 73 | void (^underlyingCompletion)(OPOperationConditionResultStatus, NSError *) = ^(OPOperationConditionResultStatus result, __unused NSError *error) { 74 | switch (result) { 75 | case OPOperationConditionResultStatusSatisfied: { 76 | // If the composed condition succeeded, then this one failed. 77 | NSDictionary *userInfo = @{ 78 | kOPOperationConditionKey : NSStringFromClass([self class]), 79 | kOPOperationNegatedConditionKey : NSStringFromClass([self.condition class]) 80 | }; 81 | NSError *negatedError = [NSError errorWithCode:OPOperationErrorCodeConditionFailed userInfo:userInfo]; 82 | completion(OPOperationConditionResultStatusFailed, negatedError); 83 | } 84 | break; 85 | 86 | case OPOperationConditionResultStatusFailed: { 87 | // If the composed condition failed, then this one succeeded. 88 | completion(OPOperationConditionResultStatusSatisfied, nil); 89 | } 90 | break; 91 | 92 | default: 93 | break; 94 | } 95 | }; 96 | 97 | [self.condition evaluateConditionForOperation:operation 98 | completion:underlyingCompletion]; 99 | } 100 | 101 | 102 | @end -------------------------------------------------------------------------------- /Example/Tests/BlockObserversTests.m: -------------------------------------------------------------------------------- 1 | // BlockObserversTests.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | #import 25 | 26 | @interface BlockObserversTests : XCTestCase 27 | 28 | @end 29 | 30 | @implementation BlockObserversTests 31 | 32 | - (void)setUp { 33 | [super setUp]; 34 | // Put setup code here. This method is called before the invocation of each test method in the class. 35 | } 36 | 37 | - (void)tearDown { 38 | // Put teardown code here. This method is called after the invocation of each test method in the class. 39 | [super tearDown]; 40 | } 41 | 42 | - (void)testStartHandler { 43 | XCTestExpectation *expectation = [self expectationWithDescription:@"Block observer should call start handler"]; 44 | 45 | OPOperationQueue *operationQueue = [[OPOperationQueue alloc] init]; 46 | OPOperation *operation = [[OPOperation alloc] init]; 47 | 48 | [operation addObserver:[[OPBlockObserver alloc] initWithStartHandler:^(OPOperation *operation) { 49 | [expectation fulfill]; 50 | } produceHandler:^(OPOperation *operation, NSOperation *newOperation) { 51 | 52 | } finishHandler:^(OPOperation *operation, NSArray *errors) { 53 | 54 | }]]; 55 | 56 | [operationQueue addOperation:operation]; 57 | 58 | [self waitForExpectationsWithTimeout:1 handler:nil]; 59 | } 60 | 61 | - (void)testFinishHandler { 62 | XCTestExpectation *expectation = [self expectationWithDescription:@"Block observer should call finish handler"]; 63 | 64 | OPOperationQueue *operationQueue = [[OPOperationQueue alloc] init]; 65 | OPOperation *operation = [[OPOperation alloc] init]; 66 | 67 | [operation addObserver:[[OPBlockObserver alloc] initWithStartHandler:^(OPOperation *operation) { 68 | 69 | } produceHandler:^(OPOperation *operation, NSOperation *newOperation) { 70 | 71 | } finishHandler:^(OPOperation *operation, NSArray *errors) { 72 | [expectation fulfill]; 73 | }]]; 74 | 75 | [operationQueue addOperation:operation]; 76 | 77 | [self waitForExpectationsWithTimeout:1 handler:nil]; 78 | } 79 | 80 | - (void)testProduceHandler { 81 | XCTestExpectation *expectation = [self expectationWithDescription:@"Block observer should call produce handler"]; 82 | 83 | OPOperationQueue *operationQueue = [[OPOperationQueue alloc] init]; 84 | OPOperation *operation = [[OPOperation alloc] init]; 85 | 86 | [operation addObserver:[[OPBlockObserver alloc] initWithStartHandler:^(OPOperation *operation) { 87 | 88 | } produceHandler:^(OPOperation *operation, NSOperation *newOperation) { 89 | [expectation fulfill]; 90 | } finishHandler:^(OPOperation *operation, NSArray *errors) { 91 | [operation produceOperation:[[OPOperation alloc] init]]; 92 | }]]; 93 | 94 | [operationQueue addOperation:operation]; 95 | 96 | [self waitForExpectationsWithTimeout:1 handler:nil]; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /Example/Operative.xcodeproj/xcshareddata/xcschemes/Operative-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Operations/Misc/OPLocationOperation.m: -------------------------------------------------------------------------------- 1 | // OPLocationOperation.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | 23 | #import "OPLocationOperation.h" 24 | 25 | #import "OPOperationConditionMutuallyExclusive.h" 26 | #import "OPLocationCondition.h" 27 | 28 | @interface OPLocationOperation () 29 | 30 | @property (assign, nonatomic) CLLocationAccuracy accuracy; 31 | 32 | @property (strong, nonatomic) CLLocationManager *manager; 33 | 34 | @property (copy, nonatomic) void (^handler)(CLLocation *); 35 | 36 | - (instancetype)init NS_DESIGNATED_INITIALIZER; 37 | 38 | @end 39 | 40 | 41 | @implementation OPLocationOperation 42 | 43 | 44 | #pragma mark - Overrides 45 | #pragma mark - 46 | 47 | - (void)execute 48 | { 49 | dispatch_async(dispatch_get_main_queue(), ^{ 50 | /** 51 | * `CLLocationManager` needs to be created on a thread with an active 52 | * run loop, so for simplicity we do this on the main queue. 53 | */ 54 | CLLocationManager *manager = [[CLLocationManager alloc] init]; 55 | [manager setDesiredAccuracy:[self accuracy]]; 56 | [manager setDelegate:self]; 57 | [manager startUpdatingLocation]; 58 | 59 | [self setManager:manager]; 60 | }); 61 | } 62 | 63 | - (void)cancel 64 | { 65 | dispatch_async(dispatch_get_main_queue(), ^{ 66 | [self stopLocationUpdates]; 67 | [super cancel]; 68 | }); 69 | } 70 | 71 | - (void)stopLocationUpdates 72 | { 73 | [self.manager stopUpdatingLocation]; 74 | [self setManager:nil]; 75 | } 76 | 77 | 78 | #pragma mark - CLLocationManagerDelegate 79 | #pragma mark - 80 | 81 | - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations 82 | { 83 | [locations enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 84 | CLLocation *location = obj; 85 | if (location.horizontalAccuracy < [self accuracy]) { 86 | [self stopLocationUpdates]; 87 | self.handler(location); 88 | [self finish]; 89 | 90 | *stop = YES; 91 | } 92 | }]; 93 | } 94 | 95 | - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error 96 | { 97 | [self stopLocationUpdates]; 98 | [self finishWithError:error]; 99 | } 100 | 101 | 102 | #pragma mark - Lifecycle 103 | #pragma mark - 104 | 105 | - (instancetype)initWithAccuracy:(CLLocationAccuracy)accuracy 106 | locationHandler:(void (^)(CLLocation *location))locationHandler 107 | { 108 | self = [super init]; 109 | if (!self) { 110 | return nil; 111 | } 112 | 113 | _accuracy = accuracy; 114 | _handler = [locationHandler copy]; 115 | 116 | [self addCondition:[[OPLocationCondition alloc] initWithUsage:OPLocationConditionWhenInUse]]; 117 | [self addCondition:[[OPOperationConditionMutuallyExclusive alloc] initWithClass:[CLLocationManager class]]]; 118 | 119 | return self; 120 | } 121 | 122 | - (instancetype)init 123 | { 124 | self = [super init]; 125 | if (!self) { 126 | return nil; 127 | } 128 | 129 | return self; 130 | } 131 | 132 | @end 133 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Observers/OPTimeoutObserver.m: -------------------------------------------------------------------------------- 1 | // OPTimeoutObserver.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPTimeoutObserver.h" 23 | #import "OPOperation.h" 24 | #import "NSError+Operative.h" 25 | 26 | 27 | static NSString *const kOPTimeoutObserverErrorKey = @"OPTimeoutObserverError"; 28 | 29 | 30 | @interface OPTimeoutObserver () 31 | 32 | @property (assign, nonatomic) NSTimeInterval timeout; 33 | 34 | #if OS_OBJECT_USE_OBJC 35 | @property (strong, nonatomic) dispatch_source_t timer; 36 | #else 37 | @property (assign, nonatomic) dispatch_source_t timer; 38 | #endif 39 | 40 | @end 41 | 42 | 43 | @implementation OPTimeoutObserver 44 | 45 | #pragma mark - OPOperationObserver Protocol 46 | #pragma mark - 47 | 48 | - (void)operationDidStart:(OPOperation *)operation 49 | { 50 | // set up timeout handler 51 | void(^timeoutHandler)() = ^{ 52 | /** 53 | * Cancel the operation if it hasn't finished and hasn't already 54 | * been cancelled. 55 | */ 56 | if (![operation isFinished] && ![operation isCancelled]) { 57 | NSDictionary *userInfo = @{ kOPTimeoutObserverErrorKey : @(([self timeout])) }; 58 | NSError *error = [NSError errorWithCode:OPOperationErrorCodeExecutionFailed userInfo:userInfo]; 59 | [operation cancelWithError:error]; 60 | } 61 | }; 62 | 63 | // When the operation starts, queue up a block to cause it to time out. 64 | self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0)); 65 | 66 | // Cancel operation immediately if timer wasn't created 67 | if(!self.timer) { 68 | timeoutHandler(); 69 | return; 70 | } 71 | 72 | // calculate time delta 73 | int64_t delta = (int64_t)(self.timeout * NSEC_PER_SEC); 74 | 75 | // calculate the leeway for timer using the same way as dispatch_after 76 | int64_t leeway = delta / 10; 77 | if(leeway < NSEC_PER_MSEC) leeway = NSEC_PER_MSEC; 78 | if(leeway > 60 * NSEC_PER_SEC) leeway = 60 * NSEC_PER_SEC; 79 | 80 | dispatch_time_t when = dispatch_walltime(NULL, delta); 81 | dispatch_source_set_event_handler(self.timer, timeoutHandler); 82 | dispatch_source_set_timer(self.timer, when, DISPATCH_TIME_FOREVER, leeway); 83 | dispatch_resume(self.timer); 84 | } 85 | 86 | - (void)operation:(OPOperation *)operation didProduceOperation:(NSOperation *)newOperation 87 | { 88 | // No-op 89 | } 90 | 91 | - (void)operation:(OPOperation *)operation didFinishWithErrors:(NSArray *)errors 92 | { 93 | if(!self.timer) { 94 | return; 95 | } 96 | 97 | // Cancel and release the timer 98 | dispatch_source_cancel(self.timer); 99 | 100 | #if !OS_OBJECT_USE_OBJC 101 | dispatch_release(self.timer); 102 | #endif 103 | 104 | self.timer = nil; 105 | } 106 | 107 | 108 | #pragma mark - Lifecycle 109 | #pragma mark - 110 | 111 | - (instancetype)initWithTimeout:(NSTimeInterval)timeout; 112 | { 113 | self = [super init]; 114 | if (!self) { 115 | return nil; 116 | } 117 | 118 | _timeout = timeout; 119 | 120 | return self; 121 | } 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operation Queue/OPExclusivityController.m: -------------------------------------------------------------------------------- 1 | // OPExclusivityController.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPExclusivityController.h" 23 | 24 | @interface OPExclusivityController() 25 | 26 | @property (strong, nonatomic) NSMutableDictionary *operations; 27 | 28 | #if OS_OBJECT_USE_OBJC 29 | @property (strong, nonatomic) dispatch_queue_t serialQueue; 30 | #else 31 | @property (assign, nonatomic) dispatch_queue_t serialQueue; 32 | #endif 33 | 34 | @end 35 | 36 | @implementation OPExclusivityController 37 | 38 | 39 | #pragma mark - Add & Remove Operations 40 | #pragma mark - 41 | 42 | - (void)addOperation:(OPOperation *)operation categories:(NSArray *)categories 43 | { 44 | dispatch_sync([self serialQueue], ^{ 45 | for (NSString *category in categories) { 46 | [self noqueue_addOperation:operation category:category]; 47 | } 48 | }); 49 | } 50 | 51 | 52 | - (void)removeOperation:(OPOperation *)operation categories:(NSArray *)categories 53 | { 54 | dispatch_sync([self serialQueue], ^{ 55 | for (NSString *category in categories) { 56 | [self noqueue_removeOperation:operation category:category]; 57 | } 58 | }); 59 | } 60 | 61 | 62 | #pragma mark - Operation Management 63 | #pragma mark - 64 | 65 | - (void)noqueue_addOperation:(OPOperation *)operation category:(NSString *)category 66 | { 67 | NSArray *operationsWithThisCategory = self.operations[category] ?: @[]; 68 | 69 | if ([operationsWithThisCategory count]) { 70 | OPOperation *op = [operationsWithThisCategory lastObject]; 71 | [operation addDependency:op]; 72 | } 73 | 74 | operationsWithThisCategory = [operationsWithThisCategory arrayByAddingObject:operation]; 75 | 76 | self.operations[category] = operationsWithThisCategory; 77 | } 78 | 79 | - (void)noqueue_removeOperation:(OPOperation *)operation category:(NSString *)category 80 | { 81 | if (!self.operations[category]) { 82 | return; 83 | } 84 | 85 | NSArray *operationsWithThisCategory = self.operations[category]; 86 | 87 | NSUInteger index = [operationsWithThisCategory indexOfObject:operation]; 88 | if (index != NSNotFound) { 89 | NSMutableArray *mutableArray = [operationsWithThisCategory mutableCopy]; 90 | [mutableArray removeObjectAtIndex:index]; 91 | operationsWithThisCategory = [NSArray arrayWithArray:mutableArray]; 92 | self.operations[category] = operationsWithThisCategory; 93 | } 94 | } 95 | 96 | 97 | #pragma mark - Lifecycle 98 | #pragma mark - 99 | 100 | + (OPExclusivityController *)sharedExclusivityController 101 | { 102 | static OPExclusivityController *_sharedInstance = nil; 103 | static dispatch_once_t onceToken; 104 | dispatch_once(&onceToken, ^{ 105 | _sharedInstance = [[OPExclusivityController alloc] init]; 106 | }); 107 | 108 | return _sharedInstance; 109 | } 110 | 111 | - (instancetype)init 112 | { 113 | self = [super init]; 114 | if (!self) { 115 | return nil; 116 | } 117 | 118 | _serialQueue = dispatch_queue_create("Operative.ExclusivityController", DISPATCH_QUEUE_SERIAL); 119 | _operations = [[NSMutableDictionary alloc] init]; 120 | 121 | return self; 122 | } 123 | 124 | @end 125 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Observers/OPBackgroundObserver.m: -------------------------------------------------------------------------------- 1 | // OPBackgroundObserver.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | 23 | #import "OPBackgroundObserver.h" 24 | 25 | 26 | @interface OPBackgroundObserver () 27 | 28 | @property (assign, nonatomic) UIBackgroundTaskIdentifier identifier; 29 | 30 | @property (assign, nonatomic, getter=isInBackground) BOOL inBackground; 31 | 32 | 33 | @end 34 | 35 | 36 | @implementation OPBackgroundObserver 37 | 38 | 39 | #pragma mark - Start / End Background Task 40 | #pragma mark - 41 | 42 | - (void)startBackgroundTask 43 | { 44 | if ([self identifier] != UIBackgroundTaskInvalid) { 45 | return; 46 | } 47 | 48 | UIBackgroundTaskIdentifier identifier = [[UIApplication sharedApplication] beginBackgroundTaskWithName:NSStringFromClass([OPBackgroundObserver class]) 49 | expirationHandler:^{ 50 | [self endBackgroundTask]; 51 | }]; 52 | [self setIdentifier:identifier]; 53 | } 54 | 55 | - (void)endBackgroundTask 56 | { 57 | if ([self identifier] == UIBackgroundTaskInvalid) { 58 | return; 59 | } 60 | 61 | [[UIApplication sharedApplication] endBackgroundTask:[self identifier]]; 62 | [self setIdentifier:UIBackgroundTaskInvalid]; 63 | } 64 | 65 | 66 | #pragma mark - Notification Actions 67 | #pragma mark - 68 | 69 | - (void)didEnterBackground:(NSNotification *)notification 70 | { 71 | if (![self isInBackground]) { 72 | [self setInBackground:YES]; 73 | [self startBackgroundTask]; 74 | } 75 | } 76 | 77 | - (void)didEnterForeground:(NSNotification *)notification 78 | { 79 | if ([self isInBackground]) { 80 | [self setInBackground:NO]; 81 | [self endBackgroundTask]; 82 | } 83 | } 84 | 85 | 86 | #pragma mark - OPOperationObserver Protocol 87 | #pragma mark - 88 | 89 | - (void)operationDidStart:(OPOperation *)operation 90 | { 91 | // No-op 92 | } 93 | 94 | - (void)operation:(OPOperation *)operation didProduceOperation:(NSOperation *)newOperation 95 | { 96 | // No-op 97 | } 98 | 99 | - (void)operation:(OPOperation *)operation didFinishWithErrors:(NSArray *)errors 100 | { 101 | [self endBackgroundTask]; 102 | } 103 | 104 | 105 | #pragma mark - Lifecycle 106 | #pragma mark - 107 | 108 | - (instancetype)init 109 | { 110 | self = [super init]; 111 | if (!self) { 112 | return nil; 113 | } 114 | 115 | // We need to know when the application moves to/from the background. 116 | NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; 117 | [center addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; 118 | [center addObserver:self selector:@selector(didEnterForeground:) name:UIApplicationDidBecomeActiveNotification object:nil]; 119 | 120 | _identifier = UIBackgroundTaskInvalid; 121 | _inBackground = ([[UIApplication sharedApplication] applicationState] == UIApplicationStateBackground); 122 | 123 | // If we're in the background already, immediately begin the background task. 124 | if (_inBackground) { 125 | [self startBackgroundTask]; 126 | } 127 | 128 | return self; 129 | } 130 | 131 | - (void)dealloc 132 | { 133 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 134 | } 135 | 136 | @end 137 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/OPOperation.h: -------------------------------------------------------------------------------- 1 | // OPOperation.h 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | @protocol OPOperationObserver; 25 | @protocol OPOperationCondition; 26 | 27 | 28 | /** 29 | * `OPOperation` is a subclass of `NSOperation` 30 | * from which all other operations within `Operative` should be derived. 31 | * This class adds both Conditions and Observers, which allow the operation 32 | * to define extended readiness requirements, as well as notify many 33 | * interested parties about interesting operation state changes 34 | */ 35 | @interface OPOperation : NSOperation 36 | 37 | /** 38 | * `BOOL` value indicating if the operation is considered user 39 | * initiated. Changing this value will change the operations quality 40 | * of service to `NSOperationQualityOfServiceUserInitiated` or 41 | * `NSOperationQualityOfServiceUtility` accordingly 42 | */ 43 | @property (assign, nonatomic) BOOL userInitiated; 44 | 45 | /** 46 | * An array of objects that conform to the `OPOperationCondition` 47 | * protocol. Before execution of the operation, conditions will be 48 | * checked and if met the operation will execute as normal. 49 | * 50 | * Array should not be manipulated directly. 51 | * 52 | * @see -addCondition: 53 | */ 54 | @property (strong, nonatomic, readonly) NSMutableArray *conditions; 55 | 56 | 57 | ///--------------------------------------------- 58 | /// @name Conditions, Observers and Dependencies 59 | ///--------------------------------------------- 60 | 61 | - (void)addCondition:(id )condition; 62 | 63 | - (void)addObserver:(id )observer; 64 | 65 | - (void)addDependency:(NSOperation *)operation; 66 | 67 | 68 | ///--------------------------------- 69 | /// @name Execution and Cancellation 70 | ///--------------------------------- 71 | 72 | /** 73 | * Indicates that the Operation can now begin to evaluate 74 | * readiness conditions, if appropriate. 75 | */ 76 | - (void)willEnqueue; 77 | 78 | /** 79 | * -execute is the entry point of execution for all `OPOperation` subclasses. 80 | * If you subclass `OPOperation` and wish to customize its execution, you 81 | * would do so by overriding the -execute method. 82 | * At some point, your `OPOperation` subclass must call one of the "finish" 83 | * methods defined below; this is how you indicate that your operation has 84 | * finished its execution, and that operations dependent on yours can 85 | * re-evaluate their readiness state. 86 | */ 87 | - (void)execute; 88 | 89 | - (void)cancelWithError:(NSError *)error; 90 | 91 | - (void)produceOperation:(NSOperation *)operation; 92 | 93 | /* 94 | * This is a convenience method to simplify calling the actual 95 | * -finishWithErrors: method, when an error isn't present 96 | * 97 | * @see -finishWithError: 98 | */ 99 | - (void)finish; 100 | 101 | /* 102 | * Most operations may finish with a single error, if they have one at all. 103 | * This is a convenience method to simplify the calling of -finishWithErrors: 104 | * -finishWithError: is useful if you wish to finish with an error provided 105 | * by the system frameworks / when a single error is present. 106 | * 107 | * @see -finish 108 | * @see -finishWithErrors: 109 | */ 110 | - (void)finishWithError:(NSError *)error; 111 | 112 | /* 113 | * Called once an `OPOperation` has finished. This method transitions the 114 | * operation to a state of finishing, informs any observers that the operation 115 | * finished, and then transitions to a state of finished 116 | * 117 | * @see -finish 118 | * @see -finishWithError: 119 | */ 120 | - (void)finishWithErrors:(NSArray *)errors; 121 | 122 | /* 123 | * Subclasses may override -finishedWithErrors: if they wish to react to the operation 124 | * finishing with errors. 125 | */ 126 | - (void)finishedWithErrors:(NSArray *)errors; 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Operations/UI/OPAlertOperation.m: -------------------------------------------------------------------------------- 1 | // OPAlertOperation.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #if TARGET_OS_IPHONE 23 | 24 | #import "OPAlertOperation.h" 25 | #import "OPOperationConditionMutuallyExclusive.h" 26 | 27 | 28 | @interface OPAlertOperation () 29 | 30 | @property (strong, nonatomic) UIAlertController *alertController; 31 | 32 | @property (strong, nonatomic) UIViewController *presentationContext; 33 | 34 | @end 35 | 36 | 37 | @implementation OPAlertOperation 38 | 39 | 40 | #pragma mark - Add Action 41 | #pragma mark - 42 | 43 | - (void)addAction:(NSString *)title 44 | style:(UIAlertActionStyle)style 45 | handler:(void (^)(OPAlertOperation *alertOperation))handler; 46 | { 47 | __weak __typeof__(self) weakSelf = self; 48 | UIAlertAction *action = [UIAlertAction actionWithTitle:title style:style handler:^(UIAlertAction *action) { 49 | __typeof__(self) strongSelf = weakSelf; 50 | 51 | if (handler) { 52 | handler(strongSelf); 53 | } 54 | 55 | [strongSelf finish]; 56 | }]; 57 | 58 | [self.alertController addAction:action]; 59 | } 60 | 61 | 62 | #pragma mark - Overrides 63 | #pragma mark - 64 | 65 | - (void)execute 66 | { 67 | if (![self presentationContext]) { 68 | [self finish]; 69 | return; 70 | } 71 | 72 | dispatch_async(dispatch_get_main_queue(), ^{ 73 | if([self isCancelled]) { 74 | return; 75 | } 76 | 77 | if ([self.alertController.actions count] == 0) { 78 | [self addAction:@"OK" style:UIAlertActionStyleDefault handler:nil]; 79 | } 80 | 81 | [self.presentationContext presentViewController:[self alertController] animated:YES completion:nil]; 82 | }); 83 | } 84 | 85 | - (void)cancel 86 | { 87 | dispatch_async(dispatch_get_main_queue(), ^{ 88 | if(self.alertController.presentingViewController) 89 | { 90 | [self.alertController dismissViewControllerAnimated:YES completion:^{ 91 | [super cancel]; 92 | }]; 93 | } 94 | else 95 | { 96 | [super cancel]; 97 | } 98 | }); 99 | } 100 | 101 | 102 | #pragma mark - Getters / Setters 103 | #pragma mark - 104 | 105 | - (NSString *)title 106 | { 107 | return [self.alertController title]; 108 | } 109 | 110 | - (void)setTitle:(NSString *)title 111 | { 112 | [self.alertController setTitle:[title copy]]; 113 | } 114 | 115 | - (NSString *)message 116 | { 117 | return [self.alertController message]; 118 | } 119 | 120 | - (void)setMessage:(NSString *)message 121 | { 122 | [self.alertController setMessage:[message copy]]; 123 | } 124 | 125 | 126 | #pragma mark - Lifecycle 127 | #pragma mark - 128 | 129 | - (instancetype)initWithPresentationContext:(UIViewController *)presentationContext 130 | { 131 | self = [self initWithPresentationContext:presentationContext 132 | preferredStyle:UIAlertControllerStyleActionSheet]; 133 | if (!self) { 134 | return nil; 135 | } 136 | 137 | return self; 138 | } 139 | 140 | - (instancetype)initWithPresentationContext:(UIViewController *)presentationContext 141 | preferredStyle:(UIAlertControllerStyle)preferredStyle 142 | { 143 | self = [super init]; 144 | 145 | if (!self) { 146 | return nil; 147 | } 148 | 149 | _alertController = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:preferredStyle]; 150 | 151 | _presentationContext = presentationContext ?: [[[UIApplication sharedApplication] keyWindow] rootViewController]; 152 | 153 | [self addCondition:[OPOperationConditionMutuallyExclusive alertPresentationExclusivity]]; 154 | 155 | /** 156 | * This operation modifies the view controller hierarchy. 157 | * Doing this while other such operations are executing can lead to 158 | * inconsistencies in UIKit. So, let's make them mutally exclusive. 159 | */ 160 | [self addCondition:[OPOperationConditionMutuallyExclusive mutuallyExclusiveWith:[UIViewController class]]]; 161 | 162 | return self; 163 | } 164 | 165 | @end 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Operations/Misc/OPGroupOperation.m: -------------------------------------------------------------------------------- 1 | // OPGroupOperation.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPGroupOperation.h" 23 | #import "OPOperationQueue.h" 24 | 25 | 26 | @interface OPGroupOperation() 27 | 28 | - (instancetype)init NS_DESIGNATED_INITIALIZER; 29 | 30 | /** 31 | * Common initialized elements used in both `-init` & `-initWithOperations:` 32 | */ 33 | - (void)commonInit; 34 | 35 | @property (strong, nonatomic) OPOperationQueue *internalQueue; 36 | @property (strong, nonatomic) NSBlockOperation *finishingOperation; 37 | 38 | @property (strong, nonatomic) NSMutableArray *aggregatedErrors; 39 | 40 | @end 41 | 42 | 43 | @implementation OPGroupOperation 44 | 45 | #pragma mark - Debugging 46 | #pragma mark - 47 | 48 | - (NSString *)debugDescription 49 | { 50 | NSMutableString *mutableString = [[NSMutableString alloc] init]; 51 | NSString *description = [super debugDescription]; 52 | NSString *result; 53 | 54 | NSArray *lines = [[self.internalQueue debugDescription] componentsSeparatedByString:@"\n"]; 55 | 56 | for(NSString *str in lines) 57 | { 58 | [mutableString appendFormat:@"\t%@\n", str]; 59 | } 60 | 61 | result = [description stringByAppendingFormat:@"\n%@", mutableString]; 62 | 63 | return [result stringByTrimmingCharactersInSet:[NSCharacterSet newlineCharacterSet]]; 64 | } 65 | 66 | #pragma mark - 67 | #pragma mark - 68 | 69 | - (void)addOperation:(NSOperation *)operation 70 | { 71 | [self.internalQueue addOperation:operation]; 72 | } 73 | 74 | - (void)addOperations:(NSArray *)operations 75 | { 76 | [self.internalQueue addOperations:operations waitUntilFinished:NO]; 77 | } 78 | 79 | - (void)aggregateError:(NSError *)error 80 | { 81 | [self.aggregatedErrors addObject:error]; 82 | } 83 | 84 | - (void)operationDidFinish:(NSOperation *)operation withErrors:(NSArray *)errors 85 | { 86 | // No-op 87 | // For use by subclass. 88 | } 89 | 90 | 91 | #pragma mark - Overrides 92 | #pragma mark - 93 | 94 | - (void)cancel 95 | { 96 | [self.internalQueue cancelAllOperations]; 97 | [super cancel]; 98 | } 99 | 100 | - (void)execute 101 | { 102 | [self.internalQueue setSuspended:NO]; 103 | [self.internalQueue addOperation:self.finishingOperation]; 104 | } 105 | 106 | 107 | #pragma mark - OPOperationQueueDelegate 108 | #pragma mark - 109 | 110 | - (void)operationQueue:(OPOperationQueue *)operationQueue willAddOperation:(NSOperation *)operation 111 | { 112 | NSAssert(![self.finishingOperation isFinished] && ![self.finishingOperation isExecuting], @"Cannot add new operations to a group after the group has completed"); 113 | 114 | if ([self finishingOperation] != operation) { 115 | [self.finishingOperation addDependency:operation]; 116 | } 117 | } 118 | 119 | - (void)operationQueue:(OPOperationQueue *)operationQueue operationDidFinish:(NSOperation *)operation withErrors:(NSArray *)errors 120 | { 121 | [self.aggregatedErrors addObjectsFromArray:errors]; 122 | 123 | if ([self finishingOperation] == operation) { 124 | [self.internalQueue setSuspended:YES]; 125 | [self finishWithErrors:[self aggregatedErrors]]; 126 | } else { 127 | [self operationDidFinish:operation withErrors:errors]; 128 | } 129 | } 130 | 131 | 132 | #pragma mark - Lifecycle 133 | #pragma mark - 134 | 135 | - (instancetype)init 136 | { 137 | self = [super init]; 138 | if (!self) { 139 | return nil; 140 | } 141 | 142 | [self commonInit]; 143 | 144 | return self; 145 | } 146 | 147 | - (instancetype)initWithOperations:(NSArray *)operations 148 | { 149 | self = [super init]; 150 | if (!self) { 151 | return nil; 152 | } 153 | 154 | [self commonInit]; 155 | 156 | for (NSOperation *operation in operations) { 157 | [_internalQueue addOperation:operation]; 158 | } 159 | 160 | return self; 161 | } 162 | 163 | 164 | #pragma mark - Private 165 | #pragma mark - 166 | 167 | - (void)commonInit 168 | { 169 | OPOperationQueue *queue = [[OPOperationQueue alloc] init]; 170 | [queue setSuspended:YES]; 171 | [queue setDelegate:self]; 172 | 173 | _internalQueue = queue; 174 | 175 | _finishingOperation = [NSBlockOperation blockOperationWithBlock:^{}]; 176 | 177 | _aggregatedErrors = [[NSMutableArray alloc] init]; 178 | } 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /Pod/Classes/Core/Conditions/OPReachabilityCondition.m: -------------------------------------------------------------------------------- 1 | // OPReachabilityCondition.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPReachabilityCondition.h" 23 | 24 | #import "NSError+Operative.h" 25 | 26 | #import 27 | 28 | 29 | static NSString *const kOPOperationHostKey = @"OperationHost"; 30 | 31 | 32 | @interface OPReachabilityController : NSObject 33 | 34 | + (OPReachabilityController *)sharedInstance; 35 | 36 | #if OS_OBJECT_USE_OBJC 37 | @property (strong, nonatomic) dispatch_queue_t reachabilityQueue; 38 | #else 39 | @property (assign, nonatomic) dispatch_queue_t reachabilityQueue; 40 | #endif 41 | 42 | @property (strong, nonatomic) NSMutableDictionary *reachabilityRefs; 43 | 44 | - (void)requestReachabilityWithURL:(NSURL *)url 45 | completionHandler:(void (^)(BOOL reachable))completionHandler; 46 | 47 | @end 48 | 49 | 50 | @interface OPReachabilityCondition () 51 | 52 | @property (copy, nonatomic) NSURL *host; 53 | 54 | @end 55 | 56 | 57 | 58 | @implementation OPReachabilityCondition 59 | 60 | 61 | #pragma mark - OPOperationCondition Protocol 62 | #pragma mark - 63 | 64 | - (NSString *)name 65 | { 66 | return @"Reachability"; 67 | } 68 | 69 | - (BOOL)isMutuallyExclusive 70 | { 71 | return NO; 72 | } 73 | 74 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 75 | { 76 | return nil; 77 | } 78 | 79 | - (void)evaluateConditionForOperation:(OPOperation *)operation 80 | completion:(void (^)(OPOperationConditionResultStatus, NSError *))completion 81 | { 82 | [[OPReachabilityController sharedInstance] requestReachabilityWithURL:[self host] 83 | completionHandler:^(BOOL reachable) { 84 | if (reachable) { 85 | completion(OPOperationConditionResultStatusSatisfied, nil); 86 | } else { 87 | NSError *error = [NSError errorWithCode:OPOperationErrorCodeConditionFailed userInfo:@{ 88 | kOPOperationConditionKey : [self name], 89 | kOPOperationHostKey : [self host] 90 | }]; 91 | completion(OPOperationConditionResultStatusFailed, error); 92 | } 93 | }]; 94 | } 95 | 96 | 97 | #pragma mark - Lifecycle 98 | #pragma mark - 99 | 100 | - (instancetype)initWithHost:(NSURL *)host 101 | { 102 | self = [super init]; 103 | if (!self) { 104 | return nil; 105 | } 106 | 107 | _host = [host copy]; 108 | 109 | return self; 110 | } 111 | 112 | @end 113 | 114 | 115 | @implementation OPReachabilityController 116 | 117 | 118 | #pragma mark - Reachability 119 | #pragma mark - 120 | 121 | - (void)requestReachabilityWithURL:(NSURL *)url 122 | completionHandler:(void (^)(BOOL reachable))completionHandler 123 | { 124 | NSString *host = [url host]; 125 | 126 | if (!host) { 127 | completionHandler(NO); 128 | return; 129 | } 130 | 131 | dispatch_async([self reachabilityQueue], ^{ 132 | SCNetworkReachabilityRef ref = (__bridge SCNetworkReachabilityRef)(self.reachabilityRefs[host]); 133 | 134 | if (!ref) { 135 | ref = SCNetworkReachabilityCreateWithName(nil, [host UTF8String]); 136 | } 137 | 138 | if (ref) { 139 | self.reachabilityRefs[host] = (__bridge id)(ref); 140 | 141 | BOOL reachable = NO; 142 | SCNetworkReachabilityFlags flags = 0; 143 | if (SCNetworkReachabilityGetFlags(ref, &flags) != 0) { 144 | reachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); 145 | } 146 | completionHandler(reachable); 147 | } else { 148 | completionHandler(NO); 149 | } 150 | }); 151 | } 152 | 153 | 154 | #pragma mark - Lifecycle 155 | #pragma mark - 156 | 157 | + (OPReachabilityController *)sharedInstance 158 | { 159 | static OPReachabilityController *_sharedInstance = nil; 160 | static dispatch_once_t onceToken; 161 | dispatch_once(&onceToken, ^{ 162 | _sharedInstance = [[OPReachabilityController alloc] init]; 163 | }); 164 | 165 | return _sharedInstance; 166 | } 167 | 168 | - (instancetype)init 169 | { 170 | self = [super init]; 171 | if (!self) { 172 | return nil; 173 | } 174 | 175 | _reachabilityQueue = dispatch_queue_create("Operative.Reachability", DISPATCH_QUEUE_SERIAL); 176 | _reachabilityRefs = [[NSMutableDictionary alloc] init]; 177 | 178 | return self; 179 | } 180 | 181 | @end 182 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Observers/OPNetworkObserver.m: -------------------------------------------------------------------------------- 1 | // OPNetworkObserver.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPNetworkObserver.h" 23 | 24 | 25 | /** 26 | * Essentially a cancellable `dispatch_after`. 27 | */ 28 | @interface OPTimer : NSObject 29 | 30 | @property (assign, nonatomic, getter=isCancelled) BOOL cancelled; 31 | 32 | @property (copy, nonatomic, readonly) dispatch_block_t handler; 33 | 34 | - (instancetype)initWithInterval:(NSTimeInterval)interval handler:(dispatch_block_t)handler NS_DESIGNATED_INITIALIZER; 35 | 36 | - (instancetype)init NS_UNAVAILABLE; 37 | 38 | - (void)cancel; 39 | 40 | @end 41 | 42 | 43 | /** 44 | * A singleton to manage a visual "reference count" on the network activity indicator. 45 | */ 46 | @interface OPNetworkIndicatorController : NSObject 47 | 48 | + (OPNetworkIndicatorController *)sharedInstance; 49 | 50 | @property (assign, nonatomic) NSUInteger activityCount; 51 | 52 | @property (strong, nonatomic) OPTimer *visibilityTimer; 53 | 54 | - (void)networkActivityDidStart; 55 | 56 | - (void)networkActivityDidEnd; 57 | 58 | - (void)updateIndicatorVisibility; 59 | 60 | @end 61 | 62 | 63 | @implementation OPNetworkObserver 64 | 65 | - (void)operationDidStart:(OPOperation *)operation 66 | { 67 | dispatch_async(dispatch_get_main_queue(), ^{ 68 | // Increment the network indicator's "reference count" 69 | [[OPNetworkIndicatorController sharedInstance] networkActivityDidStart]; 70 | }); 71 | } 72 | 73 | - (void)operation:(OPOperation *)operation didProduceOperation:(NSOperation *)newOperation {} 74 | 75 | - (void)operation:(OPOperation *)operation didFinishWithErrors:(NSArray *)errors 76 | { 77 | dispatch_async(dispatch_get_main_queue(), ^{ 78 | // Decrement the network indicator's "reference count". 79 | [[OPNetworkIndicatorController sharedInstance] networkActivityDidEnd]; 80 | }); 81 | } 82 | 83 | @end 84 | 85 | 86 | @implementation OPNetworkIndicatorController 87 | 88 | + (OPNetworkIndicatorController *)sharedInstance 89 | { 90 | static OPNetworkIndicatorController *_sharedInstance = nil; 91 | static dispatch_once_t onceToken; 92 | dispatch_once(&onceToken, ^{ 93 | _sharedInstance = [[OPNetworkIndicatorController alloc] init]; 94 | }); 95 | 96 | return _sharedInstance; 97 | } 98 | 99 | - (instancetype)init 100 | { 101 | self = [super init]; 102 | if (!self) { 103 | return nil; 104 | } 105 | 106 | _activityCount = 0; 107 | 108 | return self; 109 | } 110 | 111 | - (void)networkActivityDidStart 112 | { 113 | NSAssert([NSThread isMainThread], @"Altering network activity indicator state can only be done on the main thread."); 114 | self.activityCount++; 115 | 116 | [self updateIndicatorVisibility]; 117 | } 118 | 119 | - (void)networkActivityDidEnd 120 | { 121 | self.activityCount--; 122 | 123 | [self updateIndicatorVisibility]; 124 | } 125 | 126 | - (void)updateIndicatorVisibility 127 | { 128 | if ([self activityCount] > 0) { 129 | [self showIndicator]; 130 | } else { 131 | /* 132 | To prevent the indicator from flickering on and off, we delay the 133 | hiding of the indicator by one second. This provides the chance 134 | to come in and invalidate the timer before it fires. 135 | */ 136 | OPTimer *timer = [[OPTimer alloc] initWithInterval:1.0f 137 | handler:^{ 138 | [self hideIndicator]; 139 | }]; 140 | [self setVisibilityTimer:timer]; 141 | } 142 | } 143 | 144 | - (void)cancelVisibilityTimer 145 | { 146 | if ([self visibilityTimer]) { 147 | [self.visibilityTimer cancel]; 148 | [self setVisibilityTimer:nil]; 149 | } 150 | } 151 | 152 | - (void)showIndicator 153 | { 154 | [self cancelVisibilityTimer]; 155 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; 156 | } 157 | 158 | - (void)hideIndicator 159 | { 160 | [self cancelVisibilityTimer]; 161 | [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; 162 | } 163 | 164 | @end 165 | 166 | 167 | @implementation OPTimer 168 | 169 | #pragma mark - Public 170 | #pragma mark - 171 | 172 | - (void)cancel 173 | { 174 | [self setCancelled:YES]; 175 | } 176 | 177 | - (void)fire 178 | { 179 | if (![self isCancelled]) { 180 | self.handler(); 181 | } 182 | } 183 | 184 | 185 | #pragma mark - Lifecycle 186 | #pragma mark - 187 | 188 | - (instancetype)initWithInterval:(NSTimeInterval)interval 189 | handler:(dispatch_block_t)handler 190 | { 191 | self = [super init]; 192 | if (!self) { 193 | return nil; 194 | } 195 | 196 | _handler = [handler copy]; 197 | 198 | dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)); 199 | 200 | __weak __typeof__(self) weakSelf = self; 201 | dispatch_after(when, dispatch_get_main_queue(), ^{ 202 | __typeof__(self) strongSelf = weakSelf; 203 | [strongSelf fire]; 204 | }); 205 | 206 | return self; 207 | } 208 | 209 | @end 210 | -------------------------------------------------------------------------------- /Pod/Classes/iOS/Conditions/OPOperationConditionUserNotification.m: -------------------------------------------------------------------------------- 1 | // OPOperationConditionUserNotification.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #if TARGET_OS_IPHONE 23 | 24 | #import "OPOperationConditionUserNotification.h" 25 | #import "OPOperationConditionMutuallyExclusive.h" 26 | 27 | #import "NSError+Operative.h" 28 | #import "UIUserNotificationSettings+Operative.h" 29 | 30 | 31 | NSString * const kCurrentSettings = @"CurrentUserNotificationSettings"; 32 | NSString * const kDesiredSettings = @"DesiredUserNotificationSettings"; 33 | 34 | 35 | #pragma mark - OPOperationConditionUserNotification Private 36 | #pragma mark - 37 | 38 | @interface OPOperationConditionUserNotification() 39 | 40 | @property (strong, nonatomic) UIUserNotificationSettings *settings; 41 | @property (strong, nonatomic) UIApplication *application; 42 | @property (assign, nonatomic) OPOperationConditionUserNotificationBehavior behavior; 43 | 44 | @end 45 | 46 | 47 | #pragma mark - OPUserNotificationPermissionOperation 48 | #pragma mark - 49 | 50 | @interface OPUserNotificationPermissionOperation : OPOperation 51 | 52 | @property (strong, nonatomic) UIUserNotificationSettings *settings; 53 | @property (strong, nonatomic) UIApplication *application; 54 | @property (assign, nonatomic) OPOperationConditionUserNotificationBehavior behavior; 55 | 56 | @end 57 | 58 | 59 | @implementation OPUserNotificationPermissionOperation 60 | 61 | - (instancetype)initWithSettings:(UIUserNotificationSettings *)settings 62 | application:(UIApplication *)application 63 | behavior:(OPOperationConditionUserNotificationBehavior)behavior 64 | { 65 | self = [super init]; 66 | if (!self) { 67 | return nil; 68 | } 69 | 70 | _settings = settings; 71 | _application = application; 72 | _behavior = behavior; 73 | 74 | [self addCondition:[OPOperationConditionMutuallyExclusive alertPresentationExclusivity]]; 75 | 76 | return self; 77 | } 78 | 79 | - (void)execute 80 | { 81 | dispatch_async(dispatch_get_main_queue(), ^{ 82 | UIUserNotificationSettings *currentSettings = [self.application currentUserNotificationSettings]; 83 | UIUserNotificationSettings *settingsToRegister; 84 | 85 | switch ([self behavior]) { 86 | case OPOperationConditionBehaviorMerge: 87 | settingsToRegister = [currentSettings settingsByMerging:[self settings]]; 88 | break; 89 | case OPOperationConditionBehaviorReplace: 90 | default: 91 | settingsToRegister = [self settings]; 92 | break; 93 | } 94 | 95 | [self.application registerUserNotificationSettings:settingsToRegister]; 96 | 97 | [self finish]; 98 | }); 99 | } 100 | 101 | @end 102 | 103 | 104 | #pragma mark - OPOperationConditionUserNotification Implementation 105 | #pragma mark - 106 | 107 | @implementation OPOperationConditionUserNotification 108 | 109 | #pragma mark - Lifecycle 110 | #pragma mark - 111 | 112 | - (instancetype)initWithSettings:(UIUserNotificationSettings *)settings application:(UIApplication *)application 113 | { 114 | return [self initWithSettings:settings application:application behavior:OPOperationConditionBehaviorMerge]; 115 | } 116 | 117 | - (instancetype) initWithSettings:(UIUserNotificationSettings *)settings application:(UIApplication *)application behavior:(OPOperationConditionUserNotificationBehavior)behavior 118 | { 119 | self = [super init]; 120 | if (!self) { 121 | return nil; 122 | } 123 | _settings = settings; 124 | _application = application; 125 | _behavior = behavior; 126 | 127 | return self; 128 | } 129 | 130 | 131 | #pragma mark - OPOperationCondition 132 | #pragma mark - 133 | 134 | - (NSString *)name 135 | { 136 | return @"UserNotification"; 137 | } 138 | 139 | - (BOOL)isMutuallyExclusive 140 | { 141 | return NO; 142 | } 143 | 144 | - (NSOperation *)dependencyForOperation:(OPOperation *)operation 145 | { 146 | return [[OPUserNotificationPermissionOperation alloc] initWithSettings:[self settings] 147 | application:[self application] 148 | behavior:[self behavior]]; 149 | } 150 | 151 | - (void)evaluateConditionForOperation:(OPOperation *)operation 152 | completion:(void (^)(OPOperationConditionResultStatus result, NSError *error))completion 153 | { 154 | // Satisfied until not 155 | OPOperationConditionResultStatus result = OPOperationConditionResultStatusSatisfied; 156 | 157 | NSError *error = nil; 158 | 159 | UIUserNotificationSettings *current = [self.application currentUserNotificationSettings]; 160 | 161 | if ([current containsSettings:[self settings]]) { 162 | // No-op 163 | } else { 164 | NSDictionary *userInfo = @{ 165 | kOPOperationConditionKey : NSStringFromClass([self class]), 166 | kCurrentSettings : current ? : [NSNull null], 167 | kDesiredSettings : [self settings] 168 | }; 169 | error = [NSError errorWithCode:OPOperationErrorCodeConditionFailed userInfo:userInfo]; 170 | result = OPOperationConditionResultStatusFailed; 171 | } 172 | 173 | completion(result, error); 174 | } 175 | 176 | @end 177 | 178 | #endif -------------------------------------------------------------------------------- /Example/Tests/CategoriesTests.m: -------------------------------------------------------------------------------- 1 | // CategoriesTests.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import 23 | 24 | #import 25 | #import 26 | #import 27 | #import 28 | 29 | @interface CategoriesTests : XCTestCase 30 | 31 | @end 32 | 33 | @implementation CategoriesTests 34 | 35 | - (void)setUp { 36 | [super setUp]; 37 | // Put setup code here. This method is called before the invocation of each test method in the class. 38 | } 39 | 40 | - (void)tearDown { 41 | // Put teardown code here. This method is called after the invocation of each test method in the class. 42 | [super tearDown]; 43 | } 44 | 45 | #pragma mark - NSError category 46 | #pragma mark - 47 | 48 | - (void)testCreateErrorWithCodeAndUserInfo { 49 | NSDictionary *userInfo = @{@"test": @(YES)}; 50 | NSError *error = [NSError errorWithCode:1 userInfo:userInfo]; 51 | 52 | XCTAssertEqual(error.code, 1); 53 | XCTAssertEqualObjects(error.userInfo, userInfo); 54 | XCTAssertEqualObjects(error.domain, kOPOperationErrorDomain); 55 | } 56 | 57 | - (void)testCreateErrorWithCode { 58 | NSError *error = [NSError errorWithCode:1]; 59 | 60 | XCTAssertEqual(error.code, 1); 61 | XCTAssertEqualObjects(error.userInfo, @{}); 62 | XCTAssertEqualObjects(error.domain, kOPOperationErrorDomain); 63 | } 64 | 65 | #pragma mark - NSMutableDictionary category 66 | #pragma mark - 67 | 68 | - (void)testCreateDictionaryFromSet { 69 | NSSet *set = [NSSet setWithObjects:@{@"key": @"1", @"value": @"1"}, @{@"key": @"2", @"value": @"2"}, nil]; 70 | 71 | NSMutableDictionary *dict = [NSMutableDictionary sequence:set keyMapper:^(id obj) { 72 | return obj[@"key"]; 73 | }]; 74 | 75 | XCTAssertEqual(dict.allKeys.count, 2); 76 | XCTAssertEqual([[dict[@"1"] allKeys] count], 2); 77 | XCTAssertEqual([[dict[@"2"] allKeys] count], 2); 78 | 79 | XCTAssertEqualObjects(dict[@"1"][@"key"], @"1"); 80 | XCTAssertEqualObjects(dict[@"1"][@"value"], @"1"); 81 | 82 | XCTAssertEqualObjects(dict[@"2"][@"key"], @"2"); 83 | XCTAssertEqualObjects(dict[@"2"][@"value"], @"2"); 84 | } 85 | 86 | - (void)testCreateDictionaryFromArray { 87 | NSArray *array = @[@{@"key": @"1", @"value": @"1"}, @{@"key": @"2", @"value": @"2"}]; 88 | 89 | NSMutableDictionary *dict = [NSMutableDictionary sequence:array keyMapper:^(id obj) { 90 | return obj[@"key"]; 91 | }]; 92 | 93 | XCTAssertEqual(dict.allKeys.count, 2); 94 | XCTAssertEqual([[dict[@"1"] allKeys] count], 2); 95 | XCTAssertEqual([[dict[@"2"] allKeys] count], 2); 96 | 97 | XCTAssertEqualObjects(dict[@"1"][@"key"], @"1"); 98 | XCTAssertEqualObjects(dict[@"1"][@"value"], @"1"); 99 | 100 | XCTAssertEqualObjects(dict[@"2"][@"key"], @"2"); 101 | XCTAssertEqualObjects(dict[@"2"][@"value"], @"2"); 102 | } 103 | 104 | #pragma mark - NSOperation category 105 | #pragma mark - 106 | 107 | - (void)testAddMultipleDependencies { 108 | NSOperation *operation = [[NSOperation alloc] init]; 109 | 110 | NSMutableArray *array = [[NSMutableArray alloc] init]; 111 | for (int i = 0; i < 10; i++) 112 | { 113 | [array addObject:[[NSOperation alloc] init]]; 114 | } 115 | 116 | [operation addDependencies:array]; 117 | 118 | XCTAssertEqual(operation.dependencies.count, 10); 119 | } 120 | 121 | - (void)testAddOriginalCompletionBlock { 122 | XCTestExpectation *expectation = [self expectationWithDescription:@"Should call original completion block"]; 123 | 124 | NSOperation *operation = [[NSOperation alloc] init]; 125 | operation.completionBlock = ^{ 126 | [expectation fulfill]; 127 | }; 128 | 129 | [operation addCompletionBlock:^(void) { 130 | }]; 131 | 132 | operation.completionBlock(); 133 | 134 | [self waitForExpectationsWithTimeout:1 handler:nil]; 135 | } 136 | 137 | - (void)testAddChainedCompletionBlock { 138 | XCTestExpectation *expectation = [self expectationWithDescription:@"Should call chained completion block"]; 139 | 140 | NSOperation *operation = [[NSOperation alloc] init]; 141 | operation.completionBlock = ^{ 142 | 143 | }; 144 | 145 | [operation addCompletionBlock:^(void) { 146 | [expectation fulfill]; 147 | }]; 148 | 149 | operation.completionBlock(); 150 | 151 | [self waitForExpectationsWithTimeout:1 handler:nil]; 152 | } 153 | 154 | #pragma mark - UIUserNotificationSettings category 155 | #pragma mark - 156 | 157 | - (void)testUserNotificationSettings { 158 | UIUserNotificationSettings *settings1; 159 | UIUserNotificationSettings *settings2; 160 | 161 | // All 162 | settings1 = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; 163 | // All minus alert 164 | settings2 = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound) categories:nil]; 165 | 166 | XCTAssertTrue([settings1 containsSettings:settings2]); 167 | XCTAssertFalse([settings2 containsSettings:settings1]); 168 | 169 | // All 170 | settings1 = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; 171 | // All minus sound 172 | settings2 = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert) categories:nil]; 173 | XCTAssertTrue([settings1 containsSettings:settings2]); 174 | XCTAssertFalse([settings2 containsSettings:settings1]); 175 | 176 | // All 177 | settings1 = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; 178 | // All minus Badge 179 | settings2 = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil]; 180 | XCTAssertTrue([settings1 containsSettings:settings2]); 181 | XCTAssertFalse([settings2 containsSettings:settings1]); 182 | } 183 | 184 | @end 185 | -------------------------------------------------------------------------------- /Example/Operative/OPViewController.m: -------------------------------------------------------------------------------- 1 | // OPViewController.m 2 | // Copyright (c) 2015 Tom Wilson 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | 22 | #import "OPViewController.h" 23 | #import 24 | 25 | #import "GroupOperationTest.h" 26 | 27 | @interface OPViewController () 28 | 29 | @property (strong, nonatomic) OPOperationQueue *queue; 30 | 31 | @end 32 | 33 | @implementation OPViewController 34 | 35 | - (void)viewDidLoad 36 | { 37 | [super viewDidLoad]; 38 | // Do any additional setup after loading the view, typically from a nib. 39 | 40 | OPDelayOperation *delay = [[OPDelayOperation alloc] initWithTimeInterval:10.0f]; 41 | [self.queue addOperation:delay]; 42 | 43 | // Alert options - one at a time! 44 | for (NSUInteger i = 0; i < 5; i++) { 45 | OPAlertOperation *operation = [[OPAlertOperation alloc] initWithPresentationContext:self]; 46 | operation.title = [NSString stringWithFormat:@"Alert #%lu", (unsigned long)i]; 47 | [operation addDependency:delay]; 48 | [self.queue addOperation:operation]; 49 | } 50 | 51 | // [delay cancel]; 52 | 53 | // 54 | // Block operations 55 | // 56 | // Background block 57 | OPBlockOperation *background = [[OPBlockOperation alloc] initWithBlock:^(void(^completion)(void)) { 58 | NSLog(@"Background block operation on main thread: %i", [NSThread isMainThread]); 59 | completion(); 60 | }]; 61 | [background addObserver:[[OPBlockObserver alloc] initWithStartHandler:^(OPOperation *operation) { 62 | NSLog(@"Background block operation started!"); 63 | } produceHandler:nil 64 | finishHandler:^(OPOperation *operation, NSArray *errors) { 65 | NSLog(@"Background block operation finished!"); 66 | }]]; 67 | 68 | // Main thread block 69 | OPBlockOperation *mainThread = [[OPBlockOperation alloc] initWithMainQueueBlock:^{ 70 | NSLog(@"Main Thread block operation on main thread: %i", [NSThread isMainThread]); 71 | }]; 72 | [mainThread addObserver:[[OPBlockObserver alloc] initWithStartHandler:^(OPOperation *operation) { 73 | NSLog(@"Main Thread block operation started!"); 74 | } produceHandler:nil 75 | finishHandler:^(OPOperation *operation, NSArray *errors) { 76 | NSLog(@"Main Thread block operation finished!"); 77 | }]]; 78 | 79 | // Start them 80 | [self.queue addOperation:background]; 81 | [self.queue addOperation:mainThread]; 82 | 83 | NSURLSessionConfiguration *sessionConfig = 84 | [NSURLSessionConfiguration defaultSessionConfiguration]; 85 | 86 | // 1 87 | sessionConfig.allowsCellularAccess = YES; 88 | 89 | // 2 90 | [sessionConfig setHTTPAdditionalHeaders: 91 | @{@"Accept": @"application/json"}]; 92 | 93 | // 3 94 | sessionConfig.timeoutIntervalForRequest = 30.0; 95 | sessionConfig.timeoutIntervalForResource = 60.0; 96 | sessionConfig.HTTPMaximumConnectionsPerHost = 1; 97 | 98 | NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig]; 99 | 100 | NSURLSessionTask *sessionTask = [session dataTaskWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"https://api.github.com/repos/elixir-lang/elixir/issues"]] 101 | completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 102 | // NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; 103 | // NSLog(@"%@", dict.description); 104 | }]; 105 | 106 | OPURLSessionTaskOperation *urlOperation = [[OPURLSessionTaskOperation alloc] initWithTask:sessionTask]; 107 | 108 | [urlOperation addObserver:[[OPBlockObserver alloc] initWithStartHandler:^(OPOperation *operation) { 109 | NSLog(@"URL Operation started!"); 110 | } 111 | produceHandler:^(OPOperation *operation, NSOperation *newOperation) { 112 | } finishHandler:^(OPOperation *operation, NSArray *errors) { 113 | NSLog(@"URL Operation finished"); 114 | NSLog(@"%@", sessionTask.response); 115 | }]]; 116 | 117 | [self.queue addOperation:urlOperation]; 118 | 119 | 120 | // Group operation 121 | 122 | GroupOperationTest *groupTest = [[GroupOperationTest alloc] init]; 123 | [groupTest addObserver:[[OPBlockObserver alloc] initWithStartHandler:^(OPOperation *operation) { 124 | NSLog(@"Group operation started"); 125 | } produceHandler:^(OPOperation *operation, NSOperation *newOperation) { 126 | NSLog(@"Group operation produced operation: %@", operation); 127 | } finishHandler:^(OPOperation *operation, NSArray *errors) { 128 | NSLog(@"Group operation completed!"); 129 | }]]; 130 | [self.queue addOperation:groupTest]; 131 | 132 | 133 | 134 | 135 | 136 | // Location Test 137 | OPLocationOperation *locationOperation = [[OPLocationOperation alloc] initWithAccuracy:1000.f 138 | locationHandler:^(CLLocation *location) { 139 | NSLog(@"Got location: %f, %f", location.coordinate.latitude, location.coordinate.longitude); 140 | }]; 141 | 142 | [self.queue addOperation:locationOperation]; 143 | } 144 | 145 | - (void)didReceiveMemoryWarning 146 | { 147 | [super didReceiveMemoryWarning]; 148 | // Dispose of any resources that can be recreated. 149 | } 150 | 151 | #pragma mark - Properties 152 | 153 | - (OPOperationQueue *) queue 154 | { 155 | if (!_queue) 156 | { 157 | _queue = [[OPOperationQueue alloc] init]; 158 | _queue.maxConcurrentOperationCount = 5; 159 | } 160 | return _queue; 161 | 162 | } 163 | @end 164 | --------------------------------------------------------------------------------