Hello,
After upgrading to macOS 26.2, I’ve noticed a significant performance regression when calling evaluateJavaScript in an iOS App running on Mac (WKWebView, Swift project).
Observed behavior
On macOS 26.2, the callback of evaluateJavaScript takes around 3 seconds to return.
This happens not only for:
evaluateJavaScript("navigator.userAgent")
but also for simple or even empty scripts, for example:
evaluateJavaScript("")
On previous macOS versions, the same calls typically returned in ~200 ms.
Additional testing
I created a new, empty Objective-C project with a WKWebView and tested the same evaluateJavaScript calls.
In the Objective-C project, the callback still returns in ~200 ms, even on macOS 26.2.
Question
Is this a known issue or regression related to:
iOS Apps on Mac,
Swift + WKWebView, or
behavioral changes in evaluateJavaScript on macOS 26.2?
Any information about known issues, internal changes, or recommended workarounds would be greatly appreciated.
Thank you.
Test Code Swift
class ViewController: UIViewController {
private var tmpWebView: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
setupUserAgent()
}
func setupUserAgent() {
let t1 = CACurrentMediaTime()
tmpWebView = WKWebView(frame: .zero)
tmpWebView?.isInspectable = true
tmpWebView?.evaluateJavaScript("navigator.userAgent") { [weak self] result, error in
let t2 = CACurrentMediaTime()
print("[getUserAgent] \(t2 - t1)s")
self?.tmpWebView = nil
}
}
}
Test Code Objective-C
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
WKWebView *webView = [[WKWebView alloc] init];
dispatch_async(dispatch_get_main_queue(), ^{
[webView evaluateJavaScript:@"navigator.userAgent" completionHandler:^(id result, NSError *error) {
NSTimeInterval endTime = [[NSDate date] timeIntervalSince1970];
NSLog(@"[getUserAgent]: %.2f s", (endTime - startTime));
}];
});
}
Dive into the world of programming languages used for app development.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
So I’m writing a program, as a developer would - ‘with Xcode.’
Code produced an error.
The key values were swapped. The parameters suggested were ‘optional parameters variables.’
“var name: TYPE? = (default)”
var name0: TYPE
=============================
name0 = “super cool”
‘Name is not yet declared at this point
provided with
x - incorrect argument replace
ExampleStruct(name:”supercool”)
should be
x - incorrect argument replace
ExampleStruct(name0:”supercool”)
=============================
In swift, there is a procedural prioritization within the constructor calling process.
Application calls constructor.
Constructor provides constructor signature. Signature requires parameters & throws an error if the params are not in appropriate order. - “got it compiler; thank you, very much”
Typically, when this occurs, defaults will be suggested. Often the variable type. Ie String, Bool.
such as:
StructName(param1:Int64, param2:Bool)
(Recently, I have seen a decline in @Apple’s performance in many vectors.)
As stated before, the key value pairs were out of sequence. The optionals were suggested instead of the required parameters.
This leads me to believe that there is an order of operations in the calling procedure that is being mismanaged.
I.e. regular expression, matching with optional. This confuses these with [forced, required] parameters, and the mismanagement of ‘key: value’ pairs.
this is a superficial prognosis and would like to know if anyone has any insight as to why this may occur.
Could it be a configuration setting? Is it possibly the network I connected to bumped into something. Etc..
I appreciate any and all feedback.
Please take into consideration the Apple developer forum, guidelines before posting comments.
#dev_div
I am creating a macOs SwiftUI document based app, and I am struggling with the Window sizes and placements. Right now by default, a normal window has the minimize and full screen options which makes the whole window into full screen mode.
However, I don't want to do this for my app. I want to only allow to fill the available width and height, i.e. exclude the status bar and doc when the user press the fill window mode, and also restrict to resize the window beyond a certain point ( which ideally to me is 1200 x 700 because I am developing on macbook air 13.3-inch in which it looks ideal, but resizing it below that makes the entire content inside messed up ).
I want something like this below instead of the default full screen green
When the user presses the button, it should position centered with perfect aspect ratio from my content ( or the one I want like 1200 x 700 ) and can be able to click again to fill the available width and height excluding the status bar and docs.
Here is my entire @main code :-
@main
struct PhiaApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
DocumentGroup(newDocument: PhiaProjectDocument()) { file in
ContentView(
document: file.$document,
rootURL: file.fileURL
)
.configureEditorWindow(disableCapture: true)
.background(AppColors.background)
.preferredColorScheme(.dark)
}
.windowStyle(.hiddenTitleBar)
.windowToolbarStyle(.unified)
.defaultLaunchBehavior(.suppressed)
Settings {
SettingsView()
}
}
}
struct WindowAccessor: NSViewRepresentable {
var callback: (NSWindow?) -> Void
func makeNSView(context: Context) -> NSView {
let view = NSView()
DispatchQueue.main.async { [weak view] in
callback(view?.window)
}
return view
}
func updateNSView(_ nsView: NSView, context: Context) { }
}
extension View {
func configureEditorWindow(disableCapture: Bool = true) -> some View {
self.background(
WindowAccessor { window in
guard let window else { return }
if let screen = window.screen ?? NSScreen.main {
let visible = screen.visibleFrame
window.setFrame(visible, display: true)
window.minSize = visible.size
}
window.isMovable = true
window.isMovableByWindowBackground = false
window.sharingType = disableCapture ? .captureBlocked : .captureAllowed
}
)
}
}
This is a basic setup I did for now, this automatically fills the available width and height on launch, but user can resize and can go beyond my desired min width and height which makes the entire content inside messy.
As I said, I want a native way of doing this, respect the content aspect ratio, don't allow to enter full screen mode, only be able to fill the available width and height excluding the status bar and doc, also don't allow to resize below my desired width and height.
In trying to convert some Objective-C to Swift, I have a subclass of NSWindowController and want to write a convenience initializer. The documentation says
You can also implement an NSWindowController subclass to avoid requiring client code to get the corresponding nib’s filename and pass it to init(windowNibName:) or init(windowNibName:owner:) when instantiating the window controller. The best way to do this is to override windowNibName to return the nib’s filename and instantiate the window controller by passing nil to init(window:).
My attempt to do that looks like this:
class EdgeTab: NSWindowController
{
override var windowNibName: NSNib.Name? { "EdgeTab" }
required init?(coder: NSCoder)
{
super.init(coder: coder)
}
convenience init()
{
self.init( window: nil )
}
}
But I'm getting an error message saying "Incorrect argument label in call (have 'window:', expected 'coder:')". Why the heck is the compiler trying to use init(coder:) instead of init(window:)?
Hello
I'm using this sdk DeclaredAgeRange to get the user age range
When I'm doing in debug mode using sandbox account it is working as expected and I can get the user age range
But when I tried in TestFlight build using sandbox account it is not working and it is always return the age range 18+ and also isEligibleForAgeFeatures API is always returning false
Any advise on this?
Topic:
Programming Languages
SubTopic:
Swift
When I try to invoke the tkinter module in Python 3 that is bundled with Xcode Developer Tools, I get a message saying that my system version is too low:
$ /usr/bin/python3 -m tkinter
macOS 26 (2602) or later required, have instead 16 (1602) !
zsh: abort /usr/bin/python3 -m tkinter
It seems like the system version reported is macOS 16, which I assume is the version code before the decision to rename all OS platforms to 26. This is a very low level mistake and should be fixed as soon as possible.
Topic:
Programming Languages
SubTopic:
General
Can I use Xcode to create a playbook for soccer to design exercises and then show the exercise to the players later at practice or a game?
I need to integrate the roster with game plans and designed exercises with practice.
Hi all,
I'm working on a Call Directory Extension using CXCallDirectoryExtensionContext. I want to add a list of numbers to be blocked. Here's the function I use:
override func beginRequest(with context: CXCallDirectoryExtensionContext) {
context.delegate = self
let blockedNumbers = loadNumberEntries(forKey: blockedKey)
let identifiedNumbers = loadNumberEntries(forKey: identifiedKey)
addAllBlocking(blockedNumbers, to: context)
addAllIdentification(identifiedNumbers, to: context)
context.completeRequest()
}
private func addAllBlocking(_ entries: [NumberEntry], to context: CXCallDirectoryExtensionContext) {
let numbers: [Int64] = entries.compactMap {
Int64($0.countryCode + $0.phone)
}.sorted()
for number in numbers {
context.addBlockingEntry(withNextSequentialPhoneNumber: number)
print("# Added blocking entry: \(number)")
}
}
When I run this, I see in the console:
# Added blocking entry: (*my number with country code*)
So it seems the number is added correctly. However, in practice, the number is not blocked on the device.
I’ve made sure that:
The number is stored with the country code prefix.
The extension is enabled in Settings → Phone → Call Blocking & Identification.
The extension is reloaded after adding numbers.
The array of numbers is sorted in ascending order before calling addBlockingEntry.
Despite all this, the number still isn’t blocked.
Does anyone know why the print shows the number added, but it doesn’t actually block the call? Am I missing something in the way CXCallDirectoryExtensionContext works?
Thanks for any advice!
I am building a macOS utility using SwiftUI and Swift that records and displays keyboard shortcuts (like Cmd+C, Cmd+V) in the UI. To achieve this, I am using NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]).
I am aware that global monitoring usually requires the app to be non-sandboxed. However, I am seeing some behavior I don't quite understand during development:
I started with a fresh SwiftUI project and disabled the App Sandbox.
I requested Accessibility permissions using AXIsProcessTrustedWithOptions, manually enabled it in System Settings, and the global monitor worked perfectly.
I then re-enabled the App Sandbox in "Signing & Capabilities."
To my surprise, the app still records global events from other applications, even though the Sandbox is now active.
Is this expected behavior? Does macOS "remember" the trust because the Bundle ID was previously authorized while non-sandboxed, or is there a specific reason a Sandboxed app can still use addGlobalMonitor if the user has manually granted Accessibility access?
My app's core feature is displaying these shortcuts for the user's own reference (productivity tracking). If the user is the one explicitly granting permission via the Accessibility privacy pane, will Apple still reject the app for using global event monitors within a Sandboxed environment?
Code snippet of my monitor:
// This is still firing even after re-enabling Sandbox
eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: [.keyDown]) { event in
print("Captured: \(event.charactersIgnoringModifiers ?? "")")
}
I've tried cleaning the build folder and restarting the app, removing the app from accessibility permission, but the events keep coming through. I want to make sure I'm not relying on a "development glitch" before I commit to the App Store path.
Here is the full code anyone can use to try this :-
import SwiftUI
import Cocoa
import Combine
struct ShortcutEvent: Identifiable {
let id = UUID()
let displayString: String
let timestamp: Date
}
class KeyboardManager: ObservableObject {
@Published var isCapturing = false
@Published var capturedShortcuts: [ShortcutEvent] = []
private var eventMonitor: Any?
// 1. Check & Request Permissions
func checkAccessibilityPermissions() -> Bool {
let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String: true]
let accessEnabled = AXIsProcessTrustedWithOptions(options)
return accessEnabled
}
// 2. Start Capture
func startCapture() {
guard checkAccessibilityPermissions() else {
print("Permission denied")
return
}
isCapturing = true
let mask: NSEvent.EventTypeMask = [.keyDown, .keyUp]
eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: mask) { [weak self] event in
self?.processEvent(event)
}
}
// 3. Stop Capture
func stopCapture() {
if let monitor = eventMonitor {
NSEvent.removeMonitor(monitor)
eventMonitor = nil
}
isCapturing = false
}
private func processEvent(_ event: NSEvent) {
// Only log keyDown to avoid double-counting the UI display
guard event.type == .keyDown else { return }
var modifiers: [String] = []
var symbols: [String] = []
// Map symbols for the UI
if event.modifierFlags.contains(.command) {
modifiers.append("command")
symbols.append("⌘")
}
if event.modifierFlags.contains(.shift) {
modifiers.append("shift")
symbols.append("⇧")
}
if event.modifierFlags.contains(.option) {
modifiers.append("option")
symbols.append("⌥")
}
if event.modifierFlags.contains(.control) {
modifiers.append("control")
symbols.append("⌃")
}
let key = event.charactersIgnoringModifiers?.uppercased() ?? ""
// Only display if a modifier is active (to capture "shortcuts" vs regular typing)
if !symbols.isEmpty && !key.isEmpty {
let shortcutString = "\(symbols.joined(separator: " ")) + \(key)"
DispatchQueue.main.async {
// Insert at the top so the newest shortcut is visible
self.capturedShortcuts.insert(ShortcutEvent(displayString: shortcutString, timestamp: Date()), at: 0)
}
}
}
}
PS :- I just did another test by creating a fresh new project with the default App Sandbox enabled, and tried and there also it worked!!
Can I consider this a go to for MacOs app store than?