Post

Replies

Boosts

Views

Activity

Focusable doesn't work on iPad with external keyboard
I have a custom input view in my app which is .focusable(). It behaves similar to a TextField, where it must be focused in order to be used. This works fine on all platforms including iPad, except when when an external keyboard is connected (magic keyboard), in which case it can't be focused anymore and becomes unusable. Is there a solution to this, or a workaround? My view is very complex, so simple solutions like replacing it with a native view isn't possible, and I must be able to pragmatically force it to focus. Here's a very basic example replicating my issue. Non of the functionality works when a keyboard is connected: struct FocusableTestView: View { @FocusState private var isRectFocused: Bool var body: some View { VStack { // This text field should focus the custom input when pressing return: TextField("Enter text", text: .constant("")) .textFieldStyle(.roundedBorder) .onSubmit { isRectFocused = true } .onKeyPress(.return) { isRectFocused = true return .handled } // This custom "input" should focus itself when tapped: Rectangle() .fill(isRectFocused ? Color.accentColor : Color.gray.opacity(0.3)) .frame(width: 100, height: 100) .overlay( Text(isRectFocused ? "Focused" : "Tap me") ) .focusable(true, interactions: .edit) .focused($isRectFocused) .onTapGesture { isRectFocused = true print("Focused rectangle") } // The focus should be able to be controlled externally: Button("Toggle Focus") { isRectFocused.toggle() } .buttonStyle(.bordered) } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) } }
1
0
173
Oct ’25
Can't turn off inline auto predictions in WKWebView on Mac
I have a WKWebView that contains a js text editor, built on top of a content editable div. Currently, inline predictions on Mac break the text editors functionality significantly every time there's a prediction. There's not a way for me to fix this on the js side unless I can know when a prediction is shown. I've tried disabling inline predictions and writing tools with the web view config, but it doesn't work: let config = WKWebViewConfiguration() config.writingToolsBehavior = .none config.allowsInlinePredictions = false let webView = WKWebView(frame: .zero, configuration: config) I've also tried disabling all spellcheck and autocorrect features in the html but that doesn't work either: <div contenteditable="true" spellcheck="false" autocomplete="off" autocorrect="off" autocapitalize="off"></div> Is there anything I can do to turn it off? Or, is it possible to know when the WebView is predicting text?
1
0
276
Sep ’25
How to implement thread-safe property wrapper notifications across different contexts in Swift?
I’m trying to create a property wrapper that that can manage shared state across any context, which can get notified if changes happen from somewhere else. I'm using mutex, and getting and setting values works great. However, I can't find a way to create an observer pattern that the property wrappers can use. The problem is that I can’t trigger a notification from a different thread/context, and have that notification get called on the correct thread of the parent object that the property wrapper is used within. I would like the property wrapper to work from anywhere: a SwiftUI view, an actor, or from a class that is created in the background. The notification preferably would get called synchronously if triggered from the same thread or actor, or otherwise asynchronously. I don’t have to worry about race conditions from the notification because the state only needs to reach eventuall consistency. Here's the simplified pseudo code of what I'm trying to accomplish: // A single source of truth storage container. final class MemoryShared<Value>: Sendable { let state = Mutex<Value>(0) func withLock(_ action: (inout Value) -> Void) { state.withLock(action) notifyObservers() } func get() -> Value func notifyObservers() func addObserver() } // Some shared state used across the app static let globalCount = MemoryShared<Int>(0) // A property wrapper to access the shared state and receive changes @propertyWrapper struct SharedState<Value> { public var wrappedValue: T { get { state.get() } nonmutating set { // Can't set directly } } var publisher: Publisher {} init(state: MemoryShared) { // ... } } // I'd like to use it in multiple places: @Observable class MyObservable { @SharedState(globalCount) var count: Int } actor MyBackgroundActor { @SharedState(globalCount) var count: Int } @MainActor struct MyView: View { @SharedState(globalCount) var count: Int } What I’ve Tried All of the examples below are using the property wrapper within a @MainActor class. However the same issue happens no matter what context I use the wrapper in: The notification callback is never called on the context the property wrapper was created with. I’ve tried using @isolated(any) to capture the context of the wrapper and save it to be called within the state in with unchecked sendable, which doesn’t work: final class MemoryShared<Value: Sendable>: Sendable { // Stores the callback for later. public func subscribe(callback: @escaping @isolated(any) (Value) -> Void) -> Subscription } @propertyWrapper struct SharedState<Value> { init(state: MemoryShared<Value>) { MainActor.assertIsolated() // Works! state.subscribe { MainActor.assertIsolated() // Fails self.publisher.send() } } } I’ve tried capturing the isolation within a task with AsyncStream. This actually compiles with no sendable issues, but still fails: @propertyWrapper struct SharedState<Value> { init(isolation: isolated (any Actor)? = #isolation, state: MemoryShared<Value>) { let (taskStream, continuation) = AsyncStream<Value>.makeStream() // The shared state sends new values to the continuation. subscription = state.subscribe(continuation: continuation) MainActor.assertIsolated() // Works! let task = Task { _ = isolation for await value in taskStream { _ = isolation MainActor.assertIsolated() // Fails } } } } I’ve tried using multiple combine subjects and publishers: final class MemoryShared<Value: Sendable>: Sendable { let subject: PassthroughSubject<T, Never> // ... var publisher: Publisher {} // ... } @propertyWrapper final class SharedState<Value> { var localSubject: Subject init(state: MemoryShared<Value>) { MainActor.assertIsolated() // Works! handle = localSubject.sink { MainActor.assertIsolated() // Fails } stateHandle = state.publisher.subscribe(localSubject) } } I’ve also tried: Using NotificationCenter Making the property wrapper a class Using NSKeyValueObserving Using a box class that is stored within the wrapper. Using @_inheritActorContext. All of these don’t work, because the event is never called from the thread the property wrapper resides in. Is it possible at all to create an observation system that notifies the observer from the same context as where the observer was created? Any help would be greatly appreciated!
2
0
571
Mar ’25
Swift 6 Concurrency errors with ModelActor, or Core Data actors
In my app, I've been using ModelActors in SwiftData, and using actors with a custom executor in Core Data to create concurrency safe services. I have multiple actor services that relate to different data model components or features, each that have their own internally managed state (DocumentService, ImportService, etc). The problem I've ran into, is that I need to be able to use multiple of these services within another service, and those services need to share the same context. Swift 6 doesn't allow passing contexts across actors. The specific problem I have is that I need a master service that makes multiple unrelated changes without saving them to the main context until approved by the user. I've tried to find a solution in SwiftData and Core Data, but both have the same problem which is contexts are not sendable. Read the comments in the code to see the issue: /// This actor does multiple things without saving, until committed in SwiftData. @ModelActor actor DatabaseHelper { func commitChange() throws { try modelContext.save() } func makeChanges() async throws { // Do unrelated expensive tasks on the child context... // Next, use our item service let service = ItemService(modelContainer: SwiftDataStack.shared.container) let id = try await service.expensiveBackgroundTask(saveChanges: false) // Now that we've used the service, we need to access something the service created. // However, because the service created its own context and it was never saved, we can't access it. let itemFromService = context.fetch(id) // fails // We need to be able to access changes made from the service within this service, /// so instead I tried to create the service by passing the current service context, however that results in: // ERROR: Sending 'self.modelContext' risks causing data races let serviceFromContext = ItemService(context: modelContext) // Swift Data doesn't let you create child contexts, so the same context must be used in order to change data without saving. } } @ModelActor actor ItemService { init(context: ModelContext) { modelContainer = SwiftDataStack.shared.container modelExecutor = DefaultSerialModelExecutor(modelContext: context) } func expensiveBackgroundTask(saveChanges: Bool = true) async throws -> PersistentIdentifier? { // Do something expensive... return nil } } Core Data has the same problem: /// This actor does multiple things without saving, until committed in Core Data. actor CoreDataHelper { let parentContext: NSManagedObjectContext let context: NSManagedObjectContext /// In Core Data, I can create a child context from a background context. /// This lets you modify the context and save it without updating the main context. init(progress: Progress = Progress()) { parentContext = CoreDataStack.shared.newBackgroundContext() let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType) childContext.parent = parentContext self.context = childContext } /// To commit changes, save the parent context pushing them to the main context. func commitChange() async throws { // ERROR: Sending 'self.parentContext' risks causing data races try await parentContext.perform { try self.parentContext.save() } } func makeChanges() async throws { // Do unrelated expensive tasks on the child context... // As with the Swift Data example, I am unable to create a service that uses the current actors context from here. // ERROR: Sending 'self.context' risks causing data races let service = ItemService(context: self.context) } } Am I going about this wrong, or is there a solution to fix these errors? Some services are very large and have their own internal state. So it would be very difficult to merge all of them into a single service. I also am using Core Data, and SwiftData extensively so I need a solution for both. I seem to have trapped myself into a corner trying to make everything concurrency save, so any help would be appreciated!
6
0
906
Mar ’25
Can't invite or create an Apple Search Ads API user
I'm trying to invite an Apple ID as a search ads api user, however when I try to accept the invitation from the invited Apple ID, I get the error "Unable to create Search Ads Basic account". When I try to login directly to search ads using that account, I get the message "We're sorry. This Apple ID is no longer authorized for Apple Search Ads." I've also tried this with a separate Apple ID account, and the same problems happened. I've followed the steps in this article: https://searchads.apple.com/help/campaigns/0022-use-the-campaign-management-api Is there something I'm missing? Do I need to create a brand new Apple ID for this to work?
0
0
1.3k
Oct ’23
WKWebView custom URL handler throws error when using css mask url: "Origin null is not allowed by Access-Control-Allow-Origin."
To avoid using file URLs, I'm using the WKURLSchemeHandler to create a custom url to load my assets into a webview. This works great, except that certain ways of loading assets from the custom URL results in the error: Failed to load resource: Origin null is not allowed by Access-Control-Allow-Origin. Loading an asset in an image tag, css background property, or using a javascript import works. But using css mask, or javascript fetch does not. You can see the problem by right-clicking in the window, and clicking show developer tools. Css masks are used widely throughout the content in my webview, and I'm also using fetch. So I need both of these to work. What is causing this error? Why does it only happen when using certain methods of loading resources? import SwiftUI import WebKit struct ContentView: View {     var body: some View {         HTMLView().frame(maxWidth: .infinity, maxHeight: .infinity)     } } struct HTMLView: NSViewRepresentable {     func makeNSView(context: Context) -> WKWebView {         /* Create the custom url handler and webview */         let config = WKWebViewConfiguration()         config.setURLSchemeHandler(CustomURLHandler(), forURLScheme: "asset")         let webview = WKWebView(frame: .zero, configuration: config)         /* Enable developer tools so we can right click and show the inspector */     webview.configuration.preferences.setValue(true, forKey: "developerExtrasEnabled")         /* Example html that does and doesn't work: */         let html = """ &lt;style&gt; #box {     width: 100px;     height: 100px;     border: 1px solid green;     /* This works: */     background: url(asset://test.svg); } #box2 {     width: 100px;     height: 100px;     border: 1px solid red;     background: blue;     /* This does not work: */     -webkit-mask-image: url(asset://test.svg); } &lt;/style&gt; &lt;p&gt;This box loads the asset using the background property:&lt;/p&gt; &lt;div id="box"&gt;&lt;/div&gt; &lt;p&gt;This box results in the error, and doesn't show the image with the css mask:&lt;/p&gt; &lt;div id="box2"&gt;&lt;/div&gt; &lt;script&gt; // Using javascript fetch also doesn't work: fetch('asset://test.svg')     .then(data => {         console.log('Success:', data);     })     .catch((error) => {         console.error('Error:', error);     }); &lt;/script&gt; """         webview.loadHTMLString(html, baseURL: nil)         return webview     }     func updateNSView(_ nsView: WKWebView, context: Context) {} } class CustomURLHandler: NSObject, WKURLSchemeHandler {     func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {         guard let url = urlSchemeTask.request.url else {             return         }         /* Handle the custom url assets here. In this example I'm just returning a test svg: */         let testImage = "&lt;?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?&gt;&lt;!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"&gt;&lt;svg width=\"100%\" height=\"100%\" viewBox=\"0 0 19 18\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" xmlns:serif=\"http://www.serif.com/\" style=\"fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;\"&gt;&lt;g transform=\"matrix(1,0,0,1,-540,-709.618)\"&gt;&lt;g transform=\"matrix(0.5,0,0,0.666667,467,536)\"&gt;&lt;g transform=\"matrix(2,0,0,1.5,-934,-804)\"&gt;&lt;path d=\"M549,712.6C550.895,709 554.684,709 556.579,710.8C558.474,712.6 558.474,716.2 556.579,719.8C555.253,722.5 551.842,725.2 549,727C546.158,725.2 542.747,722.5 541.421,719.8C539.526,716.2 539.526,712.6 541.421,710.8C543.316,709 547.105,709 549,712.6Z\" style=\"fill:rgb(255,0,0);\"/&gt;&lt;/g&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;"         guard let data = testImage.data(using: .utf8) else { return }         let urlResponse = URLResponse(url: url, mimeType: "image/svg+xml", expectedContentLength: data.count, textEncodingName: nil)         urlSchemeTask.didReceive(urlResponse)         urlSchemeTask.didReceive(data)         urlSchemeTask.didFinish()     }     func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {} }
1
0
3.2k
Mar ’23
SwiftUI initializing state doesn't update after first init
I have a view which sends its size to a child, so the child can update its size relative to its parent. (The child needs to be able to respond to the parents size, and also update its own size from a drag event.) In the example below, the child sets its width to 40% of the parent in it's init. When the window is first shown, the child updates its width correctly. When you resize the window, however, the initializer is called and the size is recalculated, but the child never updates its width. The state seems to never update. When the code is called outside of the initializer (such as pressing a button) then the state updates correctly. Why doesn't the state update in the init after its called more than once? How would I accomplish this? struct ContentView: View {     var body: some View {         GeometryReader { geo in             ZStack {                 MyView(containerSize: geo.size)             }             .frame(maxWidth: .infinity, maxHeight: .infinity)             .border(Color.green, width: 1)         }     } } struct MyView: View {     let containerSize: CGSize     @State var realSize: CGSize     init(containerSize: CGSize) {         self.containerSize = containerSize         let newSize = CGSize(width: containerSize.width * 0.4, height: containerSize.height)         print("INIT", newSize)         _realSize = State(initialValue: newSize)     }     func updateWidth() {         realSize = CGSize(width: containerSize.width * 0.4, height: containerSize.height)     }     var body: some View {         ZStack {             Button(action: {                 self.updateWidth()             }) {                 Text("Update Width")             }         }         .frame(width: realSize.width, height: realSize.height)         .background(Color.blue)     } }
8
0
7.4k
Nov ’22
Detect and handle string conflicts in Core Data with iCloud Sync
I'm trying to create a note-taking like app that uses NSPersistentCloudKitContainer and core data. The store uses the NSMergeByPropertyObjectTrumpMergePolicy, which is fine for almost every property. For example, if the name of a file is changed on two different devices, then it's fine to use the latest value. The problem is that the note text cannot be overridden by the latest value if it's changed on two devices at once. It needs to be detected as a conflict so the user can choose which version they want to keep. I can replicate the behavior by turning off wifi on one device and writing content, then writing content on a different device at the same time. When I turn the wifi back on, whichever device saved the changes last completely overrides the other device's text. What I'd like to accomplish is detect when there is a conflict of text, then create a duplicate file called "Conflicted Copy." Bonus points if someone can tell me how Apple Notes magically merges text without ever creating a conflict. I really only need a simple solution though that prevents data loss. Any help in the right direction would be appreciated!
0
0
1k
Sep ’22
Restore Purchase not Working
I’m using the new StoreKit 2 APIs in my production app that sells a non-consumable iap. I’ve tested restoring purchases with a StorekitConfiguration in development, along with my own personal Apple ID in production and it works.  The problem is that I’m getting lots of users reporting that restore purchase does’t work on a consistent basis. So my question is, is there something in my production code that is wrong or broken? Or is this a common problem with end users themselves and not my app? My app used the old version of store kit previously, so could that cause this issue? I always recommend they make sure they’re signed in with the same Apple ID they purchased the app with. Sometimes recommending the user to quit and relaunch the app, or restart there computer fixes the issue. I’ve gotten multiple reports that the only fix was completely deleting then reinstalling the app. And there’s a good portion which non of the above work. Here’s the code that handles restoring purchases: /// Attempts to restore any purchases by the user. /// This is called by the restore purchase button public func restorePurchase() {     Task {         try? await AppStore.sync()         await updateActiveProducts()     } } /// Updates the status of which products have been purchased/are an active subscription @MainActor public func updateActiveProducts() async {     var purchasedIds: [String] = []     // Iterate through all of the user's purchased products.     for await result in Transaction.currentEntitlements {         do {             let transaction = try checkVerified(result)             // Has the App Store revoked this transaction?             // If it is upgraded do nothing, there is an active transaction for a higher level of service             if transaction.revocationDate != nil || transaction.isUpgraded {                 continue             }             // Check if the subscription is expired             if let expirationDate = transaction.expirationDate, expirationDate < Date() {                 continue             }             if transaction.productType == .nonConsumable || transaction.productType == .autoRenewable {                 purchasedIds.append(transaction.productID)             }         } catch { // Transaction not verified, don't do anything         }     } // This is a published property which unlocks the features of the app     self.purchasedIdentifiers = purchasedIds } Any advice would be appreciated!
2
2
2.8k
Aug ’22
How to avoid retain cycle in custom SwiftUI view closure
I'm trying to create a wrapper around a WKWebView for SwiftUI, and I'm not sure how to prevent a memory leak. I've created an ObservableObject which handles controlling the WebView, and a custom view that displays it: public class WebViewStore: ObservableObject { var webView: WKWebView = WKWebView() // List of event handlers that will be called from the WebView var eventHandlers: [String: () -> Void] = [:] deinit { // This is never called once an action has been set with the view, // and the content view is destroyed print("deinit") } // All the WebView code, including custom JavaScript message handlers, custom scheme handlers, etc... func reloadWebView() { } } The web view needs to be able to communicate with JavaScript, so I've added an onAction() method which gets called when the WebView gets a javascript event. View wrapper: struct WebView: NSViewRepresentable { let store: WebViewStore func makeNSView(context: Context) -> WKWebView { return store.webView } func updateNSView(_ view: WKWebView, context: Context) {} } extension WebView { /// Action event called from the WebView public func onAction(name: String, action: @escaping () -> Void) -> WebView { self.store.eventHandlers[name] = action return self } } Usage that creates the retain cycle: struct ContentView: View { @StateObject var store = WebViewStore() var body: some View { VStack { // Example of interacting with the WebView Button("Reload") { store.reloadWebView() } WebView(store: store) // This action closure captures the WebViewStore, causing the retain cycle. .onAction(name: "javascriptMessage") { print("Event!") } } } } Is there a way to prevent the retain cycle from happening, or is there a different SwiftUI pattern that can to handle this use case? I can't use [weak self] because the view is a struct. I need to be able to receive events from the WebView and vice versa.
0
0
1.7k
Aug ’22
NSOutlineView doesn't change height when expanded in SwiftUI
I have wrapped an NSOutlineView with NSViewRepresentable which works great. The problem is that when an item is expanded, the outline view doesn't change height and the animation doesn't work properly (see gif below). When I put the outline view in an NSScrollView, it works correctly, but I need to be able to put multiple outline views within a single SwiftUI scrollview. struct Test: View { var body: some View { ScrollView { SwiftUiOutline() // Ultimately I need multiple outline views here } } } struct SwiftUiOutline: NSViewRepresentable { func makeNSView(context: Context) -> NSOutlineView { let view = NSOutlineView() // Outline view is set up here, and connected to the coordinator delegate return view } class Coordinator: CustomOutlineViewController { // The coordinator handles all the outline view delegation, etc. } // ... } The problem: How it should work:
0
0
997
Jul ’21