├── .gitignore ├── .travis.yml ├── Framework ├── Info.plist └── YYDispatchQueuePool.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ └── contents.xcworkspacedata │ └── xcshareddata │ └── xcschemes │ └── YYDispatchQueuePool.xcscheme ├── LICENSE ├── README.md ├── Snapshots ├── CTRunDraw.png └── CTRunDrawLock.png ├── YYDispatchQueuePool.podspec └── YYDispatchQueuePool ├── YYDispatchQueuePool.h └── YYDispatchQueuePool.m /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | # 6 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 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 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcuserstate 27 | *.xcscmblueprint 28 | 29 | ## Obj-C/Swift specific 30 | *.hmap 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | # CocoaPods 36 | # 37 | # We recommend against adding the Pods directory to your .gitignore. However 38 | # you should judge for yourself, the pros and cons are mentioned at: 39 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 40 | # 41 | # Pods/ 42 | 43 | # Carthage 44 | # 45 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 46 | # Carthage/Checkouts 47 | 48 | Carthage/Build 49 | 50 | # fastlane 51 | # 52 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 53 | # screenshots whenever they are needed. 54 | # For more information about the recommended setup visit: 55 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 56 | 57 | fastlane/report.xml 58 | fastlane/Preview.html 59 | fastlane/screenshots 60 | fastlane/test_output 61 | 62 | # Code Injection 63 | # 64 | # After new code Injection tools there's a generated folder /iOSInjectionProject 65 | # https://github.com/johnno1962/injectionforxcode 66 | 67 | iOSInjectionProject/ 68 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode8 3 | xcode_project: Framework/YYDispatchQueuePool.xcodeproj 4 | xcode_scheme: YYDispatchQueuePool 5 | 6 | before_install: 7 | - env 8 | - xcodebuild -version 9 | - xcodebuild -showsdks 10 | - xcpretty --version 11 | 12 | script: 13 | - set -o pipefail 14 | - xcodebuild clean build -project "$TRAVIS_XCODE_PROJECT" -scheme "$TRAVIS_XCODE_SCHEME" | xcpretty 15 | -------------------------------------------------------------------------------- /Framework/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Framework/YYDispatchQueuePool.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D9A995131F0561E40062698B /* YYDispatchQueuePool.h in Headers */ = {isa = PBXBuildFile; fileRef = D9A995111F0561E40062698B /* YYDispatchQueuePool.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | D9A995141F0561E40062698B /* YYDispatchQueuePool.m in Sources */ = {isa = PBXBuildFile; fileRef = D9A995121F0561E40062698B /* YYDispatchQueuePool.m */; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXFileReference section */ 15 | D9A995051F0561A10062698B /* YYDispatchQueuePool.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YYDispatchQueuePool.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 16 | D9A995091F0561A10062698B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../Framework/Info.plist; sourceTree = ""; }; 17 | D9A995111F0561E40062698B /* YYDispatchQueuePool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYDispatchQueuePool.h; sourceTree = ""; }; 18 | D9A995121F0561E40062698B /* YYDispatchQueuePool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYDispatchQueuePool.m; sourceTree = ""; }; 19 | /* End PBXFileReference section */ 20 | 21 | /* Begin PBXFrameworksBuildPhase section */ 22 | D9A995011F0561A10062698B /* Frameworks */ = { 23 | isa = PBXFrameworksBuildPhase; 24 | buildActionMask = 2147483647; 25 | files = ( 26 | ); 27 | runOnlyForDeploymentPostprocessing = 0; 28 | }; 29 | /* End PBXFrameworksBuildPhase section */ 30 | 31 | /* Begin PBXGroup section */ 32 | D9A994FB1F0561A10062698B = { 33 | isa = PBXGroup; 34 | children = ( 35 | D9A995101F0561E40062698B /* YYDispatchQueuePool */, 36 | D9A995061F0561A10062698B /* Products */, 37 | ); 38 | sourceTree = ""; 39 | }; 40 | D9A995061F0561A10062698B /* Products */ = { 41 | isa = PBXGroup; 42 | children = ( 43 | D9A995051F0561A10062698B /* YYDispatchQueuePool.framework */, 44 | ); 45 | name = Products; 46 | sourceTree = ""; 47 | }; 48 | D9A995101F0561E40062698B /* YYDispatchQueuePool */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | D9A995111F0561E40062698B /* YYDispatchQueuePool.h */, 52 | D9A995121F0561E40062698B /* YYDispatchQueuePool.m */, 53 | D9A995091F0561A10062698B /* Info.plist */, 54 | ); 55 | name = YYDispatchQueuePool; 56 | path = ../YYDispatchQueuePool; 57 | sourceTree = ""; 58 | }; 59 | /* End PBXGroup section */ 60 | 61 | /* Begin PBXHeadersBuildPhase section */ 62 | D9A995021F0561A10062698B /* Headers */ = { 63 | isa = PBXHeadersBuildPhase; 64 | buildActionMask = 2147483647; 65 | files = ( 66 | D9A995131F0561E40062698B /* YYDispatchQueuePool.h in Headers */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXHeadersBuildPhase section */ 71 | 72 | /* Begin PBXNativeTarget section */ 73 | D9A995041F0561A10062698B /* YYDispatchQueuePool */ = { 74 | isa = PBXNativeTarget; 75 | buildConfigurationList = D9A9950D1F0561A10062698B /* Build configuration list for PBXNativeTarget "YYDispatchQueuePool" */; 76 | buildPhases = ( 77 | D9A995001F0561A10062698B /* Sources */, 78 | D9A995011F0561A10062698B /* Frameworks */, 79 | D9A995021F0561A10062698B /* Headers */, 80 | D9A995031F0561A10062698B /* Resources */, 81 | ); 82 | buildRules = ( 83 | ); 84 | dependencies = ( 85 | ); 86 | name = YYDispatchQueuePool; 87 | productName = YYDispatchQueuePool; 88 | productReference = D9A995051F0561A10062698B /* YYDispatchQueuePool.framework */; 89 | productType = "com.apple.product-type.framework"; 90 | }; 91 | /* End PBXNativeTarget section */ 92 | 93 | /* Begin PBXProject section */ 94 | D9A994FC1F0561A10062698B /* Project object */ = { 95 | isa = PBXProject; 96 | attributes = { 97 | LastUpgradeCheck = 0900; 98 | ORGANIZATIONNAME = ibireme; 99 | TargetAttributes = { 100 | D9A995041F0561A10062698B = { 101 | CreatedOnToolsVersion = 9.0; 102 | }; 103 | }; 104 | }; 105 | buildConfigurationList = D9A994FF1F0561A10062698B /* Build configuration list for PBXProject "YYDispatchQueuePool" */; 106 | compatibilityVersion = "Xcode 8.0"; 107 | developmentRegion = en; 108 | hasScannedForEncodings = 0; 109 | knownRegions = ( 110 | en, 111 | ); 112 | mainGroup = D9A994FB1F0561A10062698B; 113 | productRefGroup = D9A995061F0561A10062698B /* Products */; 114 | projectDirPath = ""; 115 | projectRoot = ""; 116 | targets = ( 117 | D9A995041F0561A10062698B /* YYDispatchQueuePool */, 118 | ); 119 | }; 120 | /* End PBXProject section */ 121 | 122 | /* Begin PBXResourcesBuildPhase section */ 123 | D9A995031F0561A10062698B /* Resources */ = { 124 | isa = PBXResourcesBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXResourcesBuildPhase section */ 131 | 132 | /* Begin PBXSourcesBuildPhase section */ 133 | D9A995001F0561A10062698B /* Sources */ = { 134 | isa = PBXSourcesBuildPhase; 135 | buildActionMask = 2147483647; 136 | files = ( 137 | D9A995141F0561E40062698B /* YYDispatchQueuePool.m in Sources */, 138 | ); 139 | runOnlyForDeploymentPostprocessing = 0; 140 | }; 141 | /* End PBXSourcesBuildPhase section */ 142 | 143 | /* Begin XCBuildConfiguration section */ 144 | D9A9950B1F0561A10062698B /* Debug */ = { 145 | isa = XCBuildConfiguration; 146 | buildSettings = { 147 | ALWAYS_SEARCH_USER_PATHS = NO; 148 | CLANG_ANALYZER_NONNULL = YES; 149 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 150 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 151 | CLANG_CXX_LIBRARY = "libc++"; 152 | CLANG_ENABLE_MODULES = YES; 153 | CLANG_ENABLE_OBJC_ARC = YES; 154 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 155 | CLANG_WARN_BOOL_CONVERSION = YES; 156 | CLANG_WARN_COMMA = YES; 157 | CLANG_WARN_CONSTANT_CONVERSION = YES; 158 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 159 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 160 | CLANG_WARN_EMPTY_BODY = YES; 161 | CLANG_WARN_ENUM_CONVERSION = YES; 162 | CLANG_WARN_INFINITE_RECURSION = YES; 163 | CLANG_WARN_INT_CONVERSION = YES; 164 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 165 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 166 | CLANG_WARN_STRICT_PROTOTYPES = YES; 167 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 168 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 169 | CLANG_WARN_UNREACHABLE_CODE = YES; 170 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 171 | CODE_SIGN_IDENTITY = "iPhone Developer"; 172 | COPY_PHASE_STRIP = NO; 173 | CURRENT_PROJECT_VERSION = 1; 174 | DEBUG_INFORMATION_FORMAT = dwarf; 175 | ENABLE_STRICT_OBJC_MSGSEND = YES; 176 | ENABLE_TESTABILITY = YES; 177 | GCC_C_LANGUAGE_STANDARD = gnu11; 178 | GCC_DYNAMIC_NO_PIC = NO; 179 | GCC_NO_COMMON_BLOCKS = YES; 180 | GCC_OPTIMIZATION_LEVEL = 0; 181 | GCC_PREPROCESSOR_DEFINITIONS = ( 182 | "DEBUG=1", 183 | "$(inherited)", 184 | ); 185 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 186 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 187 | GCC_WARN_UNDECLARED_SELECTOR = YES; 188 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 189 | GCC_WARN_UNUSED_FUNCTION = YES; 190 | GCC_WARN_UNUSED_VARIABLE = YES; 191 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 192 | MTL_ENABLE_DEBUG_INFO = YES; 193 | ONLY_ACTIVE_ARCH = YES; 194 | SDKROOT = iphoneos; 195 | VERSIONING_SYSTEM = "apple-generic"; 196 | VERSION_INFO_PREFIX = ""; 197 | }; 198 | name = Debug; 199 | }; 200 | D9A9950C1F0561A10062698B /* Release */ = { 201 | isa = XCBuildConfiguration; 202 | buildSettings = { 203 | ALWAYS_SEARCH_USER_PATHS = NO; 204 | CLANG_ANALYZER_NONNULL = YES; 205 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 206 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 207 | CLANG_CXX_LIBRARY = "libc++"; 208 | CLANG_ENABLE_MODULES = YES; 209 | CLANG_ENABLE_OBJC_ARC = YES; 210 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 211 | CLANG_WARN_BOOL_CONVERSION = YES; 212 | CLANG_WARN_COMMA = YES; 213 | CLANG_WARN_CONSTANT_CONVERSION = YES; 214 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 215 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 216 | CLANG_WARN_EMPTY_BODY = YES; 217 | CLANG_WARN_ENUM_CONVERSION = YES; 218 | CLANG_WARN_INFINITE_RECURSION = YES; 219 | CLANG_WARN_INT_CONVERSION = YES; 220 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 221 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 222 | CLANG_WARN_STRICT_PROTOTYPES = YES; 223 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 224 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 225 | CLANG_WARN_UNREACHABLE_CODE = YES; 226 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 227 | CODE_SIGN_IDENTITY = "iPhone Developer"; 228 | COPY_PHASE_STRIP = NO; 229 | CURRENT_PROJECT_VERSION = 1; 230 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 231 | ENABLE_NS_ASSERTIONS = NO; 232 | ENABLE_STRICT_OBJC_MSGSEND = YES; 233 | GCC_C_LANGUAGE_STANDARD = gnu11; 234 | GCC_NO_COMMON_BLOCKS = YES; 235 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 236 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 237 | GCC_WARN_UNDECLARED_SELECTOR = YES; 238 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 239 | GCC_WARN_UNUSED_FUNCTION = YES; 240 | GCC_WARN_UNUSED_VARIABLE = YES; 241 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 242 | MTL_ENABLE_DEBUG_INFO = NO; 243 | SDKROOT = iphoneos; 244 | VALIDATE_PRODUCT = YES; 245 | VERSIONING_SYSTEM = "apple-generic"; 246 | VERSION_INFO_PREFIX = ""; 247 | }; 248 | name = Release; 249 | }; 250 | D9A9950E1F0561A10062698B /* Debug */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | APPLICATION_EXTENSION_API_ONLY = YES; 254 | CODE_SIGN_IDENTITY = ""; 255 | DEFINES_MODULE = YES; 256 | DYLIB_COMPATIBILITY_VERSION = 1; 257 | DYLIB_CURRENT_VERSION = 1; 258 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 259 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 260 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 261 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 262 | PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYDispatchQueuePool; 263 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 264 | SKIP_INSTALL = YES; 265 | TARGETED_DEVICE_FAMILY = "1,2"; 266 | }; 267 | name = Debug; 268 | }; 269 | D9A9950F1F0561A10062698B /* Release */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | APPLICATION_EXTENSION_API_ONLY = YES; 273 | CODE_SIGN_IDENTITY = ""; 274 | DEFINES_MODULE = YES; 275 | DYLIB_COMPATIBILITY_VERSION = 1; 276 | DYLIB_CURRENT_VERSION = 1; 277 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 278 | INFOPLIST_FILE = "$(SRCROOT)/Info.plist"; 279 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 280 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 281 | PRODUCT_BUNDLE_IDENTIFIER = com.ibireme.YYDispatchQueuePool; 282 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 283 | SKIP_INSTALL = YES; 284 | TARGETED_DEVICE_FAMILY = "1,2"; 285 | }; 286 | name = Release; 287 | }; 288 | /* End XCBuildConfiguration section */ 289 | 290 | /* Begin XCConfigurationList section */ 291 | D9A994FF1F0561A10062698B /* Build configuration list for PBXProject "YYDispatchQueuePool" */ = { 292 | isa = XCConfigurationList; 293 | buildConfigurations = ( 294 | D9A9950B1F0561A10062698B /* Debug */, 295 | D9A9950C1F0561A10062698B /* Release */, 296 | ); 297 | defaultConfigurationIsVisible = 0; 298 | defaultConfigurationName = Release; 299 | }; 300 | D9A9950D1F0561A10062698B /* Build configuration list for PBXNativeTarget "YYDispatchQueuePool" */ = { 301 | isa = XCConfigurationList; 302 | buildConfigurations = ( 303 | D9A9950E1F0561A10062698B /* Debug */, 304 | D9A9950F1F0561A10062698B /* Release */, 305 | ); 306 | defaultConfigurationIsVisible = 0; 307 | defaultConfigurationName = Release; 308 | }; 309 | /* End XCConfigurationList section */ 310 | }; 311 | rootObject = D9A994FC1F0561A10062698B /* Project object */; 312 | } 313 | -------------------------------------------------------------------------------- /Framework/YYDispatchQueuePool.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Framework/YYDispatchQueuePool.xcodeproj/xcshareddata/xcschemes/YYDispatchQueuePool.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 ibireme 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | YYDispatchQueuePool 2 | ============== 3 | 4 | [![License MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/ibireme/YYDispatchQueuePool/master/LICENSE)  5 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)  6 | [![CocoaPods](http://img.shields.io/cocoapods/v/YYDispatchQueuePool.svg?style=flat)](http://cocoapods.org/pods/YYDispatchQueuePool)  7 | [![CocoaPods](http://img.shields.io/cocoapods/p/YYDispatchQueuePool.svg?style=flat)](http://cocoadocs.org/docsets/YYDispatchQueuePool)  8 | [![Support](https://img.shields.io/badge/support-iOS%206%2B%20-blue.svg?style=flat)](https://www.apple.com/nl/ios/)  9 | [![Build Status](https://travis-ci.org/ibireme/YYDispatchQueuePool.svg?branch=master)](https://travis-ci.org/ibireme/YYDispatchQueuePool) 10 | 11 | iOS utility class to manage global dispatch queue.
12 | (It's a component of [YYKit](https://github.com/ibireme/YYKit)) 13 | 14 | When use a concurrent queue to execute lots of blocks, I met this problem in some situation: 15 | 16 | 17 | 18 | 19 | When some block is locked, the concurrent queue may create lots of thread and may block the main thread. 20 | Use a global serial queue pool to avoid it. 21 | 22 | Usage 23 | ============== 24 | ```objc 25 | // Get a serial queue from global queue pool 26 | dispatch_queue_t queue = YYDispatchQueueGetForQOS(NSQualityOfServiceUtility); 27 | 28 | // Create a serial queue pool 29 | YYDispatchQueuePool *pool = [[YYDispatchQueuePool alloc] initWithName:@"file.read" queueCount:5 qos:NSQualityOfServiceBackground]; 30 | dispatch_queue_t queue = [pool queue]; 31 | ``` 32 | 33 | Installation 34 | ============== 35 | 36 | ### CocoaPods 37 | 38 | 1. Add `pod 'YYDispatchQueuePool'` to your Podfile. 39 | 2. Run `pod install` or `pod update`. 40 | 3. Import \. 41 | 42 | 43 | ### Carthage 44 | 45 | 1. Add `github "ibireme/YYDispatchQueuePool"` to your Cartfile. 46 | 2. Run `carthage update --platform ios` and add the framework to your project. 47 | 3. Import \. 48 | 49 | 50 | ### Manually 51 | 52 | 1. Download all the files in the YYDispatchQueuePool subdirectory. 53 | 2. Add the source files to your Xcode project. 54 | 3. Import `YYDispatchQueuePool.h`. 55 | 56 | 57 | Documentation 58 | ============== 59 | Full API documentation is available on [CocoaDocs](http://cocoadocs.org/docsets/YYDispatchQueuePool/).
60 | You can also install documentation locally using [appledoc](https://github.com/tomaz/appledoc). 61 | 62 | 63 | Requirements 64 | ============== 65 | This library requires `iOS 6.0+` and `Xcode 8.0+`. 66 | 67 | 68 | License 69 | ============== 70 | YYDispatchQueuePool is provided under the MIT license. See LICENSE file for details. 71 | 72 | 73 | 74 |

75 | --- 76 | 中文介绍 77 | ============== 78 | iOS 全局并发队列管理工具。
79 | (该项目是 [YYKit](https://github.com/ibireme/YYKit) 组件之一) 80 | 81 | 当用 concurrent queue 来执行大量 block 时,有时会遇到下面这种情况: 82 | 83 | 84 | 85 | 86 | 当某个 block 所在线程被锁住时,concurrent queue 会创建大量线程以至于占用了过多资源而影响到主线程。这里可以用一个全局的 serial queue pool 来尽量控制全局线程数。 87 | 88 | 用法 89 | ============== 90 | ```objc 91 | // 从全局的 queue pool 中获取一个 queue 92 | dispatch_queue_t queue = YYDispatchQueueGetForQOS(NSQualityOfServiceUtility); 93 | 94 | // 创建一个新的 serial queue pool 95 | YYDispatchQueuePool *pool = [[YYDispatchQueuePool alloc] initWithName:@"file.read" queueCount:5 qos:NSQualityOfServiceBackground]; 96 | dispatch_queue_t queue = [pool queue]; 97 | ``` 98 | 99 | 安装 100 | ============== 101 | 102 | ### CocoaPods 103 | 104 | 1. 在 Podfile 中添加 `pod 'YYDispatchQueuePool'`。 105 | 2. 执行 `pod install` 或 `pod update`。 106 | 3. 导入 \。 107 | 108 | 109 | ### Carthage 110 | 111 | 1. 在 Cartfile 中添加 `github "ibireme/YYDispatchQueuePool"`。 112 | 2. 执行 `carthage update --platform ios` 并将生成的 framework 添加到你的工程。 113 | 3. 导入 \。 114 | 115 | 116 | ### 手动安装 117 | 118 | 1. 下载 YYDispatchQueuePool 文件夹内的所有内容。 119 | 2. 将 YYDispatchQueuePool 内的源文件添加(拖放)到你的工程。 120 | 3. 导入 `YYDispatchQueuePool.h`。 121 | 122 | 123 | 文档 124 | ============== 125 | 你可以在 [CocoaDocs](http://cocoadocs.org/docsets/YYDispatchQueuePool/) 查看在线 API 文档,也可以用 [appledoc](https://github.com/tomaz/appledoc) 本地生成文档。 126 | 127 | 128 | 系统要求 129 | ============== 130 | 该项目最低支持 `iOS 6.0` 和 `Xcode 8.0`。 131 | 132 | 133 | 许可证 134 | ============== 135 | YYDispatchQueuePool 使用 MIT 许可证,详情见 LICENSE 文件。 136 | 137 | 138 | 相关文章 139 | ============== 140 | [iOS 保持界面流畅的技巧 141 | ](https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/) 142 | 143 | -------------------------------------------------------------------------------- /Snapshots/CTRunDraw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYDispatchQueuePool/0ac83a856484b21f97aebf2d662caa1f1fa6fcd1/Snapshots/CTRunDraw.png -------------------------------------------------------------------------------- /Snapshots/CTRunDrawLock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ibireme/YYDispatchQueuePool/0ac83a856484b21f97aebf2d662caa1f1fa6fcd1/Snapshots/CTRunDrawLock.png -------------------------------------------------------------------------------- /YYDispatchQueuePool.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'YYDispatchQueuePool' 3 | s.summary = 'iOS utility class to manage global dispatch queue.' 4 | s.version = '1.0' 5 | s.license = { :type => 'MIT', :file => 'LICENSE' } 6 | s.authors = { 'ibireme' => 'ibireme@gmail.com' } 7 | s.social_media_url = 'http://blog.ibireme.com' 8 | s.homepage = 'https://github.com/ibireme/YYDispatchQueuePool' 9 | s.platform = :ios, '6.0' 10 | s.ios.deployment_target = '6.0' 11 | s.source = { :git => 'https://github.com/ibireme/YYDispatchQueuePool.git', :tag => s.version.to_s } 12 | 13 | s.requires_arc = true 14 | s.source_files = 'YYDispatchQueuePool/*.{h,m}' 15 | s.public_header_files = 'YYDispatchQueuePool/*.{h}' 16 | 17 | s.frameworks = 'UIKit' 18 | 19 | end 20 | -------------------------------------------------------------------------------- /YYDispatchQueuePool/YYDispatchQueuePool.h: -------------------------------------------------------------------------------- 1 | // 2 | // YYDispatchQueueManager.h 3 | // YYKit 4 | // 5 | // Created by ibireme on 15/7/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import 13 | 14 | #if __has_include() 15 | FOUNDATION_EXPORT double YYDispatchQueuePoolVersionNumber; 16 | FOUNDATION_EXPORT const unsigned char YYDispatchQueuePoolVersionString[]; 17 | #endif 18 | 19 | #ifndef YYDispatchQueuePool_h 20 | #define YYDispatchQueuePool_h 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | /** 25 | A dispatch queue pool holds multiple serial queues. 26 | Use this class to control queue's thread count (instead of concurrent queue). 27 | */ 28 | @interface YYDispatchQueuePool : NSObject 29 | - (instancetype)init UNAVAILABLE_ATTRIBUTE; 30 | + (instancetype)new UNAVAILABLE_ATTRIBUTE; 31 | 32 | /** 33 | Creates and returns a dispatch queue pool. 34 | @param name The name of the pool. 35 | @param queueCount Maxmium queue count, should in range (1, 32). 36 | @param qos Queue quality of service (QOS). 37 | @return A new pool, or nil if an error occurs. 38 | */ 39 | - (instancetype)initWithName:(nullable NSString *)name queueCount:(NSUInteger)queueCount qos:(NSQualityOfService)qos; 40 | 41 | /// Pool's name. 42 | @property (nullable, nonatomic, readonly) NSString *name; 43 | 44 | /// Get a serial queue from pool. 45 | - (dispatch_queue_t)queue; 46 | 47 | + (instancetype)defaultPoolForQOS:(NSQualityOfService)qos; 48 | 49 | @end 50 | 51 | /// Get a serial queue from global queue pool with a specified qos. 52 | extern dispatch_queue_t YYDispatchQueueGetForQOS(NSQualityOfService qos); 53 | 54 | NS_ASSUME_NONNULL_END 55 | 56 | #endif -------------------------------------------------------------------------------- /YYDispatchQueuePool/YYDispatchQueuePool.m: -------------------------------------------------------------------------------- 1 | // 2 | // YYDispatchQueueManager.m 3 | // YYKit 4 | // 5 | // Created by ibireme on 15/7/18. 6 | // Copyright (c) 2015 ibireme. 7 | // 8 | // This source code is licensed under the MIT-style license found in the 9 | // LICENSE file in the root directory of this source tree. 10 | // 11 | 12 | #import "YYDispatchQueuePool.h" 13 | #import 14 | #import 15 | 16 | #define MAX_QUEUE_COUNT 32 17 | 18 | static inline dispatch_queue_priority_t NSQualityOfServiceToDispatchPriority(NSQualityOfService qos) { 19 | switch (qos) { 20 | case NSQualityOfServiceUserInteractive: return DISPATCH_QUEUE_PRIORITY_HIGH; 21 | case NSQualityOfServiceUserInitiated: return DISPATCH_QUEUE_PRIORITY_HIGH; 22 | case NSQualityOfServiceUtility: return DISPATCH_QUEUE_PRIORITY_LOW; 23 | case NSQualityOfServiceBackground: return DISPATCH_QUEUE_PRIORITY_BACKGROUND; 24 | case NSQualityOfServiceDefault: return DISPATCH_QUEUE_PRIORITY_DEFAULT; 25 | default: return DISPATCH_QUEUE_PRIORITY_DEFAULT; 26 | } 27 | } 28 | 29 | static inline qos_class_t NSQualityOfServiceToQOSClass(NSQualityOfService qos) { 30 | switch (qos) { 31 | case NSQualityOfServiceUserInteractive: return QOS_CLASS_USER_INTERACTIVE; 32 | case NSQualityOfServiceUserInitiated: return QOS_CLASS_USER_INITIATED; 33 | case NSQualityOfServiceUtility: return QOS_CLASS_UTILITY; 34 | case NSQualityOfServiceBackground: return QOS_CLASS_BACKGROUND; 35 | case NSQualityOfServiceDefault: return QOS_CLASS_DEFAULT; 36 | default: return QOS_CLASS_UNSPECIFIED; 37 | } 38 | } 39 | 40 | typedef struct { 41 | const char *name; 42 | void **queues; 43 | uint32_t queueCount; 44 | int32_t counter; 45 | } YYDispatchContext; 46 | 47 | static YYDispatchContext *YYDispatchContextCreate(const char *name, 48 | uint32_t queueCount, 49 | NSQualityOfService qos) { 50 | YYDispatchContext *context = calloc(1, sizeof(YYDispatchContext)); 51 | if (!context) return NULL; 52 | context->queues = calloc(queueCount, sizeof(void *)); 53 | if (!context->queues) { 54 | free(context); 55 | return NULL; 56 | } 57 | if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) { 58 | dispatch_qos_class_t qosClass = NSQualityOfServiceToQOSClass(qos); 59 | for (NSUInteger i = 0; i < queueCount; i++) { 60 | dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, qosClass, 0); 61 | dispatch_queue_t queue = dispatch_queue_create(name, attr); 62 | context->queues[i] = (__bridge_retained void *)(queue); 63 | } 64 | } else { 65 | long identifier = NSQualityOfServiceToDispatchPriority(qos); 66 | for (NSUInteger i = 0; i < queueCount; i++) { 67 | dispatch_queue_t queue = dispatch_queue_create(name, DISPATCH_QUEUE_SERIAL); 68 | dispatch_set_target_queue(queue, dispatch_get_global_queue(identifier, 0)); 69 | context->queues[i] = (__bridge_retained void *)(queue); 70 | } 71 | } 72 | context->queueCount = queueCount; 73 | if (name) { 74 | context->name = strdup(name); 75 | } 76 | return context; 77 | } 78 | 79 | static void YYDispatchContextRelease(YYDispatchContext *context) { 80 | if (!context) return; 81 | if (context->queues) { 82 | for (NSUInteger i = 0; i < context->queueCount; i++) { 83 | void *queuePointer = context->queues[i]; 84 | dispatch_queue_t queue = (__bridge_transfer dispatch_queue_t)(queuePointer); 85 | const char *name = dispatch_queue_get_label(queue); 86 | if (name) strlen(name); 87 | queue = nil; 88 | } 89 | free(context->queues); 90 | context->queues = NULL; 91 | } 92 | if (context->name) free((void *)context->name); 93 | free(context); 94 | } 95 | 96 | static dispatch_queue_t YYDispatchContextGetQueue(YYDispatchContext *context) { 97 | uint32_t counter = (uint32_t)OSAtomicIncrement32(&context->counter); 98 | void *queue = context->queues[counter % context->queueCount]; 99 | return (__bridge dispatch_queue_t)(queue); 100 | } 101 | 102 | 103 | static YYDispatchContext *YYDispatchContextGetForQOS(NSQualityOfService qos) { 104 | static YYDispatchContext *context[5] = {0}; 105 | switch (qos) { 106 | case NSQualityOfServiceUserInteractive: { 107 | static dispatch_once_t onceToken; 108 | dispatch_once(&onceToken, ^{ 109 | int count = (int)[NSProcessInfo processInfo].activeProcessorCount; 110 | count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count; 111 | context[0] = YYDispatchContextCreate("com.ibireme.yykit.user-interactive", count, qos); 112 | }); 113 | return context[0]; 114 | } break; 115 | case NSQualityOfServiceUserInitiated: { 116 | static dispatch_once_t onceToken; 117 | dispatch_once(&onceToken, ^{ 118 | int count = (int)[NSProcessInfo processInfo].activeProcessorCount; 119 | count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count; 120 | context[1] = YYDispatchContextCreate("com.ibireme.yykit.user-initiated", count, qos); 121 | }); 122 | return context[1]; 123 | } break; 124 | case NSQualityOfServiceUtility: { 125 | static dispatch_once_t onceToken; 126 | dispatch_once(&onceToken, ^{ 127 | int count = (int)[NSProcessInfo processInfo].activeProcessorCount; 128 | count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count; 129 | context[2] = YYDispatchContextCreate("com.ibireme.yykit.utility", count, qos); 130 | }); 131 | return context[2]; 132 | } break; 133 | case NSQualityOfServiceBackground: { 134 | static dispatch_once_t onceToken; 135 | dispatch_once(&onceToken, ^{ 136 | int count = (int)[NSProcessInfo processInfo].activeProcessorCount; 137 | count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count; 138 | context[3] = YYDispatchContextCreate("com.ibireme.yykit.background", count, qos); 139 | }); 140 | return context[3]; 141 | } break; 142 | case NSQualityOfServiceDefault: 143 | default: { 144 | static dispatch_once_t onceToken; 145 | dispatch_once(&onceToken, ^{ 146 | int count = (int)[NSProcessInfo processInfo].activeProcessorCount; 147 | count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count; 148 | context[4] = YYDispatchContextCreate("com.ibireme.yykit.default", count, qos); 149 | }); 150 | return context[4]; 151 | } break; 152 | } 153 | } 154 | 155 | 156 | @implementation YYDispatchQueuePool { 157 | @public 158 | YYDispatchContext *_context; 159 | } 160 | 161 | - (void)dealloc { 162 | if (_context) { 163 | YYDispatchContextRelease(_context); 164 | _context = NULL; 165 | } 166 | } 167 | 168 | - (instancetype)initWithContext:(YYDispatchContext *)context { 169 | self = [super init]; 170 | if (!context) return nil; 171 | self->_context = context; 172 | _name = context->name ? [NSString stringWithUTF8String:context->name] : nil; 173 | return self; 174 | } 175 | 176 | - (instancetype)initWithName:(NSString *)name queueCount:(NSUInteger)queueCount qos:(NSQualityOfService)qos { 177 | if (queueCount == 0 || queueCount > MAX_QUEUE_COUNT) return nil; 178 | self = [super init]; 179 | _context = YYDispatchContextCreate(name.UTF8String, (uint32_t)queueCount, qos); 180 | if (!_context) return nil; 181 | _name = name; 182 | return self; 183 | } 184 | 185 | - (dispatch_queue_t)queue { 186 | return YYDispatchContextGetQueue(_context); 187 | } 188 | 189 | + (instancetype)defaultPoolForQOS:(NSQualityOfService)qos { 190 | switch (qos) { 191 | case NSQualityOfServiceUserInteractive: { 192 | static YYDispatchQueuePool *pool; 193 | static dispatch_once_t onceToken; 194 | dispatch_once(&onceToken, ^{ 195 | pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)]; 196 | }); 197 | return pool; 198 | } break; 199 | case NSQualityOfServiceUserInitiated: { 200 | static YYDispatchQueuePool *pool; 201 | static dispatch_once_t onceToken; 202 | dispatch_once(&onceToken, ^{ 203 | pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)]; 204 | }); 205 | return pool; 206 | } break; 207 | case NSQualityOfServiceUtility: { 208 | static YYDispatchQueuePool *pool; 209 | static dispatch_once_t onceToken; 210 | dispatch_once(&onceToken, ^{ 211 | pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)]; 212 | }); 213 | return pool; 214 | } break; 215 | case NSQualityOfServiceBackground: { 216 | static YYDispatchQueuePool *pool; 217 | static dispatch_once_t onceToken; 218 | dispatch_once(&onceToken, ^{ 219 | pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(qos)]; 220 | }); 221 | return pool; 222 | } break; 223 | case NSQualityOfServiceDefault: 224 | default: { 225 | static YYDispatchQueuePool *pool; 226 | static dispatch_once_t onceToken; 227 | dispatch_once(&onceToken, ^{ 228 | pool = [[YYDispatchQueuePool alloc] initWithContext:YYDispatchContextGetForQOS(NSQualityOfServiceDefault)]; 229 | }); 230 | return pool; 231 | } break; 232 | } 233 | } 234 | 235 | @end 236 | 237 | dispatch_queue_t YYDispatchQueueGetForQOS(NSQualityOfService qos) { 238 | return YYDispatchContextGetQueue(YYDispatchContextGetForQOS(qos)); 239 | } 240 | --------------------------------------------------------------------------------