We're using IKPictureTaker to let users pick a room avatar image. The flow worked correctly on macOS 13–15, but breaks on macOS 26 (Tahoe).
Symptoms
popUpRecentsMenu(for:withDelegate:didEnd:contextInfo:) — no UI appears at all, and the didEnd selector is never called runModal() — a window appears but its content is completely blank (empty gray rectangle). The app freezes until the user force-quits Minimal reproduction
import Quartz
let pictureTaker = IKPictureTaker.pictureTaker()
pictureTaker?.setCommonValuesForKeys(allowsVideoCapture: true)
// Attempt 1 — silent fail, no UI, no callback
pictureTaker?.popUpRecentsMenu(for: someButton,
withDelegate: self,
didEnd: #selector(pictureTakerDidEnd),
contextInfo: nil)
// Attempt 2 — window appears but content is blank
let result = pictureTaker?.runModal()
// result is never returned while window is visible; app is frozen
Environment
macOS 26.0 (Tahoe) — reproducible by QA on multiple machines Xcode 16, Swift 5, deployment target macOS 10.14 Camera permission granted (AVAuthorizationStatus.authorized) App is sandboxed What I've ruled out
Camera permission is authorized before the call The view passed to popUpRecentsMenu has a valid, visible, key window Same code works on macOS 13, 14, 15
Question
Is this a known regression in macOS 26? Is IKPictureTaker expected to stop working, or is there a required entitlement / initialization step that changed? If the API is effectively unsupported, is NSOpenPanel with allowedContentTypes: [.image] the recommended migration path?
Hi @Quang-Damian,
You wrote:
[...] Is this a known regression in macOS 26? Is IKPictureTaker expected to stop working, or is there a required entitlement / initialization step that changed? [...]
This isn't surprising since IKPictureTaker is part of the legacy ImageKit framework—which has no Swift-native replacement, and still relied on legacy NSCell-based drawing paths that are no longer fully supported in the latest AppKit versions.
I'd suggest for you to submit a bug report via Feedback Assistant and explain your use case and reproduction steps. Once submitted, please reply here so I may escalate with the AppKit and CoreGraphics engineering teams directly.
Then, you wrote:
[...] If the API is effectively unsupported, is NSOpenPanel with allowedContentTypes: [.image] the recommended migration path?
Yes, NSOpenPanel (or PHPickerViewController if you ever need iOS parity) is the correct replacement. Please see the following example for guidance:
import AppKit
import UniformTypeIdentifiers
func pickAvatarImage(for window: NSWindow, completion: @escaping (NSImage?) -> Void) {
let panel = NSOpenPanel()
panel.allowedContentTypes = [.image]
panel.allowsMultipleSelection = false
panel.canChooseDirectories = false
panel.prompt = "Choose Avatar"
panel.beginSheetModal(for: window) { response in
guard response == .OK, let url = panel.url else {
completion(nil)
return
}
let image = NSImage(contentsOf: url)
completion(image)
}
}
If you also need the camera capture and crop/resize functionality that IKPictureTaker bundled together, you'll need to layer in additional components.
For camera capture (replacement for allowsVideoCapture):
- Import
AVFoundation. - Check authorization (you're already doing this(.
- Use AVCaptureSession and AVCapturePhotoOutput to grab a still.
- Present in your own sheet or popover.
For crop & resize (replacement for IKPictureTaker's built-in editor):
import CoreImage
func cropToSquare(_ image: NSImage, outputSize: CGSize) -> NSImage? {
guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else {
return nil
}
let side = min(cgImage.width, cgImage.height)
let originX = (cgImage.width - side) / 2
let originY = (cgImage.height - side) / 2
let cropRect = CGRect(x: originX, y: originY, width: side, height: side)
guard let cropped = cgImage.cropping(to: cropRect) else { return nil }
let result = NSImage(size: outputSize)
result.lockFocus()
NSGraphicsContext.current?.imageInterpolation = .high
let drawRect = NSRect(origin: .zero, size: outputSize)
NSImage(cgImage: cropped, size: outputSize).draw(in: drawRect)
result.unlockFocus()
return result
}
Cheers,
Paris X Pinkney | WWDR | DTS Engineer