├── .gitignore ├── Example ├── 26295020, 26294823 - Action Sheet Presentation │ ├── ActionSheetPresentationIssue.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ ├── Resources │ │ ├── Base.lproj │ │ │ └── LaunchScreen.xib │ │ ├── Images.xcassets │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ └── Info.plist │ └── Source │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── NewerWebViewController.h │ │ ├── NewerWebViewController.m │ │ ├── TextViewController.h │ │ ├── TextViewController.m │ │ ├── WebViewController.h │ │ ├── WebViewController.m │ │ ├── Workaround.h │ │ ├── Workaround.mm │ │ └── main.m └── 26954460 - UIImageWithDataMultithreaded │ ├── UIImageWithDataMultithreaded.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── UIImageWithDataMultithreaded │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── ViewController.h │ ├── ViewController.m │ ├── main.m │ └── meme.png ├── LICENSE ├── PSTModernizer.podspec ├── PSTModernizer.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── PSTModernizer ├── 1.0.0 │ └── PSTModernizer.podspec ├── PSTModernizer.h └── PSTModernizer.mm └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/ActionSheetPresentationIssue.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 780CAFD01CE9C18B00CBBF23 /* Workaround.mm in Sources */ = {isa = PBXBuildFile; fileRef = 780CAFCF1CE9C18B00CBBF23 /* Workaround.mm */; }; 11 | 7881AA831D1B7D7D005EC1FF /* PSTModernizer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7881AA821D1B7D7D005EC1FF /* PSTModernizer.mm */; }; 12 | A51CD1E51B7CE37500C6E9C3 /* TextViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A51CD1E41B7CE37500C6E9C3 /* TextViewController.m */; }; 13 | A56313591CE974B700191654 /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A56313581CE974B700191654 /* WebViewController.m */; }; 14 | A59360431A22678800711C3F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A59360421A22678700711C3F /* main.m */; }; 15 | A59360461A22678800711C3F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A59360451A22678800711C3F /* AppDelegate.m */; }; 16 | A593604E1A22678800711C3F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A593604D1A22678800711C3F /* Images.xcassets */; }; 17 | A59360511A22678800711C3F /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A593604F1A22678800711C3F /* LaunchScreen.xib */; }; 18 | A5E68B4F1CE9899A0028420D /* NewerWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5E68B4E1CE9899A0028420D /* NewerWebViewController.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 780CAFCF1CE9C18B00CBBF23 /* Workaround.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Workaround.mm; sourceTree = ""; }; 23 | 780CAFD11CE9C1EB00CBBF23 /* Workaround.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Workaround.h; sourceTree = ""; }; 24 | 7881AA811D1B7D7D005EC1FF /* PSTModernizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSTModernizer.h; sourceTree = ""; }; 25 | 7881AA821D1B7D7D005EC1FF /* PSTModernizer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PSTModernizer.mm; sourceTree = ""; }; 26 | A51CD1E31B7CE37500C6E9C3 /* TextViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextViewController.h; sourceTree = ""; }; 27 | A51CD1E41B7CE37500C6E9C3 /* TextViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextViewController.m; sourceTree = ""; }; 28 | A56313571CE974B700191654 /* WebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewController.h; sourceTree = ""; }; 29 | A56313581CE974B700191654 /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = ""; }; 30 | A593603D1A22678700711C3F /* PresentationPlayground.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PresentationPlayground.app; sourceTree = BUILT_PRODUCTS_DIR; }; 31 | A59360411A22678700711C3F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | A59360421A22678700711C3F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | A59360441A22678800711C3F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 34 | A59360451A22678800711C3F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 35 | A593604D1A22678800711C3F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 36 | A59360501A22678800711C3F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 37 | A5E68B4D1CE9899A0028420D /* NewerWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewerWebViewController.h; sourceTree = ""; }; 38 | A5E68B4E1CE9899A0028420D /* NewerWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewerWebViewController.m; sourceTree = ""; }; 39 | /* End PBXFileReference section */ 40 | 41 | /* Begin PBXFrameworksBuildPhase section */ 42 | A593603A1A22678700711C3F /* Frameworks */ = { 43 | isa = PBXFrameworksBuildPhase; 44 | buildActionMask = 2147483647; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXFrameworksBuildPhase section */ 50 | 51 | /* Begin PBXGroup section */ 52 | 7881AA801D1B7D7D005EC1FF /* PSTModernizer */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 7881AA811D1B7D7D005EC1FF /* PSTModernizer.h */, 56 | 7881AA821D1B7D7D005EC1FF /* PSTModernizer.mm */, 57 | ); 58 | name = PSTModernizer; 59 | path = ../../../PSTModernizer; 60 | sourceTree = ""; 61 | }; 62 | A59360341A22678700711C3F = { 63 | isa = PBXGroup; 64 | children = ( 65 | A59360661A2269BE00711C3F /* Source */, 66 | A59360671A2269C200711C3F /* Resources */, 67 | A593603E1A22678700711C3F /* Products */, 68 | ); 69 | sourceTree = ""; 70 | }; 71 | A593603E1A22678700711C3F /* Products */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | A593603D1A22678700711C3F /* PresentationPlayground.app */, 75 | ); 76 | name = Products; 77 | sourceTree = ""; 78 | }; 79 | A59360661A2269BE00711C3F /* Source */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | 7881AA801D1B7D7D005EC1FF /* PSTModernizer */, 83 | A59360421A22678700711C3F /* main.m */, 84 | A59360441A22678800711C3F /* AppDelegate.h */, 85 | 780CAFD11CE9C1EB00CBBF23 /* Workaround.h */, 86 | 780CAFCF1CE9C18B00CBBF23 /* Workaround.mm */, 87 | A59360451A22678800711C3F /* AppDelegate.m */, 88 | A51CD1E31B7CE37500C6E9C3 /* TextViewController.h */, 89 | A51CD1E41B7CE37500C6E9C3 /* TextViewController.m */, 90 | A56313571CE974B700191654 /* WebViewController.h */, 91 | A56313581CE974B700191654 /* WebViewController.m */, 92 | A5E68B4D1CE9899A0028420D /* NewerWebViewController.h */, 93 | A5E68B4E1CE9899A0028420D /* NewerWebViewController.m */, 94 | ); 95 | path = Source; 96 | sourceTree = ""; 97 | }; 98 | A59360671A2269C200711C3F /* Resources */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | A59360411A22678700711C3F /* Info.plist */, 102 | A593604D1A22678800711C3F /* Images.xcassets */, 103 | A593604F1A22678800711C3F /* LaunchScreen.xib */, 104 | ); 105 | path = Resources; 106 | sourceTree = ""; 107 | }; 108 | /* End PBXGroup section */ 109 | 110 | /* Begin PBXNativeTarget section */ 111 | A593603C1A22678700711C3F /* PresentationPlayground */ = { 112 | isa = PBXNativeTarget; 113 | buildConfigurationList = A59360601A22678800711C3F /* Build configuration list for PBXNativeTarget "PresentationPlayground" */; 114 | buildPhases = ( 115 | A59360391A22678700711C3F /* Sources */, 116 | A593603A1A22678700711C3F /* Frameworks */, 117 | A593603B1A22678700711C3F /* Resources */, 118 | ); 119 | buildRules = ( 120 | ); 121 | dependencies = ( 122 | ); 123 | name = PresentationPlayground; 124 | productName = PresentationPlayground; 125 | productReference = A593603D1A22678700711C3F /* PresentationPlayground.app */; 126 | productType = "com.apple.product-type.application"; 127 | }; 128 | /* End PBXNativeTarget section */ 129 | 130 | /* Begin PBXProject section */ 131 | A59360351A22678700711C3F /* Project object */ = { 132 | isa = PBXProject; 133 | attributes = { 134 | LastUpgradeCheck = 0700; 135 | ORGANIZATIONNAME = "Douglas Hill"; 136 | TargetAttributes = { 137 | A593603C1A22678700711C3F = { 138 | CreatedOnToolsVersion = 6.1; 139 | }; 140 | }; 141 | }; 142 | buildConfigurationList = A59360381A22678700711C3F /* Build configuration list for PBXProject "ActionSheetPresentationIssue" */; 143 | compatibilityVersion = "Xcode 3.2"; 144 | developmentRegion = English; 145 | hasScannedForEncodings = 0; 146 | knownRegions = ( 147 | en, 148 | Base, 149 | ); 150 | mainGroup = A59360341A22678700711C3F; 151 | productRefGroup = A593603E1A22678700711C3F /* Products */; 152 | projectDirPath = ""; 153 | projectRoot = ""; 154 | targets = ( 155 | A593603C1A22678700711C3F /* PresentationPlayground */, 156 | ); 157 | }; 158 | /* End PBXProject section */ 159 | 160 | /* Begin PBXResourcesBuildPhase section */ 161 | A593603B1A22678700711C3F /* Resources */ = { 162 | isa = PBXResourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | A59360511A22678800711C3F /* LaunchScreen.xib in Resources */, 166 | A593604E1A22678800711C3F /* Images.xcassets in Resources */, 167 | ); 168 | runOnlyForDeploymentPostprocessing = 0; 169 | }; 170 | /* End PBXResourcesBuildPhase section */ 171 | 172 | /* Begin PBXSourcesBuildPhase section */ 173 | A59360391A22678700711C3F /* Sources */ = { 174 | isa = PBXSourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | A59360461A22678800711C3F /* AppDelegate.m in Sources */, 178 | A59360431A22678800711C3F /* main.m in Sources */, 179 | A5E68B4F1CE9899A0028420D /* NewerWebViewController.m in Sources */, 180 | 780CAFD01CE9C18B00CBBF23 /* Workaround.mm in Sources */, 181 | A56313591CE974B700191654 /* WebViewController.m in Sources */, 182 | A51CD1E51B7CE37500C6E9C3 /* TextViewController.m in Sources */, 183 | 7881AA831D1B7D7D005EC1FF /* PSTModernizer.mm in Sources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXSourcesBuildPhase section */ 188 | 189 | /* Begin PBXVariantGroup section */ 190 | A593604F1A22678800711C3F /* LaunchScreen.xib */ = { 191 | isa = PBXVariantGroup; 192 | children = ( 193 | A59360501A22678800711C3F /* Base */, 194 | ); 195 | name = LaunchScreen.xib; 196 | sourceTree = ""; 197 | }; 198 | /* End PBXVariantGroup section */ 199 | 200 | /* Begin XCBuildConfiguration section */ 201 | A593605E1A22678800711C3F /* Debug */ = { 202 | isa = XCBuildConfiguration; 203 | buildSettings = { 204 | ALWAYS_SEARCH_USER_PATHS = NO; 205 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 206 | CLANG_CXX_LIBRARY = "libc++"; 207 | CLANG_ENABLE_MODULES = YES; 208 | CLANG_ENABLE_OBJC_ARC = YES; 209 | CLANG_WARN_BOOL_CONVERSION = YES; 210 | CLANG_WARN_CONSTANT_CONVERSION = YES; 211 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 212 | CLANG_WARN_EMPTY_BODY = YES; 213 | CLANG_WARN_ENUM_CONVERSION = YES; 214 | CLANG_WARN_INT_CONVERSION = YES; 215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 216 | CLANG_WARN_UNREACHABLE_CODE = YES; 217 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 218 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 219 | COPY_PHASE_STRIP = NO; 220 | ENABLE_STRICT_OBJC_MSGSEND = YES; 221 | ENABLE_TESTABILITY = YES; 222 | GCC_C_LANGUAGE_STANDARD = gnu99; 223 | GCC_DYNAMIC_NO_PIC = NO; 224 | GCC_OPTIMIZATION_LEVEL = 0; 225 | GCC_PREPROCESSOR_DEFINITIONS = ( 226 | "DEBUG=1", 227 | "$(inherited)", 228 | ); 229 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 232 | GCC_WARN_UNDECLARED_SELECTOR = YES; 233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 234 | GCC_WARN_UNUSED_FUNCTION = YES; 235 | GCC_WARN_UNUSED_VARIABLE = YES; 236 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 237 | MTL_ENABLE_DEBUG_INFO = YES; 238 | ONLY_ACTIVE_ARCH = YES; 239 | SDKROOT = iphoneos; 240 | TARGETED_DEVICE_FAMILY = "1,2"; 241 | }; 242 | name = Debug; 243 | }; 244 | A593605F1A22678800711C3F /* Release */ = { 245 | isa = XCBuildConfiguration; 246 | buildSettings = { 247 | ALWAYS_SEARCH_USER_PATHS = NO; 248 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 249 | CLANG_CXX_LIBRARY = "libc++"; 250 | CLANG_ENABLE_MODULES = YES; 251 | CLANG_ENABLE_OBJC_ARC = YES; 252 | CLANG_WARN_BOOL_CONVERSION = YES; 253 | CLANG_WARN_CONSTANT_CONVERSION = YES; 254 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 255 | CLANG_WARN_EMPTY_BODY = YES; 256 | CLANG_WARN_ENUM_CONVERSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 259 | CLANG_WARN_UNREACHABLE_CODE = YES; 260 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 261 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 262 | COPY_PHASE_STRIP = YES; 263 | ENABLE_NS_ASSERTIONS = NO; 264 | ENABLE_STRICT_OBJC_MSGSEND = YES; 265 | GCC_C_LANGUAGE_STANDARD = gnu99; 266 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 267 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 268 | GCC_WARN_UNDECLARED_SELECTOR = YES; 269 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 270 | GCC_WARN_UNUSED_FUNCTION = YES; 271 | GCC_WARN_UNUSED_VARIABLE = YES; 272 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 273 | MTL_ENABLE_DEBUG_INFO = NO; 274 | SDKROOT = iphoneos; 275 | TARGETED_DEVICE_FAMILY = "1,2"; 276 | VALIDATE_PRODUCT = YES; 277 | }; 278 | name = Release; 279 | }; 280 | A59360611A22678800711C3F /* Debug */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 284 | INFOPLIST_FILE = Resources/Info.plist; 285 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 286 | PRODUCT_BUNDLE_IDENTIFIER = com.pspdfkit.radar.ActionSheetPresentation; 287 | PRODUCT_NAME = "$(TARGET_NAME)"; 288 | }; 289 | name = Debug; 290 | }; 291 | A59360621A22678800711C3F /* Release */ = { 292 | isa = XCBuildConfiguration; 293 | buildSettings = { 294 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 295 | INFOPLIST_FILE = Resources/Info.plist; 296 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 297 | PRODUCT_BUNDLE_IDENTIFIER = com.pspdfkit.radar.ActionSheetPresentation; 298 | PRODUCT_NAME = "$(TARGET_NAME)"; 299 | }; 300 | name = Release; 301 | }; 302 | /* End XCBuildConfiguration section */ 303 | 304 | /* Begin XCConfigurationList section */ 305 | A59360381A22678700711C3F /* Build configuration list for PBXProject "ActionSheetPresentationIssue" */ = { 306 | isa = XCConfigurationList; 307 | buildConfigurations = ( 308 | A593605E1A22678800711C3F /* Debug */, 309 | A593605F1A22678800711C3F /* Release */, 310 | ); 311 | defaultConfigurationIsVisible = 0; 312 | defaultConfigurationName = Release; 313 | }; 314 | A59360601A22678800711C3F /* Build configuration list for PBXNativeTarget "PresentationPlayground" */ = { 315 | isa = XCConfigurationList; 316 | buildConfigurations = ( 317 | A59360611A22678800711C3F /* Debug */, 318 | A59360621A22678800711C3F /* Release */, 319 | ); 320 | defaultConfigurationIsVisible = 0; 321 | defaultConfigurationName = Release; 322 | }; 323 | /* End XCConfigurationList section */ 324 | }; 325 | rootObject = A59360351A22678700711C3F /* Project object */; 326 | } 327 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/ActionSheetPresentationIssue.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Resources/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Resources/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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Resources/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface AppDelegate : UIResponder 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import "TextViewController.h" 3 | #import "WebViewController.h" 4 | #import "NewerWebViewController.h" 5 | #import "Workaround.h" 6 | #import "PSTModernizer.h" 7 | 8 | @implementation AppDelegate 9 | 10 | @synthesize window = _window; 11 | 12 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 13 | //PSPDFInstallWorkaroundForSheetPresentation(); 14 | 15 | [PSTModernizer installModernizer]; 16 | 17 | self.window = [[UIWindow alloc] init]; 18 | 19 | UIViewController *firstTextViewController = [[TextViewController alloc] init]; 20 | firstTextViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present Second" style:UIBarButtonItemStylePlain target:self action:@selector(presentSecondTextView:)]; 21 | firstTextViewController.title = @"UITextView"; 22 | firstTextViewController.navigationItem.title = @"First"; 23 | 24 | UIViewController *firstWebViewController = [[WebViewController alloc] init]; 25 | firstWebViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present Second" style:UIBarButtonItemStylePlain target:self action:@selector(presentSecondWebView:)]; 26 | firstWebViewController.title = @"UIWebView"; 27 | firstWebViewController.navigationItem.title = @"First"; 28 | 29 | UIViewController *firstNewerWebViewController = [[NewerWebViewController alloc] init]; 30 | firstNewerWebViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present Second" style:UIBarButtonItemStylePlain target:self action:@selector(presentSecondNewerWebView:)]; 31 | firstNewerWebViewController.title = @"WKWebView"; 32 | firstNewerWebViewController.navigationItem.title = @"First"; 33 | 34 | UITabBarController *tabBarController = [[UITabBarController alloc] init]; 35 | tabBarController.viewControllers = @[ 36 | [[UINavigationController alloc] initWithRootViewController:firstTextViewController], 37 | [[UINavigationController alloc] initWithRootViewController:firstWebViewController], 38 | [[UINavigationController alloc] initWithRootViewController:firstNewerWebViewController], 39 | ]; 40 | 41 | self.window.rootViewController = tabBarController; 42 | [self.window makeKeyAndVisible]; 43 | 44 | return YES; 45 | } 46 | 47 | - (void)presentSecondTextView:(id)sender { 48 | [self presentSecondViewControllerOfClass:[TextViewController class]]; 49 | } 50 | 51 | - (void)presentSecondWebView:(id)sender { 52 | [self presentSecondViewControllerOfClass:[WebViewController class]]; 53 | } 54 | 55 | - (void)presentSecondNewerWebView:(id)sender { 56 | [self presentSecondViewControllerOfClass:[NewerWebViewController class]]; 57 | } 58 | 59 | - (void)presentSecondViewControllerOfClass:(Class)klass { 60 | UIViewController *secondViewController = [[klass alloc] init]; 61 | secondViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismiss:)]; 62 | secondViewController.title = @"Second"; 63 | 64 | UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:secondViewController]; 65 | navigationController.modalPresentationStyle = UIModalPresentationFormSheet; 66 | [self.window.rootViewController presentViewController:navigationController animated:YES completion:nil]; 67 | } 68 | 69 | - (void)dismiss:(id)sender { 70 | [self.window.rootViewController dismissViewControllerAnimated:YES completion:nil]; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/NewerWebViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NewerWebViewController : UIViewController 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/NewerWebViewController.m: -------------------------------------------------------------------------------- 1 | #import "NewerWebViewController.h" 2 | @import WebKit; 3 | 4 | @implementation NewerWebViewController 5 | 6 | - (void)loadView { 7 | WKWebView *textView = [[WKWebView alloc] init]; 8 | [textView loadHTMLString:@"

