Repository: PSPDFKit-labs/PSTModernizer
Branch: master
Commit: 2f1787c92f90
Files: 36
Total size: 81.9 KB
Directory structure:
gitextract_0g2bpret/
├── .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/
│ │ ├── AppDelegate.h
│ │ ├── AppDelegate.m
│ │ ├── Assets.xcassets/
│ │ │ └── AppIcon.appiconset/
│ │ │ └── Contents.json
│ │ ├── Base.lproj/
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── ViewController.h
│ │ ├── ViewController.m
│ │ └── main.m
│ └── UIImageWithDataMultithreaded.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ └── contents.xcworkspacedata
├── LICENSE
├── PSTModernizer/
│ ├── 1.0.0/
│ │ └── PSTModernizer.podspec
│ ├── PSTModernizer.h
│ └── PSTModernizer.mm
├── PSTModernizer.podspec
├── PSTModernizer.xcodeproj/
│ ├── project.pbxproj
│ └── project.xcworkspace/
│ └── contents.xcworkspacedata
└── README.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
*.moved-aside
*.xcuserstate
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
fastlane/report.xml
fastlane/screenshots
#Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode
iOSInjectionProject/
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/ActionSheetPresentationIssue.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
780CAFD01CE9C18B00CBBF23 /* Workaround.mm in Sources */ = {isa = PBXBuildFile; fileRef = 780CAFCF1CE9C18B00CBBF23 /* Workaround.mm */; };
7881AA831D1B7D7D005EC1FF /* PSTModernizer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7881AA821D1B7D7D005EC1FF /* PSTModernizer.mm */; };
A51CD1E51B7CE37500C6E9C3 /* TextViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A51CD1E41B7CE37500C6E9C3 /* TextViewController.m */; };
A56313591CE974B700191654 /* WebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A56313581CE974B700191654 /* WebViewController.m */; };
A59360431A22678800711C3F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A59360421A22678700711C3F /* main.m */; };
A59360461A22678800711C3F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A59360451A22678800711C3F /* AppDelegate.m */; };
A593604E1A22678800711C3F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A593604D1A22678800711C3F /* Images.xcassets */; };
A59360511A22678800711C3F /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A593604F1A22678800711C3F /* LaunchScreen.xib */; };
A5E68B4F1CE9899A0028420D /* NewerWebViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A5E68B4E1CE9899A0028420D /* NewerWebViewController.m */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
780CAFCF1CE9C18B00CBBF23 /* Workaround.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Workaround.mm; sourceTree = "<group>"; };
780CAFD11CE9C1EB00CBBF23 /* Workaround.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Workaround.h; sourceTree = "<group>"; };
7881AA811D1B7D7D005EC1FF /* PSTModernizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSTModernizer.h; sourceTree = "<group>"; };
7881AA821D1B7D7D005EC1FF /* PSTModernizer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PSTModernizer.mm; sourceTree = "<group>"; };
A51CD1E31B7CE37500C6E9C3 /* TextViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextViewController.h; sourceTree = "<group>"; };
A51CD1E41B7CE37500C6E9C3 /* TextViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextViewController.m; sourceTree = "<group>"; };
A56313571CE974B700191654 /* WebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewController.h; sourceTree = "<group>"; };
A56313581CE974B700191654 /* WebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewController.m; sourceTree = "<group>"; };
A593603D1A22678700711C3F /* PresentationPlayground.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PresentationPlayground.app; sourceTree = BUILT_PRODUCTS_DIR; };
A59360411A22678700711C3F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A59360421A22678700711C3F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
A59360441A22678800711C3F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
A59360451A22678800711C3F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
A593604D1A22678800711C3F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
A59360501A22678800711C3F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
A5E68B4D1CE9899A0028420D /* NewerWebViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewerWebViewController.h; sourceTree = "<group>"; };
A5E68B4E1CE9899A0028420D /* NewerWebViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewerWebViewController.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
A593603A1A22678700711C3F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7881AA801D1B7D7D005EC1FF /* PSTModernizer */ = {
isa = PBXGroup;
children = (
7881AA811D1B7D7D005EC1FF /* PSTModernizer.h */,
7881AA821D1B7D7D005EC1FF /* PSTModernizer.mm */,
);
name = PSTModernizer;
path = ../../../PSTModernizer;
sourceTree = "<group>";
};
A59360341A22678700711C3F = {
isa = PBXGroup;
children = (
A59360661A2269BE00711C3F /* Source */,
A59360671A2269C200711C3F /* Resources */,
A593603E1A22678700711C3F /* Products */,
);
sourceTree = "<group>";
};
A593603E1A22678700711C3F /* Products */ = {
isa = PBXGroup;
children = (
A593603D1A22678700711C3F /* PresentationPlayground.app */,
);
name = Products;
sourceTree = "<group>";
};
A59360661A2269BE00711C3F /* Source */ = {
isa = PBXGroup;
children = (
7881AA801D1B7D7D005EC1FF /* PSTModernizer */,
A59360421A22678700711C3F /* main.m */,
A59360441A22678800711C3F /* AppDelegate.h */,
780CAFD11CE9C1EB00CBBF23 /* Workaround.h */,
780CAFCF1CE9C18B00CBBF23 /* Workaround.mm */,
A59360451A22678800711C3F /* AppDelegate.m */,
A51CD1E31B7CE37500C6E9C3 /* TextViewController.h */,
A51CD1E41B7CE37500C6E9C3 /* TextViewController.m */,
A56313571CE974B700191654 /* WebViewController.h */,
A56313581CE974B700191654 /* WebViewController.m */,
A5E68B4D1CE9899A0028420D /* NewerWebViewController.h */,
A5E68B4E1CE9899A0028420D /* NewerWebViewController.m */,
);
path = Source;
sourceTree = "<group>";
};
A59360671A2269C200711C3F /* Resources */ = {
isa = PBXGroup;
children = (
A59360411A22678700711C3F /* Info.plist */,
A593604D1A22678800711C3F /* Images.xcassets */,
A593604F1A22678800711C3F /* LaunchScreen.xib */,
);
path = Resources;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
A593603C1A22678700711C3F /* PresentationPlayground */ = {
isa = PBXNativeTarget;
buildConfigurationList = A59360601A22678800711C3F /* Build configuration list for PBXNativeTarget "PresentationPlayground" */;
buildPhases = (
A59360391A22678700711C3F /* Sources */,
A593603A1A22678700711C3F /* Frameworks */,
A593603B1A22678700711C3F /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = PresentationPlayground;
productName = PresentationPlayground;
productReference = A593603D1A22678700711C3F /* PresentationPlayground.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
A59360351A22678700711C3F /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Douglas Hill";
TargetAttributes = {
A593603C1A22678700711C3F = {
CreatedOnToolsVersion = 6.1;
};
};
};
buildConfigurationList = A59360381A22678700711C3F /* Build configuration list for PBXProject "ActionSheetPresentationIssue" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = A59360341A22678700711C3F;
productRefGroup = A593603E1A22678700711C3F /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
A593603C1A22678700711C3F /* PresentationPlayground */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
A593603B1A22678700711C3F /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A59360511A22678800711C3F /* LaunchScreen.xib in Resources */,
A593604E1A22678800711C3F /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
A59360391A22678700711C3F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A59360461A22678800711C3F /* AppDelegate.m in Sources */,
A59360431A22678800711C3F /* main.m in Sources */,
A5E68B4F1CE9899A0028420D /* NewerWebViewController.m in Sources */,
780CAFD01CE9C18B00CBBF23 /* Workaround.mm in Sources */,
A56313591CE974B700191654 /* WebViewController.m in Sources */,
A51CD1E51B7CE37500C6E9C3 /* TextViewController.m in Sources */,
7881AA831D1B7D7D005EC1FF /* PSTModernizer.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
A593604F1A22678800711C3F /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
A59360501A22678800711C3F /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
A593605E1A22678800711C3F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
A593605F1A22678800711C3F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
A59360611A22678800711C3F /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Resources/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.pspdfkit.radar.ActionSheetPresentation;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
A59360621A22678800711C3F /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = Resources/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.pspdfkit.radar.ActionSheetPresentation;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
A59360381A22678700711C3F /* Build configuration list for PBXProject "ActionSheetPresentationIssue" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A593605E1A22678800711C3F /* Debug */,
A593605F1A22678800711C3F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A59360601A22678800711C3F /* Build configuration list for PBXNativeTarget "PresentationPlayground" */ = {
isa = XCConfigurationList;
buildConfigurations = (
A59360611A22678800711C3F /* Debug */,
A59360621A22678800711C3F /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = A59360351A22678700711C3F /* Project object */;
}
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/ActionSheetPresentationIssue.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:PresentationPlayground.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Resources/Base.lproj/LaunchScreen.xib
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="10117" systemVersion="15E65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="PSPDFKit GmbH (Peter Steinberger, Douglas Hill)" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="ActionSheet Presentation" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="22" y="140" width="438" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Resources/Images.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Resources/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/AppDelegate.h
================================================
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/AppDelegate.m
================================================
#import "AppDelegate.h"
#import "TextViewController.h"
#import "WebViewController.h"
#import "NewerWebViewController.h"
#import "Workaround.h"
#import "PSTModernizer.h"
@implementation AppDelegate
@synthesize window = _window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//PSPDFInstallWorkaroundForSheetPresentation();
[PSTModernizer installModernizer];
self.window = [[UIWindow alloc] init];
UIViewController *firstTextViewController = [[TextViewController alloc] init];
firstTextViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present Second" style:UIBarButtonItemStylePlain target:self action:@selector(presentSecondTextView:)];
firstTextViewController.title = @"UITextView";
firstTextViewController.navigationItem.title = @"First";
UIViewController *firstWebViewController = [[WebViewController alloc] init];
firstWebViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present Second" style:UIBarButtonItemStylePlain target:self action:@selector(presentSecondWebView:)];
firstWebViewController.title = @"UIWebView";
firstWebViewController.navigationItem.title = @"First";
UIViewController *firstNewerWebViewController = [[NewerWebViewController alloc] init];
firstNewerWebViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Present Second" style:UIBarButtonItemStylePlain target:self action:@selector(presentSecondNewerWebView:)];
firstNewerWebViewController.title = @"WKWebView";
firstNewerWebViewController.navigationItem.title = @"First";
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.viewControllers = @[
[[UINavigationController alloc] initWithRootViewController:firstTextViewController],
[[UINavigationController alloc] initWithRootViewController:firstWebViewController],
[[UINavigationController alloc] initWithRootViewController:firstNewerWebViewController],
];
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)presentSecondTextView:(id)sender {
[self presentSecondViewControllerOfClass:[TextViewController class]];
}
- (void)presentSecondWebView:(id)sender {
[self presentSecondViewControllerOfClass:[WebViewController class]];
}
- (void)presentSecondNewerWebView:(id)sender {
[self presentSecondViewControllerOfClass:[NewerWebViewController class]];
}
- (void)presentSecondViewControllerOfClass:(Class)klass {
UIViewController *secondViewController = [[klass alloc] init];
secondViewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismiss:)];
secondViewController.title = @"Second";
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:secondViewController];
navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
[self.window.rootViewController presentViewController:navigationController animated:YES completion:nil];
}
- (void)dismiss:(id)sender {
[self.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
}
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/NewerWebViewController.h
================================================
#import <UIKit/UIKit.h>
@interface NewerWebViewController : UIViewController
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/NewerWebViewController.m
================================================
#import "NewerWebViewController.h"
@import WebKit;
@implementation NewerWebViewController
- (void)loadView {
WKWebView *textView = [[WKWebView alloc] init];
[textView loadHTMLString:@"<p>This is a WKWebView with an HTML link: <a href=\"https://pspdfkit.com\">PSPDFKit website</a></p>" baseURL:nil];
self.view = textView;
}
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/TextViewController.h
================================================
#import <UIKit/UIKit.h>
@interface TextViewController : UIViewController
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/TextViewController.m
================================================
#import "TextViewController.h"
@implementation TextViewController
- (void)loadView {
UITextView *textView = [[UITextView alloc] init];
textView.dataDetectorTypes = UIDataDetectorTypeAll;
textView.editable = NO;
textView.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
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";
self.view = textView;
}
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/WebViewController.h
================================================
#import <UIKit/UIKit.h>
@interface WebViewController : UIViewController
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/WebViewController.m
================================================
#import "WebViewController.h"
@implementation WebViewController
- (void)loadView {
UIWebView *textView = [[UIWebView alloc] init];
textView.dataDetectorTypes = UIDataDetectorTypeAll;
[textView loadHTMLString:@"<p>This is a UIWebView with a phone number: 01234 567890 and a detected web link: https://pspdfkit.com/ and an HTML link: <a href=\"https://pspdfkit.com\">PSPDFKit website</a> and a time: 15:40 tomorrow and an address: 1 Infinite Loop Cupertino CA 95014 United States</p>" baseURL:nil];
self.view = textView;
}
@end
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/Workaround.h
================================================
//
// Workaround.h
// PresentationPlayground
//
// Created by Peter Steinberger on 16/05/16.
//
#import <Foundation/Foundation.h>
FOUNDATION_EXPORT void PSPDFInstallWorkaroundForSheetPresentation(void);
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/Workaround.mm
================================================
//
// Workaround.m
// PresentationPlayground
//
// Created by Peter Steinberger on 16/05/16.
//
#import "Workaround.h"
#import <UIKit/UIKit.h>
#import <objc/message.h>
static IMP pspdf_swizzleSelector(Class clazz, SEL selector, IMP newImplementation) {
NSCParameterAssert(clazz);
NSCParameterAssert(selector);
NSCParameterAssert(newImplementation);
// If the method does not exist for this class, do nothing.
const Method method = class_getInstanceMethod(clazz, selector);
if (!method) {
NSLog(@"%@ doesn't exist in %@.", NSStringFromSelector(selector), NSStringFromClass(clazz));
// Cannot swizzle methods which are not implemented by the class or one of its parents.
return NULL;
}
// Make sure the class implements the method. If this is not the case, inject an implementation, only calling 'super'.
const char *types = method_getTypeEncoding(method);
@synchronized (clazz) {
// class_addMethod will simply return NO if the method is already implemented.
#if !defined(__arm64__)
// Sufficiently large struct
typedef struct LargeStruct_ {
char dummy[16];
} LargeStruct;
NSUInteger retSize = 0;
NSGetSizeAndAlignment(types, &retSize, NULL);
// Large structs on 32-bit architectures
if (sizeof(void *) == 4 && types[0] == _C_STRUCT_B && retSize != 1 && retSize != 2 && retSize != 4 && retSize != 8) {
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)};
return ((LargeStruct (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper_stret)(&super, selector, argp);
}), types);
}
// All other cases
else {
#endif
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)};
return ((id (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper)(&super, selector, argp);
}), types);
#if !defined(__arm64__)
}
#endif
// Swizzling
return class_replaceMethod(clazz, selector, newImplementation, types);
}
}
IMP pspdf_swizzleSelectorWithBlock(Class clazz, SEL selector, id newImplementationBlock) {
IMP const newImplementation = imp_implementationWithBlock(newImplementationBlock);
return pspdf_swizzleSelector(clazz, selector, newImplementation);
}
FOUNDATION_EXPORT void PSPDFInstallWorkaroundForSheetPresentation(void) {
__block auto removeWorkaround = ^{};
const auto installWorkaround = ^{
const SEL presentSEL = @selector(presentViewController:animated:completion:);
__block IMP origIMP = pspdf_swizzleSelectorWithBlock(UIViewController.class, presentSEL, ^(UIViewController *self, id vC, BOOL animated, id completion) {
UIViewController *targetVC = self;
while (targetVC.presentedViewController) {
targetVC = targetVC.presentedViewController;
}
((void (*)(id, SEL, id, BOOL, id))origIMP)(targetVC, presentSEL, vC, animated, completion);
});
removeWorkaround = ^{
pspdf_swizzleSelector(UIViewController.class, presentSEL, origIMP);
};
};
// Fixes rdar:// <TODO>
const SEL presentSheetSEL = NSSelectorFromString(@"presentSheetFromRect:");
const auto swizzleOnClass = ^(Class klass) {
const __block IMP origIMP = pspdf_swizzleSelectorWithBlock(klass, presentSheetSEL, ^(id self, CGRect rect) {
// Before calling the original implementation, we swizzle the presentation logic on UIViewController
installWorkaround();
// UIKit later presents the sheet on [view.window rootViewController];
// Our workaround forwards this to the topmost presentedViewController instead.
((void (*)(id, SEL, CGRect))origIMP)(self, presentSheetSEL, rect);
// Cleaning up again - this workaround would swallow bugs if we let it be there.
removeWorkaround();
});
};
swizzleOnClass(NSClassFromString(@"_UIRotatingAlertController"));
swizzleOnClass(NSClassFromString(@"WKActionSheet"));
}
================================================
FILE: Example/26295020, 26294823 - Action Sheet Presentation/Source/main.m
================================================
@import UIKit;
#import "AppDelegate.h"
int main(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/AppDelegate.h
================================================
//
// AppDelegate.h
// UIImageWithDataMultithreaded
//
// Created by Peter Steinberger on 22/06/16.
// Copyright © 2016 PSPDFKit GmbH. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/AppDelegate.m
================================================
//
// AppDelegate.m
// UIImageWithDataMultithreaded
//
// Created by Peter Steinberger on 22/06/16.
// Copyright © 2016 PSPDFKit GmbH. All rights reserved.
//
#import "AppDelegate.h"
#import "PSTModernizer.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[PSTModernizer installModernizer];
return YES;
}
@end
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Assets.xcassets/AppIcon.appiconset/Contents.json
================================================
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Base.lproj/LaunchScreen.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8150" systemVersion="15A204g" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8122"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Base.lproj/Main.storyboard
================================================
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/ViewController.h
================================================
//
// ViewController.h
// UIImageWithDataMultithreaded
//
// Created by Peter Steinberger on 22/06/16.
// Copyright © 2016 PSPDFKit GmbH. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/ViewController.m
================================================
//
// ViewController.m
// UIImageWithDataMultithreaded
//
// Created by Peter Steinberger on 22/06/16.
// Copyright © 2016 PSPDFKit GmbH. All rights reserved.
//
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"meme" withExtension:@"png"];
NSData *data = [NSData dataWithContentsOfURL:fileURL];
dispatch_apply(10000000, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t idx) {
@autoreleasepool {
UIImage *image = [UIImage imageWithData:data];
assert(image != nil);
}
});
}
@end
#import <objc/runtime.h>
#import <objc/message.h>
// Compile-time selector checks.
#if DEBUG
#define PROPERTY(propName) NSStringFromSelector(@selector(propName))
#else
#define PROPERTY(propName) @#propName
#endif
// http://www.mikeash.com/pyblog/friday-qa-2010-01-29-method-replacement-for-fun-and-profit.html
BOOL PSPDFReplaceMethodWithBlock(Class c, SEL origSEL, SEL newSEL, id block) {
NSCParameterAssert(c);
NSCParameterAssert(origSEL);
NSCParameterAssert(newSEL);
NSCParameterAssert(block);
if ([c instancesRespondToSelector:newSEL]) return YES; // Selector already implemented, skip silently.
Method origMethod = class_getInstanceMethod(c, origSEL);
// Add the new method.
IMP impl = imp_implementationWithBlock(block);
if (!class_addMethod(c, newSEL, impl, method_getTypeEncoding(origMethod))) {
NSLog(@"Failed to add method: %@ on %@", NSStringFromSelector(newSEL), c);
return NO;
}else {
Method newMethod = class_getInstanceMethod(c, newSEL);
// If original doesn't implement the method we want to swizzle, create it.
if (class_addMethod(c, origSEL, method_getImplementation(newMethod), method_getTypeEncoding(origMethod))) {
class_replaceMethod(c, newSEL, method_getImplementation(origMethod), method_getTypeEncoding(newMethod));
}else {
method_exchangeImplementations(origMethod, newMethod);
}
}
return YES;
}
SEL _PSPDFPrefixedSelector(SEL selector) {
return NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", NSStringFromSelector(selector)]);
}
#define PSPDFAssert(expression, ...) \
do { if(!(expression)) { \
NSLog(@"%@", [NSString stringWithFormat: @"Assertion failure: %s in %s on line %s:%d. %@", #expression, __PRETTY_FUNCTION__, __FILE__, __LINE__, [NSString stringWithFormat:@"" __VA_ARGS__]]); \
abort(); }} while(0)
void PSPDFAssertIfNotMainThread(void) {
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);
}
__attribute__((constructor)) static void PSPDFUIKitMainThreadGuard(void) {
@autoreleasepool {
for (NSString *selStr in @[PROPERTY(setNeedsLayout), PROPERTY(setNeedsDisplay), PROPERTY(setNeedsDisplayInRect:)]) {
SEL selector = NSSelectorFromString(selStr);
SEL newSelector = NSSelectorFromString([NSString stringWithFormat:@"pspdf_%@", selStr]);
if ([selStr hasSuffix:@":"]) {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self, CGRect r) {
// Check for window, since *some* UIKit methods are indeed thread safe.
// https://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iPhoneOS4.html
/*
Drawing to a graphics context in UIKit is now thread-safe. Specifically:
The routines used to access and manipulate the graphics context can now correctly handle contexts residing on different threads.
String and image drawing is now thread-safe.
Using color and font objects in multiple threads is now safe to do.
*/
if (_self.window) PSPDFAssertIfNotMainThread();
((void ( *)(id, SEL, CGRect))objc_msgSend)(_self, newSelector, r);
});
}else {
PSPDFReplaceMethodWithBlock(UIView.class, selector, newSelector, ^(__unsafe_unretained UIView *_self) {
if (_self.window) {
if (!NSThread.isMainThread) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
dispatch_queue_t queue = dispatch_get_current_queue();
#pragma clang diagnostic pop
// iOS 8 layouts the MFMailComposeController in a background thread on an UIKit queue.
// https://github.com/PSPDFKit/PSPDFKit/issues/1423
if (!queue || !strstr(dispatch_queue_get_label(queue), "UIKit")) {
PSPDFAssertIfNotMainThread();
}
}
}
((void ( *)(id, SEL))objc_msgSend)(_self, newSelector);
});
}
}
}
}
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/main.m
================================================
//
// main.m
// UIImageWithDataMultithreaded
//
// Created by Peter Steinberger on 22/06/16.
// Copyright © 2016 PSPDFKit GmbH. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
7881AA7F1D1B7AE4005EC1FF /* PSTModernizer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7881AA7E1D1B7AE4005EC1FF /* PSTModernizer.mm */; };
78A341181D1B283D00858C36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A341171D1B283D00858C36 /* main.m */; };
78A3411B1D1B283D00858C36 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A3411A1D1B283D00858C36 /* AppDelegate.m */; };
78A3411E1D1B283D00858C36 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 78A3411D1D1B283D00858C36 /* ViewController.m */; };
78A341211D1B283D00858C36 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78A3411F1D1B283D00858C36 /* Main.storyboard */; };
78A341231D1B283D00858C36 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 78A341221D1B283D00858C36 /* Assets.xcassets */; };
78A341261D1B283D00858C36 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 78A341241D1B283D00858C36 /* LaunchScreen.storyboard */; };
78A3412E1D1B288900858C36 /* meme.png in Resources */ = {isa = PBXBuildFile; fileRef = 78A3412D1D1B288900858C36 /* meme.png */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
7881AA7D1D1B7AE4005EC1FF /* PSTModernizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSTModernizer.h; sourceTree = "<group>"; };
7881AA7E1D1B7AE4005EC1FF /* PSTModernizer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PSTModernizer.mm; sourceTree = "<group>"; };
78A341131D1B283D00858C36 /* UIImageWithDataMultithreaded.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIImageWithDataMultithreaded.app; sourceTree = BUILT_PRODUCTS_DIR; };
78A341171D1B283D00858C36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
78A341191D1B283D00858C36 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
78A3411A1D1B283D00858C36 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
78A3411C1D1B283D00858C36 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
78A3411D1D1B283D00858C36 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
78A341201D1B283D00858C36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
78A341221D1B283D00858C36 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
78A341251D1B283D00858C36 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
78A341271D1B283D00858C36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
78A3412D1D1B288900858C36 /* meme.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = meme.png; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
78A341101D1B283D00858C36 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7881AA7C1D1B7AE4005EC1FF /* PSTModernizer */ = {
isa = PBXGroup;
children = (
7881AA7D1D1B7AE4005EC1FF /* PSTModernizer.h */,
7881AA7E1D1B7AE4005EC1FF /* PSTModernizer.mm */,
);
name = PSTModernizer;
path = ../../../PSTModernizer;
sourceTree = "<group>";
};
78A3410A1D1B283D00858C36 = {
isa = PBXGroup;
children = (
78A341151D1B283D00858C36 /* UIImageWithDataMultithreaded */,
78A341141D1B283D00858C36 /* Products */,
);
sourceTree = "<group>";
};
78A341141D1B283D00858C36 /* Products */ = {
isa = PBXGroup;
children = (
78A341131D1B283D00858C36 /* UIImageWithDataMultithreaded.app */,
);
name = Products;
sourceTree = "<group>";
};
78A341151D1B283D00858C36 /* UIImageWithDataMultithreaded */ = {
isa = PBXGroup;
children = (
7881AA7C1D1B7AE4005EC1FF /* PSTModernizer */,
78A3412D1D1B288900858C36 /* meme.png */,
78A341191D1B283D00858C36 /* AppDelegate.h */,
78A3411A1D1B283D00858C36 /* AppDelegate.m */,
78A3411C1D1B283D00858C36 /* ViewController.h */,
78A3411D1D1B283D00858C36 /* ViewController.m */,
78A3411F1D1B283D00858C36 /* Main.storyboard */,
78A341221D1B283D00858C36 /* Assets.xcassets */,
78A341241D1B283D00858C36 /* LaunchScreen.storyboard */,
78A341271D1B283D00858C36 /* Info.plist */,
78A341161D1B283D00858C36 /* Supporting Files */,
);
path = UIImageWithDataMultithreaded;
sourceTree = "<group>";
};
78A341161D1B283D00858C36 /* Supporting Files */ = {
isa = PBXGroup;
children = (
78A341171D1B283D00858C36 /* main.m */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
78A341121D1B283D00858C36 /* UIImageWithDataMultithreaded */ = {
isa = PBXNativeTarget;
buildConfigurationList = 78A3412A1D1B283D00858C36 /* Build configuration list for PBXNativeTarget "UIImageWithDataMultithreaded" */;
buildPhases = (
78A3410F1D1B283D00858C36 /* Sources */,
78A341101D1B283D00858C36 /* Frameworks */,
78A341111D1B283D00858C36 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = UIImageWithDataMultithreaded;
productName = UIImageWithDataMultithreaded;
productReference = 78A341131D1B283D00858C36 /* UIImageWithDataMultithreaded.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
78A3410B1D1B283D00858C36 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = "PSPDFKit GmbH";
TargetAttributes = {
78A341121D1B283D00858C36 = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 78A3410E1D1B283D00858C36 /* Build configuration list for PBXProject "UIImageWithDataMultithreaded" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 78A3410A1D1B283D00858C36;
productRefGroup = 78A341141D1B283D00858C36 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
78A341121D1B283D00858C36 /* UIImageWithDataMultithreaded */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
78A341111D1B283D00858C36 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
78A341261D1B283D00858C36 /* LaunchScreen.storyboard in Resources */,
78A341231D1B283D00858C36 /* Assets.xcassets in Resources */,
78A341211D1B283D00858C36 /* Main.storyboard in Resources */,
78A3412E1D1B288900858C36 /* meme.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
78A3410F1D1B283D00858C36 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
78A3411E1D1B283D00858C36 /* ViewController.m in Sources */,
78A3411B1D1B283D00858C36 /* AppDelegate.m in Sources */,
7881AA7F1D1B7AE4005EC1FF /* PSTModernizer.mm in Sources */,
78A341181D1B283D00858C36 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
78A3411F1D1B283D00858C36 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
78A341201D1B283D00858C36 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
78A341241D1B283D00858C36 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
78A341251D1B283D00858C36 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
78A341281D1B283D00858C36 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
78A341291D1B283D00858C36 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
78A3412B1D1B283D00858C36 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = UIImageWithDataMultithreaded/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = PSPDFKit.UIImageWithDataMultithreaded;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
78A3412C1D1B283D00858C36 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = UIImageWithDataMultithreaded/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = PSPDFKit.UIImageWithDataMultithreaded;
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
78A3410E1D1B283D00858C36 /* Build configuration list for PBXProject "UIImageWithDataMultithreaded" */ = {
isa = XCConfigurationList;
buildConfigurations = (
78A341281D1B283D00858C36 /* Debug */,
78A341291D1B283D00858C36 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
78A3412A1D1B283D00858C36 /* Build configuration list for PBXNativeTarget "UIImageWithDataMultithreaded" */ = {
isa = XCConfigurationList;
buildConfigurations = (
78A3412B1D1B283D00858C36 /* Debug */,
78A3412C1D1B283D00858C36 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 78A3410B1D1B283D00858C36 /* Project object */;
}
================================================
FILE: Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:UIImageWithDataMultithreaded.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 Peter Steinberger, PSPDFKit GmbH.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: PSTModernizer/1.0.0/PSTModernizer.podspec
================================================
#
# Be sure to run `pod lib lint PSTModernizer.podspec' to ensure this is a
# valid spec before submitting.
#
Pod::Spec.new do |s|
s.name = 'PSTModernizer'
s.version = '1.0.0'
s.summary = 'Makes it easier to support older versions of iOS by fixing things and adding missing methods'
s.description = <<-DESC
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.
DESC
s.homepage = 'https://github.com/PSPDFKit-labs/PSTModernizer'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'Peter Steinberger, PSPDFKit' => 'https://pspdfkit.com/' }
s.source = { :git => 'https://github.com/PSPDFKit-labs/PSTModernizer.git', :tag => s.version.to_s }
s.source_files = 'PSTModernizer/**/*'
s.social_media_url = 'https://twitter.com/steipete'
s.ios.deployment_target = '9.0'
s.tvos.deployment_target = '9.0'
s.xcconfig = { 'CLANG_MODULES_AUTOLINK' => 'YES' }
end
================================================
FILE: PSTModernizer/PSTModernizer.h
================================================
//
// PSTModernizer.h
// PSTModernizer
//
// Created by Peter Steinberger on 23/06/16.
// Copyright © 2016 PSPDFKit GmbH. All rights reserved.
//
#import <Foundation/Foundation.h>
/// Patches the runtime as soon as this class is linked within the `load` path.
@interface PSTModernizer : NSObject
/// Call this early enough - ideally in your AppDelegate.
+ (void)installModernizer;
/// Returns the version of the modernizer.
+ (double)version;
@end
================================================
FILE: PSTModernizer/PSTModernizer.mm
================================================
//
// PSTModernizer.mm
// PSTModernizer
//
// Created by Peter Steinberger on 23/06/16.
// Copyright © 2016 PSPDFKit GmbH. All rights reserved.
//
#import "PSTModernizer.h"
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import <objc/message.h>
#import <pthread.h>
// Hello, Swift :)
#if defined(__cplusplus)
#define let const auto
#else
// Works as of Xcode 8
#define let const __auto_type
#endif
#define PSTClassObfuscate(...) NSClassFromString([NSString stringWithFormat:__VA_ARGS__])
#define PSTSELObfuscate(...) NSSelectorFromString([NSString stringWithFormat:__VA_ARGS__])
// iOS 10 compatibility
#ifndef kCFCoreFoundationVersionNumber_iOS_10_0
#define kCFCoreFoundationVersionNumber_iOS_10_0 1300.0
#endif
#define PST_IS_IOS10_0_OR_GREATER (kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_10_0)
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100000
#define PST_IF_IOS10_0_OR_GREATER(...) \
if (PST_IS_IOS10_0_OR_GREATER) { \
PST_PARTIAL_AVAILABILITY_BEGIN \
__VA_ARGS__ \
PST_PARTIAL_AVAILABILITY_END }
#else
#define PST_IF_IOS10_0_OR_GREATER(...)
#endif
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
#define PST_IF_PRE_IOS10_0(...) \
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_10_0) { \
PST_PARTIAL_AVAILABILITY_BEGIN \
__VA_ARGS__ \
PST_PARTIAL_AVAILABILITY_END }
#else
#define PST_IF_PRE_IOS10_0(...)
#endif
#define PSTLogError NSLog
#define PSTLogWarning NSLog
@implementation PSTModernizer
+ (double)version {
return 1000.0;
}
+ (void)installModernizer {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[self installModernizerOnce];
});
}
+ (void)installModernizerOnce {
// Define this class in the runtime to block the modernizer being called.
if (NSClassFromString(@"PSTModernizerDisabled")) {
return;
}
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
// Fixes rdar://26295020: Action sheets presented for links don’t work in presented view controllers.
// This has been fixed in iOS 10b1.
PSTInstallWorkaroundForSheetPresentationRdar26295020();
// UIImage has threading issues under iOS 9.
// See https://github.com/AFNetworking/AFNetworking/issues/2572#issuecomment-227895102
// This has been fixed in iOS 10b1
PSTAddLockingToUIImageRdar26954460();
#endif
// 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.
NSLog(@"%@ version %.0f installed.", NSStringFromClass(self.class), self.version);
}
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 100000
static void PSTInstallWorkaroundForSheetPresentationRdar26295020() {
// This has been fixed in iOS 10b1 so it's only necessary for older versions of iOS.
PST_IF_IOS10_0_OR_GREATER(return;)
__block auto removeWorkaround = ^{};
let installWorkaround = ^{
let presentSEL = @selector(presentViewController:animated:completion:);
const __block IMP origIMP = pst_swizzleSelectorWithBlock(UIViewController.class, presentSEL, ^(UIViewController *_self, id vC, BOOL animated, id completion) {
while (_self.presentedViewController) {
_self = _self.presentedViewController;
}
((void (*)(id, SEL, id, BOOL, id))origIMP)(_self, presentSEL, vC, animated, completion);
});
if (origIMP) {
removeWorkaround = ^{
pst_swizzleSelector(UIViewController.class, presentSEL, origIMP);
};
}
};
let presentSheetSEL = PSTSELObfuscate(@"present%@FromRect:", @"Sheet");
let swizzleOnClass = ^(Class klass) {
if (!klass) {
PSTLogWarning(@"Unable to install workaround for rdar://26295020.");
return;
}
__block IMP origIMP = pst_swizzleSelectorWithBlock(klass, presentSheetSEL, ^(id _self, CGRect rect) {
// Before calling the original implementation, we swizzle the presentation logic on UIViewController
installWorkaround();
// UIKit later presents the sheet on [view.window rootViewController];
// See https://github.com/WebKit/webkit/blob/1aceb9ed7a42d0a5ed11558c72bcd57068b642e7/Source/WebKit2/UIProcess/ios/WKActionSheet.mm#L102
// Our workaround forwards this to the topmost presentedViewController instead.
((void (*)(id, SEL, CGRect))origIMP)(_self, presentSheetSEL, rect);
// Cleaning up again - this workaround would swallow bugs if we let it be there.
removeWorkaround();
});
};
swizzleOnClass(PSTClassObfuscate(@"_%@%@AlertController", @"UI", @"Rotating"));
// WKWebView might not be loaded, then we can't patch it.
if (let wkWebViewClass = PSTClassObfuscate(@"%@ActionSheet", @"WK")) {
swizzleOnClass(wkWebViewClass);
}
}
static void PSTAddLockingToUIImageRdar26954460() {
// This has been fixed in iOS 10b1 so it's only necessary for older versions of iOS.
PST_IF_IOS10_0_OR_GREATER(return;)
// The dictionary that UITraitCollectionCacheForBuiltinStorage returns
// is not thread safe. We can't easily hook C methods, so we lock the main initializer
// where the cache is being used. This will not cover all races around UITraitCollection,
// however with this level of granularity UIImage creation will work as expected.
//
// Overriding all calls of UITraitCollectionCacheForBuiltinStorage would require
// using private API.
static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
let displayScaleSEL = @selector(traitCollectionWithDisplayScale:);
__block IMP origIMP = pst_swizzleSelectorWithBlock(object_getClass(UITraitCollection.class), displayScaleSEL, ^id(id _self, CGFloat scale) {
pthread_mutex_lock(&mutex);
id result = ((id (*)(id, SEL, CGFloat))origIMP)(_self, displayScaleSEL, scale);
pthread_mutex_unlock(&mutex);
return result;
});
}
#endif
///////////////////////////////////////////////////////////////////////////////////////////
#pragma mark - Swizzle
static IMP pst_swizzleSelectorWithBlock(Class clazz, SEL selector, id newImplementationBlock) {
const IMP newImplementation = imp_implementationWithBlock(newImplementationBlock);
return pst_swizzleSelector(clazz, selector, newImplementation);
}
static IMP pst_swizzleSelector(Class clazz, SEL selector, IMP newImplementation) {
NSCParameterAssert(clazz);
NSCParameterAssert(selector);
NSCParameterAssert(newImplementation);
// If the method does not exist for this class, do nothing.
Method method = class_getInstanceMethod(clazz, selector);
if (!method) {
PSTLogError(@"%@ doesn't exist in %@.", NSStringFromSelector(selector), NSStringFromClass(clazz));
// Cannot swizzle methods which are not implemented by the class or one of its parents.
return NULL;
}
// Make sure the class implements the method. If this is not the case, inject an implementation, only calling 'super'.
const char *types = method_getTypeEncoding(method);
@synchronized (clazz) {
// class_addMethod will simply return NO if the method is already implemented.
#if !defined(__arm64__)
// Sufficiently large struct
typedef struct LargeStruct_ {
char dummy[16];
} LargeStruct;
NSUInteger retSize = 0;
NSGetSizeAndAlignment(types, &retSize, NULL);
// Large structs on 32-bit architectures
if (sizeof(void *) == 4 && types[0] == _C_STRUCT_B && retSize != 1 && retSize != 2 && retSize != 4 && retSize != 8) {
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)};
return ((LargeStruct (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper_stret)(&super, selector, argp);
}), types);
}
// All other cases
else {
#endif
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {.receiver = self, .super_class = class_getSuperclass(clazz)};
return ((id (*)(struct objc_super *, SEL, va_list))objc_msgSendSuper)(&super, selector, argp);
}), types);
#if !defined(__arm64__)
}
#endif
// Swizzling
return class_replaceMethod(clazz, selector, newImplementation, types);
}
}
@end
================================================
FILE: PSTModernizer.podspec
================================================
#
# Be sure to run `pod lib lint PSTModernizer.podspec' to ensure this is a
# valid spec before submitting.
#
Pod::Spec.new do |s|
s.name = 'PSTModernizer'
s.version = '1.0.0'
s.summary = 'Makes it easier to support older versions of iOS by fixing things and adding missing methods'
s.description = <<-DESC
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.
DESC
s.homepage = 'https://github.com/PSPDFKit-labs/PSTModernizer'
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'Peter Steinberger, PSPDFKit' => 'https://pspdfkit.com/' }
s.source = { :git => 'https://github.com/PSPDFKit-labs/PSTModernizer.git', :tag => s.version.to_s }
s.source_files = 'PSTModernizer/**/*'
s.social_media_url = 'https://twitter.com/steipete'
s.ios.deployment_target = '9.0'
s.tvos.deployment_target = '9.0'
s.xcconfig = { 'CLANG_MODULES_AUTOLINK' => 'YES' }
end
================================================
FILE: PSTModernizer.xcodeproj/project.pbxproj
================================================
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
7877A4441D1B672B005AEBAC /* PSTModernizer.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7877A4431D1B672B005AEBAC /* PSTModernizer.h */; };
7877A4461D1B672B005AEBAC /* PSTModernizer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7877A4451D1B672B005AEBAC /* PSTModernizer.mm */; settings = {COMPILER_FLAGS = "-fno-exceptions"; }; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
7877A43E1D1B672B005AEBAC /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
7877A4441D1B672B005AEBAC /* PSTModernizer.h in CopyFiles */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
7877A4401D1B672B005AEBAC /* libPSTModernizer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPSTModernizer.a; sourceTree = BUILT_PRODUCTS_DIR; };
7877A4431D1B672B005AEBAC /* PSTModernizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PSTModernizer.h; sourceTree = "<group>"; };
7877A4451D1B672B005AEBAC /* PSTModernizer.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PSTModernizer.mm; sourceTree = "<group>"; };
7881AA3A1D1B761E005EC1FF /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
7881AA3C1D1B7622005EC1FF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
7877A43D1D1B672B005AEBAC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7877A4371D1B672B005AEBAC = {
isa = PBXGroup;
children = (
7881AA3C1D1B7622005EC1FF /* Foundation.framework */,
7881AA3A1D1B761E005EC1FF /* UIKit.framework */,
7877A4421D1B672B005AEBAC /* PSTModernizer */,
7877A4411D1B672B005AEBAC /* Products */,
);
sourceTree = "<group>";
};
7877A4411D1B672B005AEBAC /* Products */ = {
isa = PBXGroup;
children = (
7877A4401D1B672B005AEBAC /* libPSTModernizer.a */,
);
name = Products;
sourceTree = "<group>";
};
7877A4421D1B672B005AEBAC /* PSTModernizer */ = {
isa = PBXGroup;
children = (
7877A4431D1B672B005AEBAC /* PSTModernizer.h */,
7877A4451D1B672B005AEBAC /* PSTModernizer.mm */,
);
path = PSTModernizer;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
7877A43F1D1B672B005AEBAC /* PSTModernizer */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7877A4491D1B672B005AEBAC /* Build configuration list for PBXNativeTarget "PSTModernizer" */;
buildPhases = (
7877A43C1D1B672B005AEBAC /* Sources */,
7877A43D1D1B672B005AEBAC /* Frameworks */,
7877A43E1D1B672B005AEBAC /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = PSTModernizer;
productName = PSTModernizer;
productReference = 7877A4401D1B672B005AEBAC /* libPSTModernizer.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7877A4381D1B672B005AEBAC /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = "PSPDFKit GmbH";
TargetAttributes = {
7877A43F1D1B672B005AEBAC = {
CreatedOnToolsVersion = 7.3.1;
};
};
};
buildConfigurationList = 7877A43B1D1B672B005AEBAC /* Build configuration list for PBXProject "PSTModernizer" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 7877A4371D1B672B005AEBAC;
productRefGroup = 7877A4411D1B672B005AEBAC /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
7877A43F1D1B672B005AEBAC /* PSTModernizer */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
7877A43C1D1B672B005AEBAC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7877A4461D1B672B005AEBAC /* PSTModernizer.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
7877A4471D1B672B005AEBAC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-lc++";
SDKROOT = iphoneos;
};
name = Debug;
};
7877A4481D1B672B005AEBAC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.3;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-lc++";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
7877A44A1D1B672B005AEBAC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
7877A44B1D1B672B005AEBAC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7877A43B1D1B672B005AEBAC /* Build configuration list for PBXProject "PSTModernizer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7877A4471D1B672B005AEBAC /* Debug */,
7877A4481D1B672B005AEBAC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7877A4491D1B672B005AEBAC /* Build configuration list for PBXNativeTarget "PSTModernizer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7877A44A1D1B672B005AEBAC /* Debug */,
7877A44B1D1B672B005AEBAC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 7877A4381D1B672B005AEBAC /* Project object */;
}
================================================
FILE: PSTModernizer.xcodeproj/project.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:PSTModernizer.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: README.md
================================================
# PSTModernizer
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.
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.
## Installation
Simply copy `PSTModernizer.h/mm` into your project, then call `[PSTModernizer installModernizer];` somewhere early, ideally in your app delegate.
Currently covers following radars (all of them have been fixed in iOS 10)
* [26954460 - UIImage creation has a race conditon on background threads.](https://openradar.appspot.com/26954460)<br>
The radar is actually for fixing the documentation, [the original issue is explained here.](https://pspdfkit.com/blog/2016/investigating-thread-saftey-of-UIImage/)
* [26295020 - Action sheets presented for links/numbers don’t work in presented view controllers](https://openradar.appspot.com/26295020)
You can simply delete the workarounds that do not affect you - every workaround is self-contained and can be individually removed.
## FAQ
Q: *Why?*<br>
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.
Q: *Isn't that partly using private API?*<br>
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.)
## License
The MIT License (MIT)
Copyright (c) 2016 Peter Steinberger, PSPDFKit GmbH.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## About
<a href="https://pspdfkit.com/">
<img src="https://avatars2.githubusercontent.com/u/1527679?v=3&s=200" height="80" />
</a>
This project is maintained and funded by [PSPDFKit](https://pspdfkit.com/).
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)).
gitextract_0g2bpret/ ├── .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/ │ │ ├── AppDelegate.h │ │ ├── AppDelegate.m │ │ ├── Assets.xcassets/ │ │ │ └── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.storyboard │ │ │ └── Main.storyboard │ │ ├── Info.plist │ │ ├── ViewController.h │ │ ├── ViewController.m │ │ └── main.m │ └── UIImageWithDataMultithreaded.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ └── contents.xcworkspacedata ├── LICENSE ├── PSTModernizer/ │ ├── 1.0.0/ │ │ └── PSTModernizer.podspec │ ├── PSTModernizer.h │ └── PSTModernizer.mm ├── PSTModernizer.podspec ├── PSTModernizer.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ └── contents.xcworkspacedata └── README.md
Condensed preview — 36 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (94K chars).
[
{
"path": ".gitignore",
"chars": 1341,
"preview": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/ActionSheetPresentationIssue.xcodeproj/project.pbxproj",
"chars": 14116,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/ActionSheetPresentationIssue.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 167,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:PresentationPla"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Resources/Base.lproj/LaunchScreen.xib",
"chars": 3768,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.XIB\" versi"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Resources/Images.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1077,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"29x29\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Resources/Info.plist",
"chars": 1439,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/AppDelegate.h",
"chars": 92,
"preview": "#import <UIKit/UIKit.h>\n\n@interface AppDelegate : UIResponder <UIApplicationDelegate>\n\n@end\n"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/AppDelegate.m",
"chars": 3530,
"preview": "#import \"AppDelegate.h\"\n#import \"TextViewController.h\"\n#import \"WebViewController.h\"\n#import \"NewerWebViewController.h\"\n"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/NewerWebViewController.h",
"chars": 84,
"preview": "#import <UIKit/UIKit.h>\n\n@interface NewerWebViewController : UIViewController\n\n@end\n"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/NewerWebViewController.m",
"chars": 344,
"preview": "#import \"NewerWebViewController.h\"\n@import WebKit;\n\n@implementation NewerWebViewController\n\n- (void)loadView {\n WKWeb"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/TextViewController.h",
"chars": 80,
"preview": "#import <UIKit/UIKit.h>\n\n@interface TextViewController : UIViewController\n\n@end\n"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/TextViewController.m",
"chars": 548,
"preview": "#import \"TextViewController.h\"\n\n@implementation TextViewController\n\n- (void)loadView {\n UITextView *textView = [[UITe"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/WebViewController.h",
"chars": 79,
"preview": "#import <UIKit/UIKit.h>\n\n@interface WebViewController : UIViewController\n\n@end\n"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/WebViewController.m",
"chars": 546,
"preview": "#import \"WebViewController.h\"\n\n@implementation WebViewController\n\n- (void)loadView {\n UIWebView *textView = [[UIWebVi"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/Workaround.h",
"chars": 208,
"preview": "//\n// Workaround.h\n// PresentationPlayground\n//\n// Created by Peter Steinberger on 16/05/16.\n//\n\n#import <Foundation/"
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/Workaround.mm",
"chars": 4417,
"preview": "//\n// Workaround.m\n// PresentationPlayground\n//\n// Created by Peter Steinberger on 16/05/16.\n//\n\n#import \"Workaround."
},
{
"path": "Example/26295020, 26294823 - Action Sheet Presentation/Source/main.m",
"chars": 185,
"preview": "@import UIKit;\n#import \"AppDelegate.h\"\n\nint main(int argc, char *argv[]) {\n\t@autoreleasepool {\n\t\treturn UIApplicationMai"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/AppDelegate.h",
"chars": 307,
"preview": "//\n// AppDelegate.h\n// UIImageWithDataMultithreaded\n//\n// Created by Peter Steinberger on 22/06/16.\n// Copyright © 2"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/AppDelegate.m",
"chars": 452,
"preview": "//\n// AppDelegate.m\n// UIImageWithDataMultithreaded\n//\n// Created by Peter Steinberger on 22/06/16.\n// Copyright © 2"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Assets.xcassets/AppIcon.appiconset/Contents.json",
"chars": 1077,
"preview": "{\n \"images\" : [\n {\n \"idiom\" : \"iphone\",\n \"size\" : \"29x29\",\n \"scale\" : \"2x\"\n },\n {\n \"idiom\""
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Base.lproj/LaunchScreen.storyboard",
"chars": 1664,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Base.lproj/Main.storyboard",
"chars": 1575,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/Info.plist",
"chars": 1495,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/ViewController.h",
"chars": 245,
"preview": "//\n// ViewController.h\n// UIImageWithDataMultithreaded\n//\n// Created by Peter Steinberger on 22/06/16.\n// Copyright "
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/ViewController.m",
"chars": 5377,
"preview": "//\n// ViewController.m\n// UIImageWithDataMultithreaded\n//\n// Created by Peter Steinberger on 22/06/16.\n// Copyright "
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded/main.m",
"chars": 364,
"preview": "//\n// main.m\n// UIImageWithDataMultithreaded\n//\n// Created by Peter Steinberger on 22/06/16.\n// Copyright © 2016 PSP"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded.xcodeproj/project.pbxproj",
"chars": 13354,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "Example/26954460 - UIImageWithDataMultithreaded/UIImageWithDataMultithreaded.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 173,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:UIImageWithData"
},
{
"path": "LICENSE",
"chars": 1100,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2016 Peter Steinberger, PSPDFKit GmbH.\n\nPermission is hereby granted, free of charg"
},
{
"path": "PSTModernizer/1.0.0/PSTModernizer.podspec",
"chars": 1172,
"preview": "#\n# Be sure to run `pod lib lint PSTModernizer.podspec' to ensure this is a\n# valid spec before submitting.\n#\n\nPod::Spec"
},
{
"path": "PSTModernizer/PSTModernizer.h",
"chars": 457,
"preview": "//\n// PSTModernizer.h\n// PSTModernizer\n//\n// Created by Peter Steinberger on 23/06/16.\n// Copyright © 2016 PSPDFKit "
},
{
"path": "PSTModernizer/PSTModernizer.mm",
"chars": 8765,
"preview": "//\n// PSTModernizer.mm\n// PSTModernizer\n//\n// Created by Peter Steinberger on 23/06/16.\n// Copyright © 2016 PSPDFKit"
},
{
"path": "PSTModernizer.podspec",
"chars": 1172,
"preview": "#\n# Be sure to run `pod lib lint PSTModernizer.podspec' to ensure this is a\n# valid spec before submitting.\n#\n\nPod::Spec"
},
{
"path": "PSTModernizer.xcodeproj/project.pbxproj",
"chars": 9045,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 46;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "PSTModernizer.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 158,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:PSTModernizer.x"
},
{
"path": "README.md",
"chars": 3919,
"preview": "# PSTModernizer\n\nPSTModernizer carefully applies patches to UIKit and related Apple frameworks to fix known radars with "
}
]
About this extraction
This page contains the full source code of the PSPDFKit-labs/PSTModernizer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 36 files (81.9 KB), approximately 25.6k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.