[AltStoreCore] Flattens optional values when @Managed/@AsyncManaged.wrappedValue is also optional

This commit is contained in:
Riley Testut
2023-05-11 15:03:29 -05:00
committed by Magesh K
parent 7d380da5d1
commit 16c71be7f9
4 changed files with 46 additions and 2 deletions

View File

@@ -357,6 +357,7 @@
D561B2ED28EF5A4F006752E4 /* AltSign-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = D561B2EA28EF5A4F006752E4 /* AltSign-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
D5708417292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */; };
D570841A2924680D00D42D34 /* OperatingSystemVersion+Comparable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */; };
D5728CA72A0D79D30014E73C /* OptionalProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5728CA62A0D79D30014E73C /* OptionalProtocol.swift */; };
D57968CB29CB99EF00539069 /* VibrantButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D57968CA29CB99EF00539069 /* VibrantButton.swift */; };
D57DF638271E32F000677701 /* PatchApp.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D57DF637271E32F000677701 /* PatchApp.storyboard */; };
D57DF63F271E51E400677701 /* ALTAppPatcher.m in Sources */ = {isa = PBXBuildFile; fileRef = D57DF63E271E51E400677701 /* ALTAppPatcher.m */; };
@@ -912,6 +913,7 @@
D54DED1328CBC44B008B27A0 /* ErrorLogTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorLogTableViewCell.swift; sourceTree = "<group>"; };
D55E163528776CB000A627A1 /* ComplicationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationView.swift; sourceTree = "<group>"; };
D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OperatingSystemVersion+Comparable.swift"; sourceTree = "<group>"; };
D5728CA62A0D79D30014E73C /* OptionalProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalProtocol.swift; sourceTree = "<group>"; };
D57968CA29CB99EF00539069 /* VibrantButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VibrantButton.swift; sourceTree = "<group>"; };
D57DF637271E32F000677701 /* PatchApp.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = PatchApp.storyboard; sourceTree = "<group>"; };
D57DF63D271E51E400677701 /* ALTAppPatcher.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTAppPatcher.h; sourceTree = "<group>"; };
@@ -1439,6 +1441,7 @@
children = (
BF66EE9B2501AEC1007EE018 /* AppProtocol.swift */,
BF66EE9C2501AEC1007EE018 /* Fetchable.swift */,
D5728CA62A0D79D30014E73C /* OptionalProtocol.swift */,
);
path = Protocols;
sourceTree = "<group>";
@@ -2636,6 +2639,7 @@
BF66EEEB2501AED0007EE018 /* UIApplication+AppExtension.swift in Sources */,
D5F48B4829CCF21B002B52A4 /* AltStore+Async.swift in Sources */,
BF66EED92501AECA007EE018 /* Team.swift in Sources */,
D5728CA72A0D79D30014E73C /* OptionalProtocol.swift in Sources */,
BF66EED12501AECA007EE018 /* AltStore3ToAltStore4.xcmappingmodel in Sources */,
D5F48B4C29CD0C48002B52A4 /* AsyncManaged.swift in Sources */,
BFAECC5C2501B0A400528F27 /* CFNotificationName+AltStore.m in Sources */,

View File

@@ -0,0 +1,19 @@
//
// OptionalProtocol.swift
// AltStoreCore
//
// Created by Riley Testut on 5/11/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import Foundation
// Public so we can use as generic constraint.
public protocol OptionalProtocol
{
associatedtype Wrapped
static var none: Self { get }
}
extension Optional: OptionalProtocol {}

View File

@@ -71,6 +71,7 @@ public extension AsyncManaged
/// @dynamicMemberLookup
public extension AsyncManaged
{
// Non-optional values
subscript<T>(dynamicMember keyPath: KeyPath<ManagedObject, T>) -> T {
get async {
let result = await self.perform { $0[keyPath: keyPath] }
@@ -78,7 +79,7 @@ public extension AsyncManaged
}
}
// Optionals
// Optional wrapped value
subscript<Wrapped, T>(dynamicMember keyPath: KeyPath<Wrapped, T>) -> T? where ManagedObject == Optional<Wrapped> {
get async {
guard let wrappedValue else { return nil }
@@ -87,4 +88,14 @@ public extension AsyncManaged
return result
}
}
// Optional wrapped value + optional property (flattened)
subscript<Wrapped, T>(dynamicMember keyPath: KeyPath<Wrapped, T>) -> T where ManagedObject == Optional<Wrapped>, T: OptionalProtocol {
get async {
guard let wrappedValue else { return T.none }
let result = await self.perform { _ in wrappedValue[keyPath: keyPath] }
return result
}
}
}

View File

@@ -80,13 +80,14 @@ public extension Managed
/// @dynamicMemberLookup
public extension Managed
{
// Non-optional values
subscript<T>(dynamicMember keyPath: KeyPath<ManagedObject, T>) -> T
{
let result = self.perform { $0[keyPath: keyPath] }
return result
}
// Optionals
// Optional wrapped value
subscript<Wrapped, T>(dynamicMember keyPath: KeyPath<Wrapped, T>) -> T? where ManagedObject == Optional<Wrapped>
{
guard let wrappedValue else { return nil }
@@ -94,4 +95,13 @@ public extension Managed
let result = self.perform { _ in wrappedValue[keyPath: keyPath] }
return result
}
// Optional wrapped value + optional property (flattened)
subscript<Wrapped, T>(dynamicMember keyPath: KeyPath<Wrapped, T>) -> T where ManagedObject == Optional<Wrapped>, T: OptionalProtocol
{
guard let wrappedValue else { return T.none }
let result = self.perform { _ in wrappedValue[keyPath: keyPath] }
return result
}
}