macOS 27 introduces NSTextSelectionManager for custom text selection in any view, while reinforcing best practices for gesture recognizers, keyboard navigation, and NSWindowRestoration to make AppKit apps feel native and resilient.
⢠NSTextSelectionManager introduced in macOS 27 as a new API bringing gesture-recognizer-backed text selection to arbitrary views
⢠NSStatusItem expanded interface session lifecycle API clarified and promoted for custom popup windows
⢠preventsApplicationTerminationWhenModal guidance updated to encourage setting false for non-data-critical sheets
⢠Control events (NSControlEvents) confirmed available back to 10.11 and now officially recommended over mouseDown overrides
⢠NSTextSelectionManager is a new macOS 27 API that brings full bidirectional text selection, drag-and-drop, and toggle behaviors to any custom view without subclassing NSTextView
⢠Proper NSWindowRestoration ensures apps quit gracefully during system reboots and relaunch exactly where users left off, a growing expectation on modern macOS
⢠Adopting gesture recognizers and control events instead of mouseDown overrides enables cross-framework compatibility with SwiftUI and Mac Catalyst components
Demonstrates NSWindowRestoration with encodeRestorableState and restoreState so a sidebar selection survives app quit and relaunch on macOS 27.
import AppKitā// Pre-macOS 27 approach: manual state saving via UserDefaults,ā// no NSWindowRestoration, window position not automatically preserved.+// MARK: - Restoration Class+class MainWindowRestoration: NSObject, NSWindowRestoration {+ static func restoreWindow(+ withIdentifier identifier: NSUserInterfaceItemIdentifier,+ state: NSCoder,+ completionHandler: @escaping (NSWindow?, Error?) -> Void+ ) {+ let appDelegate = NSApp.delegate as! AppDelegate+ if identifier.rawValue == "MainWindow" {+ // Reuse the existing main window+ completionHandler(appDelegate.mainWindowController.window, nil)+ } else {+ let error = NSError(+ domain: "com.example.app",+ code: 1,+ userInfo: [NSLocalizedDescriptionKey: "Unknown window identifier"]+ )+ completionHandler(nil, error)+ }+ }+}āclass LegacyWindowController: NSWindowController {+// MARK: - Window Controller+class MainWindowController: NSWindowController {private let selectedProductKey = "selectedProductIdentifier"+ var selectedProductIdentifier: String = "product-1"override func windowDidLoad() {super.windowDidLoad()ā // Restore from UserDefaults manuallyā if let saved = UserDefaults.standard.string(forKey: selectedProductKey) {ā (contentViewController as? LegacyProductViewController)?.select(productID: saved)ā }+ guard let window else { return }+ // Enable state restoration+ window.identifier = NSUserInterfaceItemIdentifier("MainWindow")+ window.isRestorable = true+ window.restorationClass = MainWindowRestoration.self+ window.setFrameAutosaveName("MainWindow")}func selectProduct(_ identifier: String) {ā // Save immediately to UserDefaults ā no invalidation modelā UserDefaults.standard.set(identifier, forKey: selectedProductKey)+ selectedProductIdentifier = identifier+ // Notify AppKit that restorable state has changed+ invalidateRestorableState()}++ override func encodeRestorableState(with coder: NSCoder) {+ super.encodeRestorableState(with: coder)+ coder.encode(selectedProductIdentifier, forKey: selectedProductKey)+ }++ override func restoreState(with coder: NSCoder) {+ super.restoreState(with: coder)+ if let identifier = coder.decodeObject(forKey: selectedProductKey) as? String {+ selectedProductIdentifier = identifier+ // Push restored selection into your view controller here+ (contentViewController as? ProductViewController)?.select(productID: identifier)+ }+ }}āclass LegacyProductViewController: NSViewController {+// MARK: - Stub view controller+class ProductViewController: NSViewController {func select(productID: String) {ā print("Restored selection (legacy): \(productID)")+ // Update UI to reflect restored selection+ print("Restored selection: \(productID)")}+}++// MARK: - AppDelegate stub+class AppDelegate: NSObject, NSApplicationDelegate {+ let mainWindowController = MainWindowController(windowNibName: "MainWindow")}
Liquid Glass is Apple's new material and visual design language introduced in iOS 27, bringing translucent, refractive glass-like surfaces to system and custom UI elements. It replaces the frosted vibrancy aesthetic with a more dynamic, depth-aware material that responds to content beneath it.
PaperKit is Apple's full-featured canvas framework ā previously internal-only ā now publicly available in iOS/macOS/visionOS 27. It powers the drawing and markup experience in Notes, Preview, and Freeform, giving developers access to a complete pencil, shapes, images, and text canvas with a rich data model.
Xcode 27 introduces a fully customizable toolbar and theme system, untitled scratch projects, coding agent integration directly in the editor, and the new Device Hub for evaluating apps across simulators and physical devices side-by-side.
In-depth guide
SwiftUI & Liquid Glass in iOS 27 āNSTextSelectionManager is new in macOS 27 ā do not attempt to use it on earlier OS versions without availability checks. invalidateRestorableState() must be called whenever UI state changes or encodeRestorableState will not be triggered. Always call the completionHandler in restoreWindow(withIdentifier:) even on failure, or AppKit will hang at launch.
Mac only; not applicable to iOS or iPadOS
iOS 27 introduces new SwiftUI drag and drop APIs including reorderable, reorderContainer, dragContainer, and configuration modifiers that enable reordering within and across collections, multi-item drag, and fine-grained control over how data is transferred during drag and drop operations.