Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0F71F012B4EAF4A002E03F7"
BuildableName = "watchOS_Example Watch App.app"
BlueprintName = "watchOS_Example Watch App"
ReferencedContainer = "container:watchOS_Example.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
Expand All @@ -76,7 +75,6 @@
BuildableIdentifier = "primary"
BlueprintIdentifier = "D0F71F012B4EAF4A002E03F7"
BuildableName = "watchOS_Example Watch App.app"
BlueprintName = "watchOS_Example Watch App"
ReferencedContainer = "container:watchOS_Example.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
Expand Down
24 changes: 12 additions & 12 deletions ReerKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -634,11 +634,6 @@
D03512B92D362F4C00F4B5F2 /* Double+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03510062D362F4C00F4B5F2 /* Double+REExtensions.swift */; };
D03512BA2D362F4C00F4B5F2 /* DeinitObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0350FF92D362F4C00F4B5F2 /* DeinitObservable.swift */; };
D03512BB2D362F4C00F4B5F2 /* FileManager+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0350FE02D362F4C00F4B5F2 /* FileManager+REExtensions.swift */; };
D0USRDEF2EF6780100AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780200AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780300AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780400AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780500AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D03512BC2D362F4C00F4B5F2 /* LinkedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035103A2D362F4C00F4B5F2 /* LinkedList.swift */; };
D03512BD2D362F4C00F4B5F2 /* Sequence+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D035100F2D362F4C00F4B5F2 /* Sequence+REExtensions.swift */; };
D03512BE2D362F4C00F4B5F2 /* TypeNameDescribable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03510612D362F4C00F4B5F2 /* TypeNameDescribable.swift */; };
Expand Down Expand Up @@ -727,7 +722,6 @@
D036EAFE2B26FE5C00D451D6 /* InvocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D036EAFD2B26FE5C00D451D6 /* InvocationTests.swift */; };
D0397614286E12A900C33E17 /* OptionalExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0397613286E12A900C33E17 /* OptionalExtensionsTests.swift */; };
D03CC8ED2AE6816C00FCF78D /* DataExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0421AD22939033800452845 /* DataExtensionsTests.swift */; };
D0USRDEF2EF6789100AAAA00 /* UserDefaultsExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6789000AAAA00 /* UserDefaultsExtensionsTests.swift */; };
D0421ACF2938F5D500452845 /* CalendarExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0421ACE2938F5D500452845 /* CalendarExtensionsTests.swift */; };
D0421AD32939033800452845 /* DataExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0421AD22939033800452845 /* DataExtensionsTests.swift */; };
D04B859629F9A19200177357 /* ReerKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D04B858E29F9A19200177357 /* ReerKit.framework */; };
Expand Down Expand Up @@ -833,6 +827,12 @@
D0F39A84287DF21300A754B2 /* TestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F39A83287DF21300A754B2 /* TestHelpers.swift */; };
D0FB4058286363380019D56A /* OnceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FB4057286363380019D56A /* OnceTests.swift */; };
D0FD1FF52B232796000A433D /* test_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = D0FD1FF42B232796000A433D /* test_gray.png */; };
D0USRDEF2EF6780100AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780200AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780300AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780400AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6780500AAAA00 /* UserDefaults+REExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */; };
D0USRDEF2EF6789100AAAA00 /* UserDefaultsExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0USRDEF2EF6789000AAAA00 /* UserDefaultsExtensionsTests.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -924,7 +924,6 @@
D0350FE82D362F4C00F4B5F2 /* Timer+REExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timer+REExtensions.swift"; sourceTree = "<group>"; };
D0350FE92D362F4C00F4B5F2 /* URL+REExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+REExtensions.swift"; sourceTree = "<group>"; };
D0350FEA2D362F4C00F4B5F2 /* URLRequest+REExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URLRequest+REExtensions.swift"; sourceTree = "<group>"; };
D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+REExtensions.swift"; sourceTree = "<group>"; };
D0350FEC2D362F4C00F4B5F2 /* ReerKit.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReerKit.swift; sourceTree = "<group>"; };
D0350FEE2D362F4C00F4B5F2 /* Punycode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Punycode.swift; sourceTree = "<group>"; };
D0350FEF2D362F4C00F4B5F2 /* RSA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSA.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1038,7 +1037,6 @@
D0397613286E12A900C33E17 /* OptionalExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalExtensionsTests.swift; sourceTree = "<group>"; };
D0421ACE2938F5D500452845 /* CalendarExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarExtensionsTests.swift; sourceTree = "<group>"; };
D0421AD22939033800452845 /* DataExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataExtensionsTests.swift; sourceTree = "<group>"; };
D0USRDEF2EF6789000AAAA00 /* UserDefaultsExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsExtensionsTests.swift; sourceTree = "<group>"; };
D04B858E29F9A19200177357 /* ReerKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReerKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D04B859529F9A19200177357 /* ReerKit-macOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "ReerKit-macOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
D04B863929F9A60B00177357 /* ReerKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReerKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1139,6 +1137,8 @@
D0F39A83287DF21300A754B2 /* TestHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelpers.swift; sourceTree = "<group>"; };
D0FB4057286363380019D56A /* OnceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnceTests.swift; sourceTree = "<group>"; };
D0FD1FF42B232796000A433D /* test_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = test_gray.png; sourceTree = "<group>"; };
D0USRDEF2EF6780000AAAA00 /* UserDefaults+REExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserDefaults+REExtensions.swift"; sourceTree = "<group>"; };
D0USRDEF2EF6789000AAAA00 /* UserDefaultsExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsExtensionsTests.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -3977,7 +3977,7 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -4058,7 +4058,7 @@
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -4138,7 +4138,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -4209,7 +4209,7 @@
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
2 changes: 2 additions & 0 deletions ReerKit.xcodeproj/xcshareddata/xcschemes/ReerKit-iOS.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
language = "en"
region = "US"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
language = "en"
region = "US"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
language = "en"
region = "US"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
Expand Down
10 changes: 6 additions & 4 deletions Sources/ReerKit/Foundation/Data+REExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ public extension ReerForEquatable where Base == Data {
///
/// - Parameters:
/// - key: A key length of 16(AES128), 24(AES192) or 32(AES256)
/// - iv: An initialization vector length of 16(CBC), or use the default data that length of 0(ECB)
/// - iv: An initialization vector length of 16 (CBC), or the default empty data to use an all-zero IV (equivalent to ECB for input shorter than one block)
/// - Returns: A `Data` encrypted, or nil if an error occurs.
func aesEncrypt(withKey key: Data, iv: Data = .init()) -> Data? {
guard key.count == 16 || key.count == 24 || key.count == 32 else {
Expand All @@ -443,7 +443,8 @@ public extension ReerForEquatable where Base == Data {
CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding),
keyBytes.baseAddress, key.count,
ivBytes.baseAddress,
// An empty Data still has a non-nil (stack) baseAddress, and CCCrypt would read 16 garbage bytes from it as the IV.
iv.isEmpty ? nil : ivBytes.baseAddress,
dataBytes.baseAddress, base.count,
resultBytes.baseAddress,
resultBytes.count,
Expand All @@ -467,7 +468,7 @@ public extension ReerForEquatable where Base == Data {
///
/// - Parameters:
/// - key: A key length of 16(AES128), 24(AES192) or 32(AES256)
/// - iv: An initialization vector length of 16(CBC), or use the default data that length of 0(ECB)
/// - iv: An initialization vector length of 16 (CBC), or the default empty data to use an all-zero IV (equivalent to ECB for input shorter than one block)
/// - Returns: An `Data` decrypted, or nil if an error occurs.
func aesDecrypt(withKey key: Data, iv: Data = .init()) -> Data? {
guard key.count == 16 || key.count == 24 || key.count == 32 else {
Expand All @@ -489,7 +490,8 @@ public extension ReerForEquatable where Base == Data {
CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding),
keyBytes.baseAddress, key.count,
ivBytes.baseAddress,
// An empty Data still has a non-nil (stack) baseAddress, and CCCrypt would read 16 garbage bytes from it as the IV.
iv.isEmpty ? nil : ivBytes.baseAddress,
dataBytes.baseAddress, base.count,
resultBytes.baseAddress,
resultBytes.count,
Expand Down
8 changes: 7 additions & 1 deletion Sources/ReerKit/Foundation/Date+REExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,13 @@ extension Date {
static let sharedDateFormatter = DateFormatter()

static var dateFormatter: DateFormatter {
return Thread.isMainThread ? sharedDateFormatter: DateFormatter()
guard Thread.isMainThread else { return DateFormatter() }
// Callers such as `iso8601String` customize locale/timeZone on the shared instance,
// so restore the defaults (all three are null_resettable) before handing it out.
sharedDateFormatter.locale = nil
sharedDateFormatter.timeZone = nil
sharedDateFormatter.calendar = nil
return sharedDateFormatter
}
}

Expand Down
14 changes: 8 additions & 6 deletions Sources/ReerKit/StandardLibrary/String+REExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -427,8 +427,9 @@ public extension Reer where Base == String {
#endif

#if canImport(Foundation)
private static var dateFormatter: DateFormatter = {
let formatter = Date.dateFormatter
private static let dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone.current
formatter.dateFormat = "yyyy-MM-dd"
return formatter
Expand All @@ -445,8 +446,9 @@ public extension Reer where Base == String {
#endif

#if canImport(Foundation)
private static var dateTimeFormatter: DateFormatter = {
let formatter = Date.dateFormatter
private static let dateTimeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone.current
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
return formatter
Expand Down Expand Up @@ -1474,7 +1476,7 @@ public extension Reer where Base == String {
///
/// - Parameters:
/// - key: A key with a length of 16(AES128), 24(AES192) or 32(AES256) after conversion to data
/// - iv: An initialization vector with a length of 16(CBC) after conversion to data, or use the default data that length of 0(EBC)
/// - iv: An initialization vector with a length of 16 (CBC) after conversion to data, or the default empty string to use an all-zero IV
/// - Returns: A base64 encoded string of the encrypted Data encrypted, or nil if an error occurs.
func aesEncrypt(withKey key: String, iv: String = "") -> String? {
guard let data = base.re.utf8Data,
Expand All @@ -1489,7 +1491,7 @@ public extension Reer where Base == String {
///
/// - Parameters:
/// - key: A key with a length of 16(AES128), 24(AES192) or 32(AES256) after conversion to data
/// - iv: An initialization vector with a length of 16(CBC) after conversion to data, or use the default data that length of 0(EBC)
/// - iv: An initialization vector with a length of 16 (CBC) after conversion to data, or the default empty string to use an all-zero IV
/// - Returns: A decrypted string, or nil if an error occurs.
func aesDecrypt(withKey key: String, iv: String = "") -> String? {
guard let data = Data(base64Encoded: base, options: .ignoreUnknownCharacters),
Expand Down
9 changes: 8 additions & 1 deletion Sources/ReerKit/UIKit/UIImage+REExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,7 @@ public extension Reer where Base: UIImage {
corners = temp
}

guard base.size.width > 0, base.size.height > 0 else { return base }
UIGraphicsBeginImageContextWithOptions(base.size, false, base.scale)
guard let context = UIGraphicsGetCurrentContext() else {
return base
Expand Down Expand Up @@ -498,6 +499,7 @@ public extension Reer where Base: UIImage {
height: destRect.height.rounded()
)

guard roundedDestRect.width > 0, roundedDestRect.height > 0 else { return nil }
UIGraphicsBeginImageContextWithOptions(roundedDestRect.size, false, base.scale)
guard let contextRef = UIGraphicsGetCurrentContext() else { return nil }
contextRef.setShouldAntialias(true)
Expand Down Expand Up @@ -538,6 +540,7 @@ public extension Reer where Base: UIImage {
height: destRect.height.rounded()
)

guard roundedDestRect.width > 0, roundedDestRect.height > 0 else { return nil }
UIGraphicsBeginImageContextWithOptions(roundedDestRect.size, false, base.scale)
guard let contextRef = UIGraphicsGetCurrentContext() else { return nil }

Expand Down Expand Up @@ -592,7 +595,8 @@ public extension Reer where Base: UIImage {
///
/// - Returns: A new image with orientation .up, or the original image if already .up.
func orientationFixed() -> UIImage {
guard base.imageOrientation != .up else { return base }
guard base.imageOrientation != .up,
base.size.width > 0, base.size.height > 0 else { return base }
UIGraphicsBeginImageContextWithOptions(base.size, false, base.scale)
defer { UIGraphicsEndImageContext() }
base.draw(in: CGRect(origin: .zero, size: base.size))
Expand All @@ -608,6 +612,7 @@ public extension Reer where Base: UIImage {
func resize(toHeight: CGFloat, opaque: Bool = false) -> UIImage? {
let scale = toHeight / base.size.height
let newWidth = base.size.width * scale
guard newWidth > 0, toHeight > 0 else { return nil }
UIGraphicsBeginImageContextWithOptions(CGSize(width: newWidth, height: toHeight), opaque, base.scale)
base.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: toHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
Expand All @@ -624,6 +629,7 @@ public extension Reer where Base: UIImage {
func resize(toWidth: CGFloat, opaque: Bool = false) -> UIImage? {
let scale = toWidth / base.size.width
let newHeight = base.size.height * scale
guard toWidth > 0, newHeight > 0 else { return nil }
UIGraphicsBeginImageContextWithOptions(CGSize(width: toWidth, height: newHeight), opaque, base.scale)
base.draw(in: CGRect(x: 0, y: 0, width: toWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
Expand Down Expand Up @@ -1065,6 +1071,7 @@ public extension UIImage {
/// - color: image fill color.
/// - size: image size.
static func re(color: UIColor, size: CGSize = .init(width: 1, height: 1)) -> UIImage {
guard size.width > 0, size.height > 0 else { return UIImage() }
UIGraphicsBeginImageContextWithOptions(size, false, 1)

defer {
Expand Down
Loading
Loading