{"id":6085,"library":"pyobjc-framework-contactsui","title":"PyObjC ContactsUI Framework","description":"PyObjC provides Python wrappers for Apple's ContactsUI framework on macOS, enabling Python applications to integrate with the system's contact selection interface. This library is part of the larger PyObjC bridge, which facilitates full-featured Cocoa application development in Python. Currently at version 12.1, PyObjC projects are actively maintained with releases often synchronized with major macOS SDK updates.","status":"active","version":"12.1","language":"en","source_language":"en","source_url":"https://github.com/ronaldoussoren/pyobjc","tags":["macos","cocoa","ui","contacts","pyobjc","apple"],"install":[{"cmd":"pip install pyobjc-framework-contactsui","lang":"bash","label":"Install latest version"}],"dependencies":[{"reason":"Core bridge for Python and Objective-C, required by all PyObjC framework wrappers.","package":"pyobjc-core","optional":false},{"reason":"Provides fundamental UI and application services, commonly required for macOS UI frameworks like ContactsUI.","package":"pyobjc-framework-Cocoa","optional":false}],"imports":[{"note":"Main class for displaying the contact picker.","symbol":"CNContactPickerViewController","correct":"from ContactsUI import CNContactPickerViewController"},{"note":"Standard import for Cocoa applications to manage the application lifecycle.","symbol":"NSApplication","correct":"from AppKit import NSApplication"},{"note":"Base class for most Objective-C objects, often used for delegate implementations.","symbol":"NSObject","correct":"from Foundation import NSObject"},{"note":"Protocol for handling contact picker events. Implement this in a Python class.","symbol":"CNContactPickerDelegate","correct":"from ContactsUI import CNContactPickerDelegate"},{"note":"Used for representing contacts, often in conjunction with ContactsUI results.","symbol":"CNContact","correct":"from Contacts import CNContact"}],"quickstart":{"code":"import objc\nfrom AppKit import NSApplication, NSApp, NSObject, NSWindow\nfrom ContactsUI import CNContactPickerViewController, CNContactPickerDelegate\nfrom Contacts import CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey\nfrom Foundation import NSLog\n\n\nclass ContactPickerDelegate(NSObject, CNContactPickerDelegate):\n    def contactPicker_didSelectContact_(self, picker, contact):\n        NSLog(\"Selected contact: %@ %@\", contact.givenName(), contact.familyName())\n        for phone_number in contact.phoneNumbers():\n            NSLog(\"  Phone: %@\", phone_number.value().stringValue())\n        picker.dismissViewControllerAnimated_completion_(True, None)\n        NSApp().stop_(None)\n\n    def contactPickerDidCancel_(self, picker):\n        NSLog(\"Contact picker cancelled\")\n        picker.dismissViewControllerAnimated_completion_(True, None)\n        NSApp().stop_(None)\n\n\ndef main():\n    app = NSApplication.sharedApplication()\n    delegate = ContactPickerDelegate.alloc().init()\n\n    picker = CNContactPickerViewController.alloc().init()\n    picker.setDelegate_(delegate)\n    picker.setDisplayedPropertyKeys_([CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey])\n\n    # Present the picker. In a real app, this would typically be triggered by a button click.\n    # For a simple script, we'll just present it directly from a dummy window or by itself.\n    # For a console app, it usually needs a backing NSApplication and a way to present it.\n    # Creating a minimal window to anchor it for this quickstart example.\n    from AppKit import NSWindow, NSBorderlessWindowMask, NSBackingStoreBuffered\n    from Foundation import NSMakeRect\n\n    dummy_window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(\n        NSMakeRect(0, 0, 1, 1), NSBorderlessWindowMask, NSBackingStoreBuffered, False\n    )\n    dummy_window.orderOut_(None)\n    app.activateIgnoringOtherApps_(True)\n    \n    app.beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(\n        picker.view(),\n        dummy_window,\n        None,  # No modal delegate needed for simple dismiss\n        None,\n        None\n    )\n    \n    # The picker is presented as a sheet, which requires the app run loop.\n    app.run()\n\nif __name__ == '__main__':\n    main()\n","lang":"python","description":"This quickstart demonstrates how to display a `CNContactPickerViewController` to allow the user to select contacts. It initializes an `NSApplication`, sets up a `CNContactPickerDelegate` to handle selection or cancellation, and then presents the picker as a sheet. The selected contact's name and phone numbers are logged. Note that running PyObjC UI code typically requires an active `NSApplication` event loop."},"warnings":[{"fix":"Ensure your Python environment meets the minimum version requirement for the PyObjC version you are installing or upgrading to. Use `pyenv` or `conda` to manage Python versions.","message":"PyObjC frequently drops support for older Python versions. For example, version 12.0 dropped support for Python 3.9, and version 11.0 dropped Python 3.8. Always check the release notes for minimum Python version requirements before upgrading.","severity":"breaking","affected_versions":"11.0, 12.0+"},{"fix":"Always install the PyObjC version that is compatible with your macOS SDK. Use `pip install pyobjc` (or a specific framework like `pyobjc-framework-contactsui`) on the target machine to ensure the correct wheels are installed for your OS and Python version.","message":"PyObjC versions are tightly coupled with macOS SDKs. Installing an older PyObjC version with a newer macOS SDK, or vice-versa, can lead to build errors or runtime issues due to missing or changed APIs.","severity":"breaking","affected_versions":"All versions"},{"fix":"When calling Objective-C methods from Python via PyObjC, convert all colons in the Objective-C selector to underscores in the Python method name. Ensure the number of arguments passed matches the number of underscores/colons.","message":"Objective-C selectors with colons (e.g., `doSomething:withSomethingElse:`) are translated into Python method names with underscores (e.g., `doSomething_withSomethingElse_`). Each underscore represents an argument.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review code that manually manages object lifetimes or relies on specific `alloc().init()` reference counting behavior, especially when subclassing Objective-C classes. In most cases, PyObjC handles this automatically, but custom memory management code might need adjustments.","message":"Starting with PyObjC 11.1, the core bridge aligns with `clang`'s Automatic Reference Counting (ARC) documentation for initializer methods. Methods in the 'init' family now correctly steal a reference to `self` and return a new reference, which might change reference counting behavior in complex `alloc().init()` patterns.","severity":"gotcha","affected_versions":"11.1+"},{"fix":"If experiencing issues with `__init__` not being called after `__new__`, ensure you are on `pyobjc` 10.3.1 or later. If relying on PyObjC's default `__new__`, avoid implementing `__init__` in a way that bypasses Objective-C's two-phase initialization (alloc/init).","message":"PyObjC 10.3 introduced changes that could break `__init__` when a class (or its superclass) defines its own `__new__`. Version 10.3.1 partially reverted this, reintroducing the ability to use `__init__` if `__new__` is user-implemented, but not for PyObjC's provided `__new__`.","severity":"gotcha","affected_versions":"10.3 - 10.3.1"},{"fix":"Periodically review Apple's developer documentation for framework deprecations and plan to update your application's dependencies and code to newer frameworks as needed when upgrading PyObjC or macOS.","message":"PyObjC removes bindings for macOS frameworks that are deprecated and removed by Apple in newer macOS SDKs. For example, `IMServicePlugIn` bindings were removed in PyObjC 10.0 because the framework was deprecated in macOS 10.13 and removed in macOS 14.","severity":"deprecated","affected_versions":"10.0+"}],"env_vars":null,"last_verified":"2026-04-14T00:00:00.000Z","next_check":"2026-07-13T00:00:00.000Z","problems":[]}