This is a WKWebView with an HTML link: PSPDFKit website

" baseURL:nil]; 9 | 10 | self.view = textView; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/TextViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface TextViewController : UIViewController 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/TextViewController.m: -------------------------------------------------------------------------------- 1 | #import "TextViewController.h" 2 | 3 | @implementation TextViewController 4 | 5 | - (void)loadView { 6 | UITextView *textView = [[UITextView alloc] init]; 7 | textView.dataDetectorTypes = UIDataDetectorTypeAll; 8 | textView.editable = NO; 9 | textView.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; 10 | textView.text = @"This is a UITextView with a phone number: 01234 567890 and web link: https://pspdfkit.com/ and a time: 15:40 tomorrow and an address:\n\n1 Infinite Loop\nCupertino CA 95014\nUnited States"; 11 | 12 | self.view = textView; 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/WebViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface WebViewController : UIViewController 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/WebViewController.m: -------------------------------------------------------------------------------- 1 | #import "WebViewController.h" 2 | 3 | @implementation WebViewController 4 | 5 | - (void)loadView { 6 | UIWebView *textView = [[UIWebView alloc] init]; 7 | textView.dataDetectorTypes = UIDataDetectorTypeAll; 8 | [textView loadHTMLString:@"

This is a UIWebView with a phone number: 01234 567890 and a detected web link: https://pspdfkit.com/ and an HTML link: PSPDFKit website and a time: 15:40 tomorrow and an address: 1 Infinite Loop Cupertino CA 95014 United States

