Skip to content

Commit

Permalink
implement a single dealloc replacement for all properties
Browse files Browse the repository at this point in the history
  • Loading branch information
Sam Schott committed Jul 6, 2021
1 parent b6d2f15 commit bd70e4e
Showing 1 changed file with 28 additions and 19 deletions.
47 changes: 28 additions & 19 deletions rubicon/objc/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,27 +445,18 @@ def _objc_setter(objc_self, _cmd, new_value):
attrs = self._get_property_attributes()
libobjc.class_addProperty(class_ptr, ensure_bytes(attr_name), attrs, len(attrs))

# Add cleanup routines to dealloc.
def dealloc_callback(self, objc_self, attr_name):

old_dealloc = libobjc.class_getMethodImplementation(class_ptr, SEL("dealloc"))

def _new_delloc(objc_self, _cmd):

# Clean up ivar.
if self.weak:
# Clean up weak reference.
set_ivar(objc_self, ivar_name, self.vartype(None), weak=True)
elif issubclass(self.vartype, objc_id):
# If the old value is a non-null object, release it. There is no need to set the actual ivar to nil.
old_value = get_ivar(objc_self, ivar_name, weak=self.weak)
send_message(old_value, 'release', restype=None, argtypes=[])

# Invoke original dealloc.
cfunctype = CFUNCTYPE(None, objc_id, SEL)
old_dealloc_callable = cast(old_dealloc, cfunctype)
old_dealloc_callable(objc_self, SEL("dealloc"))
ivar_name = '_' + attr_name

add_method(class_ptr, 'dealloc', _new_delloc, [None, ObjCInstance, SEL], replace=True)
# Clean up ivar.
if self.weak:
# Clean up weak reference.
set_ivar(objc_self, ivar_name, self.vartype(None), weak=True)
elif issubclass(self.vartype, objc_id):
# If the old value is a non-null object, release it. There is no need to set the actual ivar to nil.
old_value = get_ivar(objc_self, ivar_name, weak=self.weak)
send_message(old_value, 'release', restype=None, argtypes=[])

def protocol_register(self, proto_ptr, attr_name):
attrs = self._get_property_attributes()
Expand Down Expand Up @@ -1009,6 +1000,24 @@ def _new_from_class_statement(cls, name, bases, attrs, *, protocols):
else:
class_register(ptr, attr_name)

# Add cleanup of ivars / properties to dealloc

old_dealloc = libobjc.class_getMethodImplementation(ptr, SEL("dealloc"))

def _new_delloc(objc_self, _cmd):

# Invoke dealloc callback of each property.
for attr_name, obj in attrs.items():
if isinstance(obj, objc_property):
obj.dealloc_callback(objc_self, attr_name)

# Invoke original dealloc.
cfunctype = CFUNCTYPE(None, objc_id, SEL)
old_dealloc_callable = cast(old_dealloc, cfunctype)
old_dealloc_callable(objc_self, SEL("dealloc"))

add_method(ptr, "dealloc", _new_delloc, [None, ObjCInstance, SEL], replace=True)

# Register the ObjC class
libobjc.objc_registerClassPair(ptr)

Expand Down

0 comments on commit bd70e4e

Please sign in to comment.