PyObjC is a bridge between Python and Objective-C that allows full featured Cocoa applications to be written in pure Python.
—
Protocol management, formal and informal protocol definition, and protocol conformance checking. Protocols in Objective-C define interfaces that classes can implement, similar to interfaces in other languages. PyObjC provides comprehensive support for working with both formal and informal protocols.
Functions for finding and accessing existing Objective-C protocols.
def protocolNamed(name: str):
"""
Get an Objective-C protocol by name.
Args:
name (str): Name of the protocol to retrieve
Returns:
The protocol object, or None if not found
Usage:
ns_copying = objc.protocolNamed("NSCopying")
if ns_copying:
print("Found NSCopying protocol")
"""
def protocolsForClass(cls):
"""
Get all protocols implemented by a class.
Args:
cls: The Objective-C class to examine
Returns:
list: List of protocol objects implemented by the class
Usage:
protocols = objc.protocolsForClass(NSString)
for protocol in protocols:
print(f"NSString implements: {protocol.name}")
"""
def protocolsForProcess():
"""
Get all protocols available in the current process.
Returns:
list: List of all registered protocol objects
Usage:
all_protocols = objc.protocolsForProcess()
print(f"Found {len(all_protocols)} protocols")
"""Functions for defining new formal and informal protocols.
def formal_protocol(name: str, supers, selectors):
"""
Define a new formal Objective-C protocol.
Args:
name (str): Name for the new protocol
supers: Parent protocols (can be None)
selectors: Dictionary of method selectors and their signatures
Returns:
The newly created protocol object
Usage:
my_protocol = objc.formal_protocol(
"MyCustomProtocol",
(objc.protocolNamed("NSObject"),),
{
"doSomething": objc.signature("v@:"),
"getSomething": objc.signature("@@:")
}
)
"""
def informal_protocol(name: str, selectors):
"""
Define a new informal Objective-C protocol.
Args:
name (str): Name for the informal protocol
selectors: Dictionary of optional method selectors
Informal protocols define optional methods that classes may implement.
They are used for delegation patterns and optional functionality.
Usage:
objc.informal_protocol(
"MyDelegate",
{
"willStartProcessing": objc.signature("v@:"),
"didFinishProcessing:": objc.signature("v@:@")
}
)
"""The Protocol class represents Objective-C protocol objects.
class Protocol:
"""
Represents an Objective-C protocol object.
Provides access to protocol metadata, method signatures,
and conformance information.
"""
def name(self) -> str:
"""Get the protocol name."""
def conformsToProtocol_(self, protocol) -> bool:
"""Check if this protocol conforms to another protocol."""
def methodDescriptionForSelector_isRequiredMethod_isInstanceMethod_(
self, selector: str, required: bool, instance: bool
):
"""Get method description for a specific selector."""import objc
from Foundation import NSString, NSMutableString
# Get the NSCopying protocol
copying_protocol = objc.protocolNamed("NSCopying")
if copying_protocol:
print(f"Protocol name: {copying_protocol.name()}")
# Check if NSString conforms to NSCopying
protocols = objc.protocolsForClass(NSString)
if copying_protocol in protocols:
print("NSString implements NSCopying")import objc
# Define a formal protocol
drawable_protocol = objc.formal_protocol(
"Drawable",
None, # No parent protocols
{
"draw": objc.signature("v@:"),
"drawInRect:": objc.signature("v@:{CGRect=dddd}"),
"canDraw": objc.signature("c@:")
}
)
# Create a class that implements the protocol
class MyDrawableView(NSView):
def draw(self):
"""Required method from Drawable protocol."""
# Drawing implementation
pass
@objc.signature("v@:{CGRect=dddd}")
def drawInRect_(self, rect):
"""Draw in a specific rectangle."""
# Rectangle-specific drawing
pass
def canDraw(self):
"""Check if drawing is possible."""
return Trueimport objc
# Define an informal protocol for delegation
objc.informal_protocol(
"MyProcessorDelegate",
{
"processorWillStart:": objc.signature("v@:@"),
"processor:didProcessItem:": objc.signature("v@:@@"),
"processor:didFailWithError:": objc.signature("v@:@@"),
"processorDidFinish:": objc.signature("v@:@")
}
)
# Create a processor class that uses the delegate
class MyProcessor(NSObject):
def setDelegate_(self, delegate):
self._delegate = delegate
def startProcessing(self):
# Notify delegate if it implements the method
if hasattr(self._delegate, 'processorWillStart_'):
self._delegate.processorWillStart_(self)
# Do processing...
for item in self._items:
if hasattr(self._delegate, 'processor_didProcessItem_'):
self._delegate.processor_didProcessItem_(self, item)
# Notify completion
if hasattr(self._delegate, 'processorDidFinish_'):
self._delegate.processorDidFinish_(self)
# Create a delegate class
class MyDelegate(NSObject):
def processorWillStart_(self, processor):
print("Processing started")
def processor_didProcessItem_(self, processor, item):
print(f"Processed item: {item}")
def processorDidFinish_(self, processor):
print("Processing completed")import objc
from Foundation import NSArray, NSString
# Check what protocols a class implements
string_protocols = objc.protocolsForClass(NSString)
array_protocols = objc.protocolsForClass(NSArray)
print("NSString protocols:")
for protocol in string_protocols:
print(f" - {protocol.name()}")
print("NSArray protocols:")
for protocol in array_protocols:
print(f" - {protocol.name()}")
# Check if a specific protocol is implemented
copying_protocol = objc.protocolNamed("NSCopying")
if copying_protocol in string_protocols:
print("NSString implements NSCopying")
# Check protocol inheritance
coding_protocol = objc.protocolNamed("NSCoding")
if coding_protocol and copying_protocol:
conforms = coding_protocol.conformsToProtocol_(copying_protocol)
print(f"NSCoding conforms to NSCopying: {conforms}")import objc
from Foundation import NSObject
# Create a class that explicitly conforms to NSCopying
class MyCopiableClass(NSObject):
def initWithValue_(self, value):
self = objc.super(MyCopiableClass, self).init()
if self is None:
return None
self._value = value
return self
def copyWithZone_(self, zone):
"""Implement NSCopying protocol."""
return MyCopiableClass.alloc().initWithValue_(self._value)
def value(self):
return self._value
# Verify the class works with copying
original = MyCopiableClass.alloc().initWithValue_("Hello")
copy = original.copy()
print(f"Original value: {original.value()}") # "Hello"
print(f"Copy value: {copy.value()}") # "Hello"
print(f"Same object: {original is copy}") # FalseInstall with Tessl CLI
npx tessl i tessl/pypi-pyobjc