" baseURL:nil]; 9 | 10 | self.view = textView; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/Workaround.h: -------------------------------------------------------------------------------- 1 | // 2 | // Workaround.h 3 | // PresentationPlayground 4 | // 5 | // Created by Peter Steinberger on 16/05/16. 6 | // 7 | 8 | #import 9 | 10 | FOUNDATION_EXPORT void PSPDFInstallWorkaroundForSheetPresentation(void); 11 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/Workaround.mm: -------------------------------------------------------------------------------- 1 | // 2 | // Workaround.m 3 | // PresentationPlayground 4 | // 5 | // Created by Peter Steinberger on 16/05/16. 6 | // 7 | 8 | #import "Workaround.h" 9 | #import 10 | #import 11 | 12 | static IMP pspdf_swizzleSelector(Class clazz, SEL selector, IMP newImplementation) { 13 | NSCParameterAssert(clazz); 14 | NSCParameterAssert(selector); 15 | NSCParameterAssert(newImplementation); 16 | 17 | // If the method does not exist for this class, do nothing. 18 | const Method method = class_getInstanceMethod(clazz, selector); 19 | if (!method) { 20 | NSLog(@"%@ doesn't exist in %@.", NSStringFromSelector(selector), NSStringFromClass(clazz)); 21 | // Cannot swizzle methods which are not implemented by the class or one of its parents. 22 | return NULL; 23 | } 24 | 25 | // Make sure the class implements the method. If this is not the case, inject an implementation, only calling 'super'. 26 | const char *types = method_getTypeEncoding(method); 27 | 28 | @synchronized (clazz) { 29 | // class_addMethod will simply return NO if the method is already implemented. 30 | #if !defined(__arm64__) 31 | // Sufficiently large struct 32 | typedef struct LargeStruct_ { 33 | char dummy[16]; 34 | } LargeStruct; 35 | 36 | NSUInteger retSize = 0; 37 | NSGetSizeAndAlignment(types, &retSize, NULL); 38 | 39 | // Large structs on 32-bit architectures 40 | if (sizeof(void *) == 4 && types[0] == _C_STRUCT_B && retSize != 1 && retSize != 2 && retSize != 4 && retSize != 8) { 41 | class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) { 42 | struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)}; 43 | return ((LargeStruct (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper_stret)(&super, selector, argp); 44 | }), types); 45 | } 46 | // All other cases 47 | else { 48 | #endif 49 | class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) { 50 | struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)}; 51 | return ((id (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper)(&super, selector, argp); 52 | }), types); 53 | #if !defined(__arm64__) 54 | } 55 | #endif 56 | 57 | // Swizzling 58 | return class_replaceMethod(clazz, selector, newImplementation, types); 59 | } 60 | } 61 | 62 | IMP pspdf_swizzleSelectorWithBlock(Class clazz, SEL selector, id newImplementationBlock) { 63 | IMP const newImplementation = imp_implementationWithBlock(newImplementationBlock); 64 | return pspdf_swizzleSelector(clazz, selector, newImplementation); 65 | } 66 | 67 | FOUNDATION_EXPORT void PSPDFInstallWorkaroundForSheetPresentation(void) { 68 | __block auto removeWorkaround = ^{}; 69 | const auto installWorkaround = ^{ 70 | const SEL presentSEL = @selector(presentViewController:animated:completion:); 71 | __block IMP origIMP = pspdf_swizzleSelectorWithBlock(UIViewController.class, presentSEL, ^(UIViewController *self, id vC, BOOL animated, id completion) { 72 | UIViewController *targetVC = self; 73 | while (targetVC.presentedViewController) { 74 | targetVC = targetVC.presentedViewController; 75 | } 76 | ((void (*)(id, SEL, id, BOOL, id))origIMP)(targetVC, presentSEL, vC, animated, completion); 77 | }); 78 | removeWorkaround = ^{ 79 | pspdf_swizzleSelector(UIViewController.class, presentSEL, origIMP); 80 | }; 81 | }; 82 | 83 | // Fixes rdar:// 84 | const SEL presentSheetSEL = NSSelectorFromString(@"presentSheetFromRect:"); 85 | const auto swizzleOnClass = ^(Class klass) { 86 | const __block IMP origIMP = pspdf_swizzleSelectorWithBlock(klass, presentSheetSEL, ^(id self, CGRect rect) { 87 | // Before calling the original implementation, we swizzle the presentation logic on UIViewController 88 | installWorkaround(); 89 | // UIKit later presents the sheet on [view.window rootViewController]; 90 | // Our workaround forwards this to the topmost presentedViewController instead. 91 | ((void (*)(id, SEL, CGRect))origIMP)(self, presentSheetSEL, rect); 92 | // Cleaning up again - this workaround would swallow bugs if we let it be there. 93 | removeWorkaround(); 94 | }); 95 | }; 96 | swizzleOnClass(NSClassFromString(@"_UIRotatingAlertController")); 97 | swizzleOnClass(NSClassFromString(@"WKActionSheet")); 98 | } 99 | -------------------------------------------------------------------------------- /Example/26295020, 26294823 - Action Sheet Presentation/Source/main.m: -------------------------------------------------------------------------------- 1 | @import UIKit; 2 | #import "AppDelegate.h" 3 | 4 | int main(int argc, char *argv[]) { 5 | @autoreleasepool { 6 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7881AA7F1D1B7AE4005EC1FF /* PSTModernizer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7881AA7E1D1B7AE4005EC1FF /* PSTModernizer.mm */; }; 11 | 78A341181D1B283D00858C36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A341171D1B283D00858C36 /* main.m */; }; 12 | 78A3411B1D1B283D00858C36 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A3411A1D1B283D00858C36 /* AppDelegate.m */; }; 13 | 78A3411E1D1B283D00858C36 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A3411D1D1B283D00858C36 /* ViewController.m */; }; 14 | 78A341211D1B283D00858C36 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78A3411F1D1B283D00858C36 /* Main.storyboard */; }; 15 | 78A341231D1B283D00858C36 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 78A341221D1B283D00858C36 /* Assets.xcassets */; }; 16 | 78A341261D1B283D00858C36 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78A341241D1B283D00858C36 /* LaunchScreen.storyboard */; }; 17 | 78A3412E1D1B288900858C36 /* meme.png in Resources */ = {isa = PBXBuildFile; fileRef = 78A3412D1D1B288900858C36 /* meme.png */; }; 18 | /* End PBXBuildFile section */ 19 | 20 | /* Begin PBXFileReference section */ 21 | 7881AA7D1D1B7AE4005EC1FF /* PSTModernizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSTModernizer.h; sourceTree = ""; }; 22 | 7881AA7E1D1B7AE4005EC1FF /* PSTModernizer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PSTModernizer.mm; sourceTree = ""; }; 23 | 78A341131D1B283D00858C36 /* UIImageWithDataMultithreaded.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIImageWithDataMultithreaded.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 78A341171D1B283D00858C36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 25 | 78A341191D1B283D00858C36 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 26 | 78A3411A1D1B283D00858C36 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 27 | 78A3411C1D1B283D00858C36 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 28 | 78A3411D1D1B283D00858C36 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 29 | 78A341201D1B283D00858C36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | 78A341221D1B283D00858C36 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 31 | 78A341251D1B283D00858C36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | 78A341271D1B283D00858C36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 33 | 78A3412D1D1B288900858C36 /* meme.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = meme.png; sourceTree = ""; }; 34 | /* End PBXFileReference section */ 35 | 36 | /* Begin PBXFrameworksBuildPhase section */ 37 | 78A341101D1B283D00858C36 /* Frameworks */ = { 38 | isa = PBXFrameworksBuildPhase; 39 | buildActionMask = 2147483647; 40 | files = ( 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | 7881AA7C1D1B7AE4005EC1FF /* PSTModernizer */ = { 48 | isa = PBXGroup; 49 | children = ( 50 | 7881AA7D1D1B7AE4005EC1FF /* PSTModernizer.h */, 51 | 7881AA7E1D1B7AE4005EC1FF /* PSTModernizer.mm */, 52 | ); 53 | name = PSTModernizer; 54 | path = ../../../PSTModernizer; 55 | sourceTree = ""; 56 | }; 57 | 78A3410A1D1B283D00858C36 = { 58 | isa = PBXGroup; 59 | children = ( 60 | 78A341151D1B283D00858C36 /* UIImageWithDataMultithreaded */, 61 | 78A341141D1B283D00858C36 /* Products */, 62 | ); 63 | sourceTree = ""; 64 | }; 65 | 78A341141D1B283D00858C36 /* Products */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 78A341131D1B283D00858C36 /* UIImageWithDataMultithreaded.app */, 69 | ); 70 | name = Products; 71 | sourceTree = ""; 72 | }; 73 | 78A341151D1B283D00858C36 /* UIImageWithDataMultithreaded */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 7881AA7C1D1B7AE4005EC1FF /* PSTModernizer */, 77 | 78A3412D1D1B288900858C36 /* meme.png */, 78 | 78A341191D1B283D00858C36 /* AppDelegate.h */, 79 | 78A3411A1D1B283D00858C36 /* AppDelegate.m */, 80 | 78A3411C1D1B283D00858C36 /* ViewController.h */, 81 | 78A3411D1D1B283D00858C36 /* ViewController.m */, 82 | 78A3411F1D1B283D00858C36 /* Main.storyboard */, 83 | 78A341221D1B283D00858C36 /* Assets.xcassets */, 84 | 78A341241D1B283D00858C36 /* LaunchScreen.storyboard */, 85 | 78A341271D1B283D00858C36 /* Info.plist */, 86 | 78A341161D1B283D00858C36 /* Supporting Files */, 87 | ); 88 | path = UIImageWithDataMultithreaded; 89 | sourceTree = ""; 90 | }; 91 | 78A341161D1B283D00858C36 /* Supporting Files */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 78A341171D1B283D00858C36 /* main.m */, 95 | ); 96 | name = "Supporting Files"; 97 | sourceTree = ""; 98 | }; 99 | /* End PBXGroup section */ 100 | 101 | /* Begin PBXNativeTarget section */ 102 | 78A341121D1B283D00858C36 /* UIImageWithDataMultithreaded */ = { 103 | isa = PBXNativeTarget; 104 | buildConfigurationList = 78A3412A1D1B283D00858C36 /* Build configuration list for PBXNativeTarget "UIImageWithDataMultithreaded" */; 105 | buildPhases = ( 106 | 78A3410F1D1B283D00858C36 /* Sources */, 107 | 78A341101D1B283D00858C36 /* Frameworks */, 108 | 78A341111D1B283D00858C36 /* Resources */, 109 | ); 110 | buildRules = ( 111 | ); 112 | dependencies = ( 113 | ); 114 | name = UIImageWithDataMultithreaded; 115 | productName = UIImageWithDataMultithreaded; 116 | productReference = 78A341131D1B283D00858C36 /* UIImageWithDataMultithreaded.app */; 117 | productType = "com.apple.product-type.application"; 118 | }; 119 | /* End PBXNativeTarget section */ 120 | 121 | /* Begin PBXProject section */ 122 | 78A3410B1D1B283D00858C36 /* Project object */ = { 123 | isa = PBXProject; 124 | attributes = { 125 | LastUpgradeCheck = 0730; 126 | ORGANIZATIONNAME = "PSPDFKit GmbH"; 127 | TargetAttributes = { 128 | 78A341121D1B283D00858C36 = { 129 | CreatedOnToolsVersion = 7.3.1; 130 | }; 131 | }; 132 | }; 133 | buildConfigurationList = 78A3410E1D1B283D00858C36 /* Build configuration list for PBXProject "UIImageWithDataMultithreaded" */; 134 | compatibilityVersion = "Xcode 3.2"; 135 | developmentRegion = English; 136 | hasScannedForEncodings = 0; 137 | knownRegions = ( 138 | en, 139 | Base, 140 | ); 141 | mainGroup = 78A3410A1D1B283D00858C36; 142 | productRefGroup = 78A341141D1B283D00858C36 /* Products */; 143 | projectDirPath = ""; 144 | projectRoot = ""; 145 | targets = ( 146 | 78A341121D1B283D00858C36 /* UIImageWithDataMultithreaded */, 147 | ); 148 | }; 149 | /* End PBXProject section */ 150 | 151 | /* Begin PBXResourcesBuildPhase section */ 152 | 78A341111D1B283D00858C36 /* Resources */ = { 153 | isa = PBXResourcesBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 78A341261D1B283D00858C36 /* LaunchScreen.storyboard in Resources */, 157 | 78A341231D1B283D00858C36 /* Assets.xcassets in Resources */, 158 | 78A341211D1B283D00858C36 /* Main.storyboard in Resources */, 159 | 78A3412E1D1B288900858C36 /* meme.png in Resources */, 160 | ); 161 | runOnlyForDeploymentPostprocessing = 0; 162 | }; 163 | /* End PBXResourcesBuildPhase section */ 164 | 165 | /* Begin PBXSourcesBuildPhase section */ 166 | 78A3410F1D1B283D00858C36 /* Sources */ = { 167 | isa = PBXSourcesBuildPhase; 168 | buildActionMask = 2147483647; 169 | files = ( 170 | 78A3411E1D1B283D00858C36 /* ViewController.m in Sources */, 171 | 78A3411B1D1B283D00858C36 /* AppDelegate.m in Sources */, 172 | 7881AA7F1D1B7AE4005EC1FF /* PSTModernizer.mm in Sources */, 173 | 78A341181D1B283D00858C36 /* main.m in Sources */, 174 | ); 175 | runOnlyForDeploymentPostprocessing = 0; 176 | }; 177 | /* End PBXSourcesBuildPhase section */ 178 | 179 | /* Begin PBXVariantGroup section */ 180 | 78A3411F1D1B283D00858C36 /* Main.storyboard */ = { 181 | isa = PBXVariantGroup; 182 | children = ( 183 | 78A341201D1B283D00858C36 /* Base */, 184 | ); 185 | name = Main.storyboard; 186 | sourceTree = ""; 187 | }; 188 | 78A341241D1B283D00858C36 /* LaunchScreen.storyboard */ = { 189 | isa = PBXVariantGroup; 190 | children = ( 191 | 78A341251D1B283D00858C36 /* Base */, 192 | ); 193 | name = LaunchScreen.storyboard; 194 | sourceTree = ""; 195 | }; 196 | /* End PBXVariantGroup section */ 197 | 198 | /* Begin XCBuildConfiguration section */ 199 | 78A341281D1B283D00858C36 /* Debug */ = { 200 | isa = XCBuildConfiguration; 201 | buildSettings = { 202 | ALWAYS_SEARCH_USER_PATHS = NO; 203 | CLANG_ANALYZER_NONNULL = YES; 204 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 205 | CLANG_CXX_LIBRARY = "libc++"; 206 | CLANG_ENABLE_MODULES = YES; 207 | CLANG_ENABLE_OBJC_ARC = YES; 208 | CLANG_WARN_BOOL_CONVERSION = YES; 209 | CLANG_WARN_CONSTANT_CONVERSION = YES; 210 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 211 | CLANG_WARN_EMPTY_BODY = YES; 212 | CLANG_WARN_ENUM_CONVERSION = YES; 213 | CLANG_WARN_INT_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_UNREACHABLE_CODE = YES; 216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 217 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 218 | COPY_PHASE_STRIP = NO; 219 | DEBUG_INFORMATION_FORMAT = dwarf; 220 | ENABLE_STRICT_OBJC_MSGSEND = YES; 221 | ENABLE_TESTABILITY = YES; 222 | GCC_C_LANGUAGE_STANDARD = gnu99; 223 | GCC_DYNAMIC_NO_PIC = NO; 224 | GCC_NO_COMMON_BLOCKS = YES; 225 | GCC_OPTIMIZATION_LEVEL = 0; 226 | GCC_PREPROCESSOR_DEFINITIONS = ( 227 | "DEBUG=1", 228 | "$(inherited)", 229 | ); 230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 232 | GCC_WARN_UNDECLARED_SELECTOR = YES; 233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 234 | GCC_WARN_UNUSED_FUNCTION = YES; 235 | GCC_WARN_UNUSED_VARIABLE = YES; 236 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 237 | MTL_ENABLE_DEBUG_INFO = YES; 238 | ONLY_ACTIVE_ARCH = YES; 239 | SDKROOT = iphoneos; 240 | TARGETED_DEVICE_FAMILY = "1,2"; 241 | }; 242 | name = Debug; 243 | }; 244 | 78A341291D1B283D00858C36 /* Release */ = { 245 | isa = XCBuildConfiguration; 246 | buildSettings = { 247 | ALWAYS_SEARCH_USER_PATHS = NO; 248 | CLANG_ANALYZER_NONNULL = YES; 249 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 250 | CLANG_CXX_LIBRARY = "libc++"; 251 | CLANG_ENABLE_MODULES = YES; 252 | CLANG_ENABLE_OBJC_ARC = YES; 253 | CLANG_WARN_BOOL_CONVERSION = YES; 254 | CLANG_WARN_CONSTANT_CONVERSION = YES; 255 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 256 | CLANG_WARN_EMPTY_BODY = YES; 257 | CLANG_WARN_ENUM_CONVERSION = YES; 258 | CLANG_WARN_INT_CONVERSION = YES; 259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | TARGETED_DEVICE_FAMILY = "1,2"; 279 | VALIDATE_PRODUCT = YES; 280 | }; 281 | name = Release; 282 | }; 283 | 78A3412B1D1B283D00858C36 /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 287 | INFOPLIST_FILE = UIImageWithDataMultithreaded/Info.plist; 288 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 289 | PRODUCT_BUNDLE_IDENTIFIER = PSPDFKit.UIImageWithDataMultithreaded; 290 | PRODUCT_NAME = "$(TARGET_NAME)"; 291 | }; 292 | name = Debug; 293 | }; 294 | 78A3412C1D1B283D00858C36 /* Release */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 298 | INFOPLIST_FILE = UIImageWithDataMultithreaded/Info.plist; 299 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 300 | PRODUCT_BUNDLE_IDENTIFIER = PSPDFKit.UIImageWithDataMultithreaded; 301 | PRODUCT_NAME = "$(TARGET_NAME)"; 302 | }; 303 | name = Release; 304 | }; 305 | /* End XCBuildConfiguration section */ 306 | 307 | /* Begin XCConfigurationList section */ 308 | 78A3410E1D1B283D00858C36 /* Build configuration list for PBXProject "UIImageWithDataMultithreaded" */ = { 309 | isa = XCConfigurationList; 310 | buildConfigurations = ( 311 | 78A341281D1B283D00858C36 /* Debug */, 312 | 78A341291D1B283D00858C36 /* Release */, 313 | ); 314 | defaultConfigurationIsVisible = 0; 315 | defaultConfigurationName = Release; 316 | }; 317 | 78A3412A1D1B283D00858C36 /* Build configuration list for PBXNativeTarget "UIImageWithDataMultithreaded" */ = { 318 | isa = XCConfigurationList; 319 | buildConfigurations = ( 320 | 78A3412B1D1B283D00858C36 /* Debug */, 321 | 78A3412C1D1B283D00858C36 /* Release */, 322 | ); 323 | defaultConfigurationIsVisible = 0; 324 | defaultConfigurationName = Release; 325 | }; 326 | /* End XCConfigurationList section */ 327 | }; 328 | rootObject = 78A3410B1D1B283D00858C36 /* Project object */; 329 | } 330 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // UIImageWithDataMultithreaded 4 | // 5 | // Created by Peter Steinberger on 22/06/16. 6 | // Copyright © 2016 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // UIImageWithDataMultithreaded 4 | // 5 | // Created by Peter Steinberger on 22/06/16. 6 | // Copyright © 2016 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "PSTModernizer.h" 11 | 12 | @interface AppDelegate () 13 | 14 | @end 15 | 16 | @implementation AppDelegate 17 | 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 | [PSTModernizer installModernizer]; 21 | return YES; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Assets.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" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Base.lproj/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 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/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 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // UIImageWithDataMultithreaded 4 | // 5 | // Created by Peter Steinberger on 22/06/16. 6 | // Copyright © 2016 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // UIImageWithDataMultithreaded 4 | // 5 | // Created by Peter Steinberger on 22/06/16. 6 | // Copyright © 2016 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | @interface ViewController () 12 | 13 | @end 14 | 15 | @implementation ViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"meme" withExtension:@"png"]; 21 | NSData *data = [NSData dataWithContentsOfURL:fileURL]; 22 | 23 | dispatch_apply(10000000, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t idx) { 24 | @autoreleasepool { 25 | UIImage *image = [UIImage imageWithData:data]; 26 | assert(image != nil); 27 | } 28 | }); 29 | } 30 | 31 | @end 32 | 33 | 34 | 35 | #import 36 | #import 37 | 38 | // Compile-time selector checks. 39 | #if DEBUG 40 | #define PROPERTY(propName) NSStringFromSelector(@selector(propName)) 41 | #else 42 | #define PROPERTY(propName) @#propName 43 | #endif 44 | 45 | // http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html 46 | BOOL PSPDFReplaceMethodWithBlock(Class c, SEL origSEL, SEL newSEL, id block) { 47 | NSCParameterAssert(c); 48 | NSCParameterAssert(origSEL); 49 | NSCParameterAssert(newSEL); 50 | NSCParameterAssert(block); 51 | 52 | if ([c instancesRespondToSelector:newSEL]) return YES; // Selector already implemented, skip silently. 53 | 54 | Method origMethod = class_getInstanceMethod(c, origSEL); 55 | 56 | // Add the new method. 57 | IMP impl = imp_implementationWithBlock(block); 58 | if (!class_addMethod(c, newSEL, impl, method_getTypeEncoding(origMethod))) { 59 | NSLog(@"Failed to add method: %@ on %@", NSStringFromSelector(newSEL), c); 60 | return NO; 61 | }else { 62 | Method newMethod = class_getInstanceMethod(c, newSEL); 63 | 64 | // If original doesn't implement the method we want to swizzle, create it. 65 | if (class_addMethod(c, origSEL, method_getImplementation(newMethod), method_getTypeEncoding(origMethod))) { 66 | class_replaceMethod(c, newSEL, method_getImplementation(origMethod), method_getTypeEncoding(newMethod)); 67 | }else { 68 | method_exchangeImplementations(origMethod, newMethod); 69 | } 70 | } 71 | return YES; 72 | } 73 | 74 | SEL _PSPDFPrefixedSelector(SEL selector) { 75 | return NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", NSStringFromSelector(selector)]); 76 | } 77 | 78 | #define PSPDFAssert(expression, ...) \ 79 | do { if(!(expression)) { \ 80 | NSLog(@"%@", [NSString stringWithFormat: @"Assertion failure: %s in %s on line %s:%d. %@", #expression, __PRETTY_FUNCTION__, __FILE__, __LINE__, [NSString stringWithFormat:@"" __VA_ARGS__]]); \ 81 | abort(); }} while(0) 82 | 83 | void PSPDFAssertIfNotMainThread(void) { 84 | PSPDFAssert(NSThread.isMainThread, @"\nERROR: All calls to UIKit need to happen on the main thread. You have a bug in your code. Use dispatch_async(dispatch_get_main_queue(), ^{ ... }); if you're unsure what thread you're in.\n\nBreak on PSPDFAssertIfNotMainThread to find out where.\n\nStacktrace: %@", NSThread.callStackSymbols); 85 | } 86 | 87 | __attribute__((constructor)) static void PSPDFUIKitMainThreadGuard(void) { 88 | @autoreleasepool { 89 | for (NSString *selStr in @[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) { 90 | SEL selector = NSSelectorFromString(selStr); 91 | SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", selStr]); 92 | if ([selStr hasSuffix:@":"]) { 93 | PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self, CGRect r) { 94 | // Check for window, since *some* UIKit methods are indeed thread safe. 95 | // https://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html 96 | /* 97 | Drawing to a graphics context in UIKit is now thread-safe. Specifically: 98 | The routines used to access and manipulate the graphics context can now correctly handle contexts residing on different threads. 99 | String and image drawing is now thread-safe. 100 | Using color and font objects in multiple threads is now safe to do. 101 | */ 102 | if (_self.window) PSPDFAssertIfNotMainThread(); 103 | ((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r); 104 | }); 105 | }else { 106 | PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self) { 107 | if (_self.window) { 108 | if (!NSThread.isMainThread) { 109 | #pragma clang diagnostic push 110 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 111 | dispatch_queue_t queue = dispatch_get_current_queue(); 112 | #pragma clang diagnostic pop 113 | // iOS 8 layouts the MFMailComposeController in a background thread on an UIKit queue. 114 | // https://github.com/PSPDFKit/PSPDFKit/issues/1423 115 | if (!queue || !strstr(dispatch_queue_get_label(queue), "UIKit")) { 116 | PSPDFAssertIfNotMainThread(); 117 | } 118 | } 119 | } 120 | ((void ( *)(id, SEL))objc_msgSend)(_self, newSelector); 121 | }); 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // UIImageWithDataMultithreaded 4 | // 5 | // Created by Peter Steinberger on 22/06/16. 6 | // Copyright © 2016 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/meme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PSPDFKit-labs/PSTModernizer/2f1787c92f90fee0fa524f33e6e5bde75ef295f2/Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/meme.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Peter Steinberger, PSPDFKit GmbH. 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 | -------------------------------------------------------------------------------- /PSTModernizer.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint PSTModernizer.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | 6 | Pod::Spec.new do |s| 7 | s.name = 'PSTModernizer' 8 | s.version = '1.0.0' 9 | s.summary = 'Makes it easier to support older versions of iOS by fixing things and adding missing methods' 10 | s.description = <<-DESC 11 | PSTModernizer carefully applies patches to UIKit and related Apple frameworks to fix known radars with the least impact. The current set of patches just applies to iOS 9 and nothing is executed on iOS 10, as the bugs have been fixed there. 12 | DESC 13 | 14 | s.homepage = 'https://github.com/PSPDFKit-labs/PSTModernizer' 15 | s.license = { :type => 'MIT', :file => 'LICENSE' } 16 | s.author = { 'Peter Steinberger, PSPDFKit' => 'https://pspdfkit.com/' } 17 | s.source = { :git => 'https://github.com/PSPDFKit-labs/PSTModernizer.git', :tag => s.version.to_s } 18 | s.source_files = 'PSTModernizer/**/*' 19 | s.social_media_url = 'https://twitter.com/steipete' 20 | 21 | s.ios.deployment_target = '9.0' 22 | s.tvos.deployment_target = '9.0' 23 | s.xcconfig = { 'CLANG_MODULES_AUTOLINK' => 'YES' } 24 | 25 | end 26 | -------------------------------------------------------------------------------- /PSTModernizer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7877A4441D1B672B005AEBAC /* PSTModernizer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7877A4431D1B672B005AEBAC /* PSTModernizer.h */; }; 11 | 7877A4461D1B672B005AEBAC /* PSTModernizer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7877A4451D1B672B005AEBAC /* PSTModernizer.mm */; settings = {COMPILER_FLAGS = "-fno-exceptions"; }; }; 12 | /* End PBXBuildFile section */ 13 | 14 | /* Begin PBXCopyFilesBuildPhase section */ 15 | 7877A43E1D1B672B005AEBAC /* CopyFiles */ = { 16 | isa = PBXCopyFilesBuildPhase; 17 | buildActionMask = 2147483647; 18 | dstPath = "include/$(PRODUCT_NAME)"; 19 | dstSubfolderSpec = 16; 20 | files = ( 21 | 7877A4441D1B672B005AEBAC /* PSTModernizer.h in CopyFiles */, 22 | ); 23 | runOnlyForDeploymentPostprocessing = 0; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 7877A4401D1B672B005AEBAC /* libPSTModernizer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPSTModernizer.a; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | 7877A4431D1B672B005AEBAC /* PSTModernizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PSTModernizer.h; sourceTree = ""; }; 30 | 7877A4451D1B672B005AEBAC /* PSTModernizer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PSTModernizer.mm; sourceTree = ""; }; 31 | 7881AA3A1D1B761E005EC1FF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 32 | 7881AA3C1D1B7622005EC1FF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 7877A43D1D1B672B005AEBAC /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 7877A4371D1B672B005AEBAC = { 47 | isa = PBXGroup; 48 | children = ( 49 | 7881AA3C1D1B7622005EC1FF /* Foundation.framework */, 50 | 7881AA3A1D1B761E005EC1FF /* UIKit.framework */, 51 | 7877A4421D1B672B005AEBAC /* PSTModernizer */, 52 | 7877A4411D1B672B005AEBAC /* Products */, 53 | ); 54 | sourceTree = ""; 55 | }; 56 | 7877A4411D1B672B005AEBAC /* Products */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | 7877A4401D1B672B005AEBAC /* libPSTModernizer.a */, 60 | ); 61 | name = Products; 62 | sourceTree = ""; 63 | }; 64 | 7877A4421D1B672B005AEBAC /* PSTModernizer */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | 7877A4431D1B672B005AEBAC /* PSTModernizer.h */, 68 | 7877A4451D1B672B005AEBAC /* PSTModernizer.mm */, 69 | ); 70 | path = PSTModernizer; 71 | sourceTree = ""; 72 | }; 73 | /* End PBXGroup section */ 74 | 75 | /* Begin PBXNativeTarget section */ 76 | 7877A43F1D1B672B005AEBAC /* PSTModernizer */ = { 77 | isa = PBXNativeTarget; 78 | buildConfigurationList = 7877A4491D1B672B005AEBAC /* Build configuration list for PBXNativeTarget "PSTModernizer" */; 79 | buildPhases = ( 80 | 7877A43C1D1B672B005AEBAC /* Sources */, 81 | 7877A43D1D1B672B005AEBAC /* Frameworks */, 82 | 7877A43E1D1B672B005AEBAC /* CopyFiles */, 83 | ); 84 | buildRules = ( 85 | ); 86 | dependencies = ( 87 | ); 88 | name = PSTModernizer; 89 | productName = PSTModernizer; 90 | productReference = 7877A4401D1B672B005AEBAC /* libPSTModernizer.a */; 91 | productType = "com.apple.product-type.library.static"; 92 | }; 93 | /* End PBXNativeTarget section */ 94 | 95 | /* Begin PBXProject section */ 96 | 7877A4381D1B672B005AEBAC /* Project object */ = { 97 | isa = PBXProject; 98 | attributes = { 99 | LastUpgradeCheck = 0730; 100 | ORGANIZATIONNAME = "PSPDFKit GmbH"; 101 | TargetAttributes = { 102 | 7877A43F1D1B672B005AEBAC = { 103 | CreatedOnToolsVersion = 7.3.1; 104 | }; 105 | }; 106 | }; 107 | buildConfigurationList = 7877A43B1D1B672B005AEBAC /* Build configuration list for PBXProject "PSTModernizer" */; 108 | compatibilityVersion = "Xcode 3.2"; 109 | developmentRegion = English; 110 | hasScannedForEncodings = 0; 111 | knownRegions = ( 112 | en, 113 | Base, 114 | ); 115 | mainGroup = 7877A4371D1B672B005AEBAC; 116 | productRefGroup = 7877A4411D1B672B005AEBAC /* Products */; 117 | projectDirPath = ""; 118 | projectRoot = ""; 119 | targets = ( 120 | 7877A43F1D1B672B005AEBAC /* PSTModernizer */, 121 | ); 122 | }; 123 | /* End PBXProject section */ 124 | 125 | /* Begin PBXSourcesBuildPhase section */ 126 | 7877A43C1D1B672B005AEBAC /* Sources */ = { 127 | isa = PBXSourcesBuildPhase; 128 | buildActionMask = 2147483647; 129 | files = ( 130 | 7877A4461D1B672B005AEBAC /* PSTModernizer.mm in Sources */, 131 | ); 132 | runOnlyForDeploymentPostprocessing = 0; 133 | }; 134 | /* End PBXSourcesBuildPhase section */ 135 | 136 | /* Begin XCBuildConfiguration section */ 137 | 7877A4471D1B672B005AEBAC /* Debug */ = { 138 | isa = XCBuildConfiguration; 139 | buildSettings = { 140 | ALWAYS_SEARCH_USER_PATHS = NO; 141 | CLANG_ANALYZER_NONNULL = YES; 142 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 143 | CLANG_CXX_LIBRARY = "libc++"; 144 | CLANG_ENABLE_MODULES = YES; 145 | CLANG_ENABLE_OBJC_ARC = YES; 146 | CLANG_WARN_BOOL_CONVERSION = YES; 147 | CLANG_WARN_CONSTANT_CONVERSION = YES; 148 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 149 | CLANG_WARN_EMPTY_BODY = YES; 150 | CLANG_WARN_ENUM_CONVERSION = YES; 151 | CLANG_WARN_INT_CONVERSION = YES; 152 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 153 | CLANG_WARN_UNREACHABLE_CODE = YES; 154 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 155 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 156 | COPY_PHASE_STRIP = NO; 157 | DEBUG_INFORMATION_FORMAT = dwarf; 158 | ENABLE_STRICT_OBJC_MSGSEND = YES; 159 | ENABLE_TESTABILITY = YES; 160 | GCC_C_LANGUAGE_STANDARD = gnu99; 161 | GCC_DYNAMIC_NO_PIC = NO; 162 | GCC_NO_COMMON_BLOCKS = YES; 163 | GCC_OPTIMIZATION_LEVEL = 0; 164 | GCC_PREPROCESSOR_DEFINITIONS = ( 165 | "DEBUG=1", 166 | "$(inherited)", 167 | ); 168 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 169 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 170 | GCC_WARN_UNDECLARED_SELECTOR = YES; 171 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 172 | GCC_WARN_UNUSED_FUNCTION = YES; 173 | GCC_WARN_UNUSED_VARIABLE = YES; 174 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 175 | MTL_ENABLE_DEBUG_INFO = YES; 176 | ONLY_ACTIVE_ARCH = YES; 177 | OTHER_LDFLAGS = "-lc++"; 178 | SDKROOT = iphoneos; 179 | }; 180 | name = Debug; 181 | }; 182 | 7877A4481D1B672B005AEBAC /* Release */ = { 183 | isa = XCBuildConfiguration; 184 | buildSettings = { 185 | ALWAYS_SEARCH_USER_PATHS = NO; 186 | CLANG_ANALYZER_NONNULL = YES; 187 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 188 | CLANG_CXX_LIBRARY = "libc++"; 189 | CLANG_ENABLE_MODULES = YES; 190 | CLANG_ENABLE_OBJC_ARC = YES; 191 | CLANG_WARN_BOOL_CONVERSION = YES; 192 | CLANG_WARN_CONSTANT_CONVERSION = YES; 193 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 194 | CLANG_WARN_EMPTY_BODY = YES; 195 | CLANG_WARN_ENUM_CONVERSION = YES; 196 | CLANG_WARN_INT_CONVERSION = YES; 197 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 198 | CLANG_WARN_UNREACHABLE_CODE = YES; 199 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 200 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 201 | COPY_PHASE_STRIP = NO; 202 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 203 | ENABLE_NS_ASSERTIONS = NO; 204 | ENABLE_STRICT_OBJC_MSGSEND = YES; 205 | GCC_C_LANGUAGE_STANDARD = gnu99; 206 | GCC_NO_COMMON_BLOCKS = YES; 207 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 208 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 209 | GCC_WARN_UNDECLARED_SELECTOR = YES; 210 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 211 | GCC_WARN_UNUSED_FUNCTION = YES; 212 | GCC_WARN_UNUSED_VARIABLE = YES; 213 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 214 | MTL_ENABLE_DEBUG_INFO = NO; 215 | OTHER_LDFLAGS = "-lc++"; 216 | SDKROOT = iphoneos; 217 | VALIDATE_PRODUCT = YES; 218 | }; 219 | name = Release; 220 | }; 221 | 7877A44A1D1B672B005AEBAC /* Debug */ = { 222 | isa = XCBuildConfiguration; 223 | buildSettings = { 224 | OTHER_LDFLAGS = "-ObjC"; 225 | PRODUCT_NAME = "$(TARGET_NAME)"; 226 | SKIP_INSTALL = YES; 227 | }; 228 | name = Debug; 229 | }; 230 | 7877A44B1D1B672B005AEBAC /* Release */ = { 231 | isa = XCBuildConfiguration; 232 | buildSettings = { 233 | OTHER_LDFLAGS = "-ObjC"; 234 | PRODUCT_NAME = "$(TARGET_NAME)"; 235 | SKIP_INSTALL = YES; 236 | }; 237 | name = Release; 238 | }; 239 | /* End XCBuildConfiguration section */ 240 | 241 | /* Begin XCConfigurationList section */ 242 | 7877A43B1D1B672B005AEBAC /* Build configuration list for PBXProject "PSTModernizer" */ = { 243 | isa = XCConfigurationList; 244 | buildConfigurations = ( 245 | 7877A4471D1B672B005AEBAC /* Debug */, 246 | 7877A4481D1B672B005AEBAC /* Release */, 247 | ); 248 | defaultConfigurationIsVisible = 0; 249 | defaultConfigurationName = Release; 250 | }; 251 | 7877A4491D1B672B005AEBAC /* Build configuration list for PBXNativeTarget "PSTModernizer" */ = { 252 | isa = XCConfigurationList; 253 | buildConfigurations = ( 254 | 7877A44A1D1B672B005AEBAC /* Debug */, 255 | 7877A44B1D1B672B005AEBAC /* Release */, 256 | ); 257 | defaultConfigurationIsVisible = 0; 258 | defaultConfigurationName = Release; 259 | }; 260 | /* End XCConfigurationList section */ 261 | }; 262 | rootObject = 7877A4381D1B672B005AEBAC /* Project object */; 263 | } 264 | -------------------------------------------------------------------------------- /PSTModernizer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PSTModernizer/1.0.0/PSTModernizer.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint PSTModernizer.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | 6 | Pod::Spec.new do |s| 7 | s.name = 'PSTModernizer' 8 | s.version = '1.0.0' 9 | s.summary = 'Makes it easier to support older versions of iOS by fixing things and adding missing methods' 10 | s.description = <<-DESC 11 | PSTModernizer carefully applies patches to UIKit and related Apple frameworks to fix known radars with the least impact. The current set of patches just applies to iOS 9 and nothing is executed on iOS 10, as the bugs have been fixed there. 12 | DESC 13 | 14 | s.homepage = 'https://github.com/PSPDFKit-labs/PSTModernizer' 15 | s.license = { :type => 'MIT', :file => 'LICENSE' } 16 | s.author = { 'Peter Steinberger, PSPDFKit' => 'https://pspdfkit.com/' } 17 | s.source = { :git => 'https://github.com/PSPDFKit-labs/PSTModernizer.git', :tag => s.version.to_s } 18 | s.source_files = 'PSTModernizer/**/*' 19 | s.social_media_url = 'https://twitter.com/steipete' 20 | 21 | s.ios.deployment_target = '9.0' 22 | s.tvos.deployment_target = '9.0' 23 | s.xcconfig = { 'CLANG_MODULES_AUTOLINK' => 'YES' } 24 | 25 | end 26 | -------------------------------------------------------------------------------- /PSTModernizer/PSTModernizer.h: -------------------------------------------------------------------------------- 1 | // 2 | // PSTModernizer.h 3 | // PSTModernizer 4 | // 5 | // Created by Peter Steinberger on 23/06/16. 6 | // Copyright © 2016 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /// Patches the runtime as soon as this class is linked within the `load` path. 12 | @interface PSTModernizer : NSObject 13 | 14 | /// Call this early enough - ideally in your AppDelegate. 15 | + (void)installModernizer; 16 | 17 | /// Returns the version of the modernizer. 18 | + (double)version; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /PSTModernizer/PSTModernizer.mm: -------------------------------------------------------------------------------- 1 | // 2 | // PSTModernizer.mm 3 | // PSTModernizer 4 | // 5 | // Created by Peter Steinberger on 23/06/16. 6 | // Copyright © 2016 PSPDFKit GmbH. All rights reserved. 7 | // 8 | 9 | #import "PSTModernizer.h" 10 | #import 11 | #import 12 | #import 13 | #import 14 | 15 | // Hello, Swift :) 16 | #if defined(__cplusplus) 17 | #define let const auto 18 | #else 19 | // Works as of Xcode 8 20 | #define let const __auto_type 21 | #endif 22 | 23 | #define PSTClassObfuscate(...) NSClassFromString([NSString stringWithFormat:__VA_ARGS__]) 24 | #define PSTSELObfuscate(...) NSSelectorFromString([NSString stringWithFormat:__VA_ARGS__]) 25 | 26 | // iOS 10 compatibility 27 | #ifndef kCFCoreFoundationVersionNumber_iOS_10_0 28 | #define kCFCoreFoundationVersionNumber_iOS_10_0 1300.0 29 | #endif 30 | 31 | #define PST_IS_IOS10_0_OR_GREATER (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_10_0) 32 | 33 | #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000 34 | #define PST_IF_IOS10_0_OR_GREATER(...) \ 35 | if (PST_IS_IOS10_0_OR_GREATER) { \ 36 | PST_PARTIAL_AVAILABILITY_BEGIN \ 37 | __VA_ARGS__ \ 38 | PST_PARTIAL_AVAILABILITY_END } 39 | #else 40 | #define PST_IF_IOS10_0_OR_GREATER(...) 41 | #endif 42 | 43 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000 44 | #define PST_IF_PRE_IOS10_0(...) \ 45 | if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_10_0) { \ 46 | PST_PARTIAL_AVAILABILITY_BEGIN \ 47 | __VA_ARGS__ \ 48 | PST_PARTIAL_AVAILABILITY_END } 49 | #else 50 | #define PST_IF_PRE_IOS10_0(...) 51 | #endif 52 | 53 | #define PSTLogError NSLog 54 | #define PSTLogWarning NSLog 55 | 56 | @implementation PSTModernizer 57 | 58 | + (double)version { 59 | return 1000.0; 60 | } 61 | 62 | + (void)installModernizer { 63 | static dispatch_once_t onceToken; 64 | dispatch_once(&onceToken, ^{ 65 | [self installModernizerOnce]; 66 | }); 67 | } 68 | 69 | + (void)installModernizerOnce { 70 | // Define this class in the runtime to block the modernizer being called. 71 | if (NSClassFromString(@"PSTModernizerDisabled")) { 72 | return; 73 | } 74 | 75 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000 76 | 77 | // Fixes rdar://26295020: Action sheets presented for links don’t work in presented view controllers. 78 | // This has been fixed in iOS 10b1. 79 | PSTInstallWorkaroundForSheetPresentationRdar26295020(); 80 | 81 | // UIImage has threading issues under iOS 9. 82 | // See https://github.com/AFNetworking/AFNetworking/issues/2572#issuecomment-227895102 83 | // This has been fixed in iOS 10b1 84 | PSTAddLockingToUIImageRdar26954460(); 85 | 86 | #endif 87 | 88 | // In anticipation that we'll find bugs in iOS 10 that we run as well, not everything is blocked when you compile with iOS 10 only. 89 | NSLog(@"%@ version %.0f installed.", NSStringFromClass(self.class), self.version); 90 | } 91 | 92 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000 93 | 94 | static void PSTInstallWorkaroundForSheetPresentationRdar26295020() { 95 | // This has been fixed in iOS 10b1 so it's only necessary for older versions of iOS. 96 | PST_IF_IOS10_0_OR_GREATER(return;) 97 | 98 | __block auto removeWorkaround = ^{}; 99 | let installWorkaround = ^{ 100 | let presentSEL = @selector(presentViewController:animated:completion:); 101 | const __block IMP origIMP = pst_swizzleSelectorWithBlock(UIViewController.class, presentSEL, ^(UIViewController *_self, id vC, BOOL animated, id completion) { 102 | while (_self.presentedViewController) { 103 | _self = _self.presentedViewController; 104 | } 105 | ((void (*)(id, SEL, id, BOOL, id))origIMP)(_self, presentSEL, vC, animated, completion); 106 | }); 107 | if (origIMP) { 108 | removeWorkaround = ^{ 109 | pst_swizzleSelector(UIViewController.class, presentSEL, origIMP); 110 | }; 111 | } 112 | }; 113 | 114 | let presentSheetSEL = PSTSELObfuscate(@"present%@FromRect:", @"Sheet"); 115 | let swizzleOnClass = ^(Class klass) { 116 | if (!klass) { 117 | PSTLogWarning(@"Unable to install workaround for rdar://26295020."); 118 | return; 119 | } 120 | __block IMP origIMP = pst_swizzleSelectorWithBlock(klass, presentSheetSEL, ^(id _self, CGRect rect) { 121 | // Before calling the original implementation, we swizzle the presentation logic on UIViewController 122 | installWorkaround(); 123 | // UIKit later presents the sheet on [view.window rootViewController]; 124 | // See https://github.com/WebKit/webkit/blob/1aceb9ed7a42d0a5ed11558c72bcd57068b642e7/Source/WebKit2/UIProcess/ios/WKActionSheet.mm#L102 125 | // Our workaround forwards this to the topmost presentedViewController instead. 126 | ((void (*)(id, SEL, CGRect))origIMP)(_self, presentSheetSEL, rect); 127 | // Cleaning up again - this workaround would swallow bugs if we let it be there. 128 | removeWorkaround(); 129 | }); 130 | }; 131 | swizzleOnClass(PSTClassObfuscate(@"_%@%@AlertController", @"UI", @"Rotating")); 132 | 133 | // WKWebView might not be loaded, then we can't patch it. 134 | if (let wkWebViewClass = PSTClassObfuscate(@"%@ActionSheet", @"WK")) { 135 | swizzleOnClass(wkWebViewClass); 136 | } 137 | } 138 | 139 | static void PSTAddLockingToUIImageRdar26954460() { 140 | // This has been fixed in iOS 10b1 so it's only necessary for older versions of iOS. 141 | PST_IF_IOS10_0_OR_GREATER(return;) 142 | 143 | // The dictionary that UITraitCollectionCacheForBuiltinStorage returns 144 | // is not thread safe. We can't easily hook C methods, so we lock the main initializer 145 | // where the cache is being used. This will not cover all races around UITraitCollection, 146 | // however with this level of granularity UIImage creation will work as expected. 147 | // 148 | // Overriding all calls of UITraitCollectionCacheForBuiltinStorage would require 149 | // using private API. 150 | 151 | static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; 152 | let displayScaleSEL = @selector(traitCollectionWithDisplayScale:); 153 | __block IMP origIMP = pst_swizzleSelectorWithBlock(object_getClass(UITraitCollection.class), displayScaleSEL, ^id(id _self, CGFloat scale) { 154 | pthread_mutex_lock(&mutex); 155 | id result = ((id (*)(id, SEL, CGFloat))origIMP)(_self, displayScaleSEL, scale); 156 | pthread_mutex_unlock(&mutex); 157 | return result; 158 | }); 159 | } 160 | 161 | #endif 162 | 163 | /////////////////////////////////////////////////////////////////////////////////////////// 164 | #pragma mark - Swizzle 165 | 166 | static IMP pst_swizzleSelectorWithBlock(Class clazz, SEL selector, id newImplementationBlock) { 167 | const IMP newImplementation = imp_implementationWithBlock(newImplementationBlock); 168 | return pst_swizzleSelector(clazz, selector, newImplementation); 169 | } 170 | 171 | static IMP pst_swizzleSelector(Class clazz, SEL selector, IMP newImplementation) { 172 | NSCParameterAssert(clazz); 173 | NSCParameterAssert(selector); 174 | NSCParameterAssert(newImplementation); 175 | 176 | // If the method does not exist for this class, do nothing. 177 | Method method = class_getInstanceMethod(clazz, selector); 178 | if (!method) { 179 | PSTLogError(@"%@ doesn't exist in %@.", NSStringFromSelector(selector), NSStringFromClass(clazz)); 180 | // Cannot swizzle methods which are not implemented by the class or one of its parents. 181 | return NULL; 182 | } 183 | 184 | // Make sure the class implements the method. If this is not the case, inject an implementation, only calling 'super'. 185 | const char *types = method_getTypeEncoding(method); 186 | 187 | @synchronized (clazz) { 188 | // class_addMethod will simply return NO if the method is already implemented. 189 | #if !defined(__arm64__) 190 | // Sufficiently large struct 191 | typedef struct LargeStruct_ { 192 | char dummy[16]; 193 | } LargeStruct; 194 | 195 | NSUInteger retSize = 0; 196 | NSGetSizeAndAlignment(types, &retSize, NULL); 197 | 198 | // Large structs on 32-bit architectures 199 | if (sizeof(void *) == 4 && types[0] == _C_STRUCT_B && retSize != 1 && retSize != 2 && retSize != 4 && retSize != 8) { 200 | class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) { 201 | struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)}; 202 | return ((LargeStruct (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper_stret)(&super, selector, argp); 203 | }), types); 204 | } 205 | // All other cases 206 | else { 207 | #endif 208 | class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) { 209 | struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)}; 210 | return ((id (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper)(&super, selector, argp); 211 | }), types); 212 | #if !defined(__arm64__) 213 | } 214 | #endif 215 | // Swizzling 216 | return class_replaceMethod(clazz, selector, newImplementation, types); 217 | } 218 | } 219 | 220 | @end 221 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PSTModernizer 2 | 3 | PSTModernizer carefully applies patches to UIKit and related Apple frameworks to fix known radars with the least impact. 4 | The current set of patches just applies to iOS 9 and nothing is executed on iOS 10, as the bugs have been fixed there. 5 | 6 | This project later on might also patch-add a few essential missing elements in iOS 10 if there's need - currently the focus is just to fix various bugs. 7 | 8 | ## Installation 9 | 10 | Simply copy `PSTModernizer.h/mm` into your project, then call `[PSTModernizer installModernizer];` somewhere early, ideally in your app delegate. 11 | 12 | Currently covers following radars (all of them have been fixed in iOS 10) 13 | 14 | * [26954460 - UIImage creation has a race conditon on background threads.](https://openradar.appspot.com/26954460)
15 | The radar is actually for fixing the documentation, [the original issue is explained here.](https://pspdfkit.com/blog/2016/investigating-thread-saftey-of-UIImage/) 16 | * [26295020 - Action sheets presented for links/numbers don’t work in presented view controllers](https://openradar.appspot.com/26295020) 17 | 18 | You can simply delete the workarounds that do not affect you - every workaround is self-contained and can be individually removed. 19 | 20 | ## FAQ 21 | 22 | Q: *Why?*
23 | A: Because we need to support older UIKit versions. [At PSPDFKit we support n-1](https://pspdfkit.com/guides/ios/current/announcements/version-support/), so we're just about to drop iOS 8 and will likely use something like this for our next major release. This project should make it easier to patch up the system so you need to write less ugly code. 24 | 25 | Q: *Isn't that partly using private API?*
26 | A: Partly. The goal is to write workarounds using just public API, but it's not always possible or would lead to much more scary code. If we revert to private API, we use it for good, not evil. You decide. Since we restrict API usage to versions that have been already released and don't apply it to unknown versions, the risk is minimal. If you do find a way to patch things without private API that are similary effective and not 10x the code, please submit a pull request. We also only use it to work around bugs, not for accessing new features. Of course I can't make any guarantees if Apple accepts this on app review. (but so far we have not gotten a report that blocks this, and worst case you disable the parts that are private and just have a slightly more broken app.) 27 | 28 | ## License 29 | 30 | The MIT License (MIT) 31 | 32 | Copyright (c) 2016 Peter Steinberger, PSPDFKit GmbH. 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy 35 | of this software and associated documentation files (the "Software"), to deal 36 | in the Software without restriction, including without limitation the rights 37 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | copies of the Software, and to permit persons to whom the Software is 39 | furnished to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in all 42 | copies or substantial portions of the Software. 43 | 44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 50 | SOFTWARE. 51 | 52 | ## About 53 | 54 | 55 | 56 | 57 | 58 | This project is maintained and funded by [PSPDFKit](https://pspdfkit.com/). 59 | 60 | See [our other open source projects](https://github.com/PSPDFKit-labs), read [our blog](https://pspdfkit.com/blog/) or say hello on Twitter ([@PSPDFKit](https://twitter.com/pspdfkit)). 61 | --------------------------------------------------------------------------------