Skip to content

Commit 3dbe1d3

Browse files
authored
Update private API usage on Darwin platform (#205)
* Update private header * Update didMoveToWindow to UIHostingView * Update shims private API wrapper
1 parent 9c02104 commit 3dbe1d3

File tree

9 files changed

+174
-44
lines changed

9 files changed

+174
-44
lines changed

Sources/OpenSwiftUI/Integration/Hosting/UIKit/View/UIHostingView.swift

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,9 +279,28 @@ open class _UIHostingView<Content>: UIView, XcodeViewDebugDataProvider where Con
279279
}
280280

281281
override dynamic open func didMoveToWindow() {
282+
Update.begin()
283+
if window != nil {
284+
traitCollectionOverride = nil
285+
initialInheritedEnvironment = nil
286+
invalidateProperties(.transform)
287+
}
288+
// updateKeyboardAvoidance()
289+
// eventBridge.hostingView(self, didMoveToWindow: window)
290+
// TODO: rootViewDelegate
291+
if window != nil {
292+
updateRemovedState()
293+
// updateEventBridge()
294+
} else {
295+
UIApplication.shared._performBlockAfterCATransactionCommits { [weak self] in
296+
guard let self else { return }
297+
updateRemovedState()
298+
}
299+
}
282300
// TODO
301+
Update.end()
283302
}
284-
303+
285304
override dynamic open func layoutSubviews() {
286305
super.layoutSubviews()
287306
guard window != nil else {

Sources/OpenSwiftUICore/Graph/GraphHost.swift

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,7 @@ open class GraphHost: CustomReflectable {
184184
globalSubgraph.willInvalidate(isInserted: false)
185185
isInstantiated = false
186186
}
187-
if let graph = data.graph {
188-
Update.begin()
189-
globalSubgraph.invalidate()
190-
graph.context = nil
191-
graph.invalidate()
192-
data.graph = nil
193-
Update.end()
194-
}
187+
data.invalidate()
195188
}
196189

197190
package static var isUpdating: Bool {

Sources/OpenSwiftUI_SPI/README.md

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,50 @@
11
## OpenSwiftUI_SPI
22

3-
TODO: module name - OpenSwiftUI_SPI
3+
### Shims
4+
5+
For private Darwin ObjectiveC API, we use shims wrapped to replace the direct private API call to avoid breaking change.
6+
7+
Below is an example of how to shim a private API call.
8+
9+
```objectivec
10+
@interface UIApplication (OpenSwiftUI_SPI)
11+
- (void)_performBlockAfterCATransactionCommits_openswiftui_safe_wrapper:(void (^)(void))block OPENSWIFTUI_SWIFT_NAME(_performBlockAfterCATransactionCommits(_:));
12+
@end
13+
14+
@implementation UIApplication (OpenSwiftUI_SPI)
15+
- (void)_performBlockAfterCATransactionCommits_openswiftui_safe_wrapper:(void (^)(void))block {
16+
typedef void (*Func)(UIApplication *, SEL, void (^)(void));
17+
SEL selector = NSSelectorFromString(@"_performBlockAfterCATransactionCommits:");
18+
Func func = nil;
19+
if ([self respondsToSelector:selector]) {
20+
IMP impl = class_getMethodImplementation([self class], selector);
21+
func = (Func)impl;
22+
}
23+
if (func != nil) {
24+
func(self, selector, block);
25+
}
26+
}
27+
@end
28+
```
29+
30+
```swift
31+
extension UIApplication {
32+
func _performBlockAfterCATransactionCommits(_ block: @escaping (Int) -> Void) {
33+
typealias Function = @convention(c) (UIApplication, Selector, @escaping (Int) -> Void) -> Void
34+
35+
let selector = Selector(("_performBlockAfterCATransactionCommits:"))
36+
guard responds(to: selector),
37+
let implementation = class_getMethodImplementation(UIApplication.self, selector)
38+
else {
39+
return
40+
}
41+
let function = unsafeBitCast(implementation, to: Function.self)
42+
return function(self, selector, block)
43+
}
44+
}
45+
```
46+
47+
TODO:
48+
- [ ] Add String concat helper macro to avoid selector name being detected.
49+
- [ ] Add static variable to avoid selector build.
50+
- [ ] Add static variable to avoid multiple method lookup.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// AppKit_Private.h
3+
// OpenSwiftUI_SPI
4+
//
5+
// Status: WIP
6+
7+
#ifndef AppKit_Private_h
8+
#define AppKit_Private_h
9+
10+
#include "OpenSwiftUIBase.h"
11+
12+
#if __has_include(<AppKit/AppKit.h>)
13+
14+
#import <AppKit/AppKit.h>
15+
16+
OPENSWIFTUI_ASSUME_NONNULL_BEGIN
17+
18+
@interface NSApplication (OpenSwiftUI_SPI)
19+
- (void)startedTest:(nullable NSString *)name;
20+
- (void)finishedTest:(nullable NSString *)name;
21+
- (void)failedTest:(nullable NSString *)name withFailure:(nullable NSError*)failure;
22+
@end
23+
24+
OPENSWIFTUI_ASSUME_NONNULL_END
25+
26+
#endif /* AppKit.h */
27+
28+
#endif /* AppKit_Private_h */
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//
2+
// AppKit_Private.m
3+
// OpenSwiftUI_SPI
4+
//
5+
// Status: WIP
6+
7+
#import "AppKit_Private.h"
8+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//
2+
// CoreAnimation_Private.h
3+
// OpenSwiftUI_SPI
4+
//
5+
// Status: WIP
6+
7+
#ifndef CoreAnimation_Private_h
8+
#define CoreAnimation_Private_h
9+
10+
#include "OpenSwiftUIBase.h"
11+
12+
#if __has_include(<QuartzCore/CoreAnimation.h>)
13+
14+
#import <QuartzCore/CoreAnimation.h>
15+
16+
OPENSWIFTUI_ASSUME_NONNULL_BEGIN
17+
18+
@interface CALayer (OpenSwiftUI_SPI)
19+
- (BOOL)hasBeenCommitted;
20+
@end
21+
22+
OPENSWIFTUI_ASSUME_NONNULL_END
23+
24+
#endif /* CoreAnimation.h */
25+
26+
#endif /* CoreAnimation_Private_h */
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//
2+
// CoreAnimation_Private.m
3+
// OpenSwiftUI_SPI
4+
//
5+
// Status: WIP
6+
7+
#import "CoreAnimation_Private.h"
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,28 @@
11
//
2-
// UIKitAppKit_Private.h
2+
// UIKit_Private.h
33
// OpenSwiftUI_SPI
44
//
5-
// Audited for iOS 15.5
65
// Status: WIP
76

8-
#ifndef UIKitAppKit_Private_h
9-
#define UIKitAppKit_Private_h
7+
#ifndef UIKit_Private_h
8+
#define UIKit_Private_h
109

1110
#include "OpenSwiftUIBase.h"
1211

13-
#if __has_include(<QuartzCore/CoreAnimation.h>)
14-
15-
#import <QuartzCore/CoreAnimation.h>
16-
17-
OPENSWIFTUI_ASSUME_NONNULL_BEGIN
18-
19-
@interface CALayer (OpenSwiftUI_SPI)
20-
- (BOOL)hasBeenCommitted;
21-
@end
22-
23-
OPENSWIFTUI_ASSUME_NONNULL_END
24-
25-
#endif /* CoreAnimation.h */
26-
2712
#if __has_include(<UIKit/UIKit.h>)
2813

2914
#import <UIKit/UIKit.h>
3015

3116
OPENSWIFTUI_ASSUME_NONNULL_BEGIN
3217

3318
@interface UIApplication (OpenSwiftUI_SPI)
19+
// Test API
3420
- (void)startedTest:(nullable NSString *)name;
3521
- (void)finishedTest:(nullable NSString *)name;
3622
- (void)failedTest:(nullable NSString *)name withFailure:(nullable NSError*)failure;
3723
- (nullable NSString *)_launchTestName;
24+
25+
- (void)_performBlockAfterCATransactionCommits_openswiftui_safe_wrapper:(void (^)(void))block OPENSWIFTUI_SWIFT_NAME(_performBlockAfterCATransactionCommits(_:));
3826
@end
3927

4028
@interface UIView (OpenSwiftUI_SPI)
@@ -53,20 +41,6 @@ double UIAnimationDragCoefficient(void);
5341

5442
OPENSWIFTUI_ASSUME_NONNULL_END
5543

56-
#elif __has_include(<AppKit/AppKit.h>)
57-
58-
#import <AppKit/AppKit.h>
59-
60-
OPENSWIFTUI_ASSUME_NONNULL_BEGIN
61-
62-
@interface NSApplication (OpenSwiftUI_SPI)
63-
- (void)startedTest:(nullable NSString *)name;
64-
- (void)finishedTest:(nullable NSString *)name;
65-
- (void)failedTest:(nullable NSString *)name withFailure:(nullable NSError*)failure;
66-
@end
67-
68-
OPENSWIFTUI_ASSUME_NONNULL_END
69-
70-
#endif /* UIKit.h / AppKit.h */
44+
#endif /* UIKit.h */
7145

72-
#endif /* UIKitAppKit_Private_h */
46+
#endif /* UIKit_Private_h */
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// UIKit_Private.m
3+
// OpenSwiftUI_SPI
4+
//
5+
// Status: WIP
6+
7+
#import "UIKit_Private.h"
8+
9+
#if __has_include(<UIKit/UIKit.h>)
10+
11+
#import <objc/runtime.h>
12+
13+
@implementation UIApplication (OpenSwiftUI_SPI)
14+
- (void)_performBlockAfterCATransactionCommits_openswiftui_safe_wrapper:(void (^)(void))block {
15+
typedef void (*Func)(UIApplication *, SEL, void (^)(void));
16+
SEL selector = NSSelectorFromString(@"_performBlockAfterCATransactionCommits:");
17+
Func func = nil;
18+
if ([self respondsToSelector:selector]) {
19+
IMP impl = class_getMethodImplementation([self class], selector);
20+
func = (Func)impl;
21+
}
22+
if (func != nil) {
23+
func(self, selector, block);
24+
}
25+
}
26+
@end
27+
28+
#endif /* UIKit.h */

0 commit comments

Comments
 (0)