From 2b5d9d00288bc4389e5c48eab924e0aaabc062d6 Mon Sep 17 00:00:00 2001 From: Sam Schott Date: Sat, 23 Nov 2024 12:28:35 +0100 Subject: [PATCH 01/12] Remove unneeded autoreleases Those were used to prevent rubicon from releasing an object immediately when going out of scope and delaying this instead until after ObjC can take ownership. --- cocoa/src/toga_cocoa/widgets/detailedlist.py | 2 +- cocoa/src/toga_cocoa/widgets/table.py | 4 ---- cocoa/src/toga_cocoa/widgets/tree.py | 4 ---- iOS/src/toga_iOS/widgets/detailedlist.py | 6 ++---- 4 files changed, 3 insertions(+), 13 deletions(-) diff --git a/cocoa/src/toga_cocoa/widgets/detailedlist.py b/cocoa/src/toga_cocoa/widgets/detailedlist.py index 8e007deee0..d1a17875ca 100644 --- a/cocoa/src/toga_cocoa/widgets/detailedlist.py +++ b/cocoa/src/toga_cocoa/widgets/detailedlist.py @@ -37,7 +37,7 @@ def menuForEvent_(self, event): ) # Create a popup menu to display the possible actions. - popup = NSMenu.alloc().initWithTitle("popup").autorelease() + popup = NSMenu.alloc().initWithTitle("popup") if self.impl.primary_action_enabled: primary_action_item = popup.addItemWithTitle( self.interface._primary_action, diff --git a/cocoa/src/toga_cocoa/widgets/table.py b/cocoa/src/toga_cocoa/widgets/table.py index 635cf6e55e..c99cbde8ef 100644 --- a/cocoa/src/toga_cocoa/widgets/table.py +++ b/cocoa/src/toga_cocoa/widgets/table.py @@ -71,10 +71,6 @@ def tableView_viewForTableColumn_row_(self, table, column, row: int): tcv = TogaIconView.alloc().init() tcv.identifier = identifier - # Prevent tcv from being deallocated prematurely when no Python references - # are left - tcv.autorelease() - tcv.setText(str(value)) if icon: tcv.setImage(icon._impl.native) diff --git a/cocoa/src/toga_cocoa/widgets/tree.py b/cocoa/src/toga_cocoa/widgets/tree.py index 889481904b..48d723b6b0 100644 --- a/cocoa/src/toga_cocoa/widgets/tree.py +++ b/cocoa/src/toga_cocoa/widgets/tree.py @@ -99,10 +99,6 @@ def outlineView_viewForTableColumn_item_(self, tree, column, item): tcv = TogaIconView.alloc().init() tcv.identifier = identifier - # Prevent tcv from being deallocated prematurely when no Python references - # are left - tcv.autorelease() - tcv.setText(str(value)) if icon: tcv.setImage(icon._impl.native) diff --git a/iOS/src/toga_iOS/widgets/detailedlist.py b/iOS/src/toga_iOS/widgets/detailedlist.py index c124c65068..5dd9b8a51a 100644 --- a/iOS/src/toga_iOS/widgets/detailedlist.py +++ b/iOS/src/toga_iOS/widgets/detailedlist.py @@ -39,10 +39,8 @@ def tableView_numberOfRowsInSection_(self, tableView, section: int) -> int: def tableView_cellForRowAtIndexPath_(self, tableView, indexPath): cell = tableView.dequeueReusableCellWithIdentifier("row") if cell is None: - cell = ( - UITableViewCell.alloc() - .initWithStyle(UITableViewCellStyleSubtitle, reuseIdentifier="row") - .autorelease() + cell = UITableViewCell.alloc().initWithStyle( + UITableViewCellStyleSubtitle, reuseIdentifier="row" ) value = self.interface.data[indexPath.item] From 464d524d52674498e7819e01fa15bed160fbac15 Mon Sep 17 00:00:00 2001 From: Sam Schott Date: Sat, 23 Nov 2024 12:29:23 +0100 Subject: [PATCH 02/12] Remove unneeded cache retains --- cocoa/src/toga_cocoa/colors.py | 3 +-- cocoa/src/toga_cocoa/fonts.py | 2 +- iOS/src/toga_iOS/colors.py | 3 +-- iOS/src/toga_iOS/fonts.py | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/cocoa/src/toga_cocoa/colors.py b/cocoa/src/toga_cocoa/colors.py index e204d36cfa..80c86195d2 100644 --- a/cocoa/src/toga_cocoa/colors.py +++ b/cocoa/src/toga_cocoa/colors.py @@ -10,10 +10,9 @@ def native_color(c): try: color = CACHE[c] except KeyError: - # Color needs to be retained to be kept in cache. color = NSColor.colorWithRed( c.rgba.r / 255, green=c.rgba.g / 255, blue=c.rgba.b / 255, alpha=c.rgba.a - ).retain() + ) CACHE[c] = color return color diff --git a/cocoa/src/toga_cocoa/fonts.py b/cocoa/src/toga_cocoa/fonts.py index a8a902ab64..d6fa949b47 100644 --- a/cocoa/src/toga_cocoa/fonts.py +++ b/cocoa/src/toga_cocoa/fonts.py @@ -124,6 +124,6 @@ def __init__(self, interface): else: attributed_font = font - _FONT_CACHE[self.interface] = attributed_font.retain() + _FONT_CACHE[self.interface] = attributed_font self.native = attributed_font diff --git a/iOS/src/toga_iOS/colors.py b/iOS/src/toga_iOS/colors.py index 25d80f3360..847233de66 100644 --- a/iOS/src/toga_iOS/colors.py +++ b/iOS/src/toga_iOS/colors.py @@ -11,10 +11,9 @@ def native_color(c): try: color = CACHE[c] except KeyError: - # Color needs to be retained to be kept in the cache color = UIColor.colorWithRed( c.rgba.r / 255, green=c.rgba.g / 255, blue=c.rgba.b / 255, alpha=c.rgba.a - ).retain() + ) CACHE[c] = color return color diff --git a/iOS/src/toga_iOS/fonts.py b/iOS/src/toga_iOS/fonts.py index e34dfa830d..fa9585b898 100644 --- a/iOS/src/toga_iOS/fonts.py +++ b/iOS/src/toga_iOS/fonts.py @@ -123,6 +123,6 @@ def __init__(self, interface): else: attributed_font = font - _FONT_CACHE[self.interface] = attributed_font.retain() + _FONT_CACHE[self.interface] = attributed_font self.native = attributed_font From a658bd7c28b3ac339f264b207d5215446193bd11 Mon Sep 17 00:00:00 2001 From: Sam Schott Date: Sat, 23 Nov 2024 12:30:29 +0100 Subject: [PATCH 03/12] Remove unneeded retain / release pairs --- cocoa/src/toga_cocoa/constraints.py | 13 ++++--------- cocoa/src/toga_cocoa/container.py | 6 ++---- cocoa/src/toga_cocoa/statusicons.py | 3 +-- cocoa/src/toga_cocoa/window.py | 15 +++------------ iOS/src/toga_iOS/constraints.py | 13 ++++--------- iOS/src/toga_iOS/dialogs.py | 2 +- iOS/src/toga_iOS/icons.py | 8 -------- iOS/src/toga_iOS/images.py | 6 ------ 8 files changed, 15 insertions(+), 51 deletions(-) diff --git a/cocoa/src/toga_cocoa/constraints.py b/cocoa/src/toga_cocoa/constraints.py index ca635a6301..6c545c4a30 100644 --- a/cocoa/src/toga_cocoa/constraints.py +++ b/cocoa/src/toga_cocoa/constraints.py @@ -44,11 +44,6 @@ def _remove_constraints(self): self.container.native.removeConstraint(self.left_constraint) self.container.native.removeConstraint(self.top_constraint) - self.width_constraint.release() - self.height_constraint.release() - self.left_constraint.release() - self.top_constraint.release() - @property def container(self): return self._container @@ -70,7 +65,7 @@ def container(self, value): attribute__2=NSLayoutAttributeLeft, multiplier=1.0, constant=10, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.left_constraint) self.top_constraint = NSLayoutConstraint.constraintWithItem( @@ -81,7 +76,7 @@ def container(self, value): attribute__2=NSLayoutAttributeTop, multiplier=1.0, constant=5, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.top_constraint) self.width_constraint = NSLayoutConstraint.constraintWithItem( @@ -92,7 +87,7 @@ def container(self, value): attribute__2=NSLayoutAttributeLeft, multiplier=1.0, constant=50, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.width_constraint) self.height_constraint = NSLayoutConstraint.constraintWithItem( @@ -103,7 +98,7 @@ def container(self, value): attribute__2=NSLayoutAttributeTop, multiplier=1.0, constant=30, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.height_constraint) def update(self, x, y, width, height): diff --git a/cocoa/src/toga_cocoa/container.py b/cocoa/src/toga_cocoa/container.py index 8979114082..d855cbbbbe 100644 --- a/cocoa/src/toga_cocoa/container.py +++ b/cocoa/src/toga_cocoa/container.py @@ -67,7 +67,7 @@ def __init__( attribute__2=NSLayoutAttributeLeft, multiplier=1.0, constant=min_width, - ).retain() + ) self.native.addConstraint(self._min_width_constraint) self._min_height_constraint = NSLayoutConstraint.constraintWithItem( @@ -78,12 +78,10 @@ def __init__( attribute__2=NSLayoutAttributeTop, multiplier=1.0, constant=min_height, - ).retain() + ) self.native.addConstraint(self._min_height_constraint) def __del__(self): - self._min_height_constraint.release() - self._min_width_constraint.release() self.native = None @property diff --git a/cocoa/src/toga_cocoa/statusicons.py b/cocoa/src/toga_cocoa/statusicons.py index 3327c38139..688f4fc88d 100644 --- a/cocoa/src/toga_cocoa/statusicons.py +++ b/cocoa/src/toga_cocoa/statusicons.py @@ -30,13 +30,12 @@ def set_icon(self, icon): def create(self): self.native = NSStatusBar.systemStatusBar.statusItemWithLength( NSSquareStatusItemLength - ).retain() + ) self.native.button.toolTip = self.interface.text self.set_icon(self.interface.icon) def remove(self): NSStatusBar.systemStatusBar.removeStatusItem(self.native) - self.native.release() self.native = None diff --git a/cocoa/src/toga_cocoa/window.py b/cocoa/src/toga_cocoa/window.py index 5a0604c7d6..58086c16c8 100644 --- a/cocoa/src/toga_cocoa/window.py +++ b/cocoa/src/toga_cocoa/window.py @@ -105,10 +105,6 @@ def toolbar_itemForItemIdentifier_willBeInsertedIntoToolbar_( except KeyError: # Separator items pass - # Prevent the toolbar item from being deallocated when - # no Python references remain - native.retain() - native.autorelease() return native @objc_method @@ -162,9 +158,9 @@ def __init__(self, interface, title, position, size): # Cocoa releases windows when they are closed; this causes havoc with # Toga's widget cleanup because the ObjC runtime thinks there's no - # references to the object left. Add a reference that can be released - # in response to the close. - self.native.retain() + # references to the object left. Explicitly prevent this and let Rubicon + # manage the release when no Python references are left. + self.native.releasedWhenClosed = False self.set_title(title) self.set_size(size) @@ -179,9 +175,6 @@ def __init__(self, interface, title, position, size): self.native.wantsLayer = True self.container.native.backgroundColor = self.native.backgroundColor - def __del__(self): - self.native.release() - ###################################################################### # Window properties ###################################################################### @@ -326,7 +319,6 @@ def __init__(self, interface, title, position, size): def __del__(self): self.purge_toolbar() - super().__del__() def create_menus(self): # macOS doesn't have window-level menus @@ -373,4 +365,3 @@ def purge_toolbar(self): for item_native in dead_items: cmd._impl.native.remove(item_native) - item_native.release() diff --git a/iOS/src/toga_iOS/constraints.py b/iOS/src/toga_iOS/constraints.py index dc3e4df076..9d8da1d57e 100644 --- a/iOS/src/toga_iOS/constraints.py +++ b/iOS/src/toga_iOS/constraints.py @@ -39,11 +39,6 @@ def _remove_constraints(self): self.container.native.removeConstraint(self.left_constraint) self.container.native.removeConstraint(self.top_constraint) - self.width_constraint.release() - self.height_constraint.release() - self.left_constraint.release() - self.top_constraint.release() - @property def container(self): return self._container @@ -65,7 +60,7 @@ def container(self, value): attribute__2=NSLayoutAttributeLeft, multiplier=1.0, constant=10, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.left_constraint) self.top_constraint = NSLayoutConstraint.constraintWithItem( @@ -76,7 +71,7 @@ def container(self, value): attribute__2=NSLayoutAttributeTop, multiplier=1.0, constant=5, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.top_constraint) self.width_constraint = NSLayoutConstraint.constraintWithItem( @@ -87,7 +82,7 @@ def container(self, value): attribute__2=NSLayoutAttributeLeft, multiplier=1.0, constant=50, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.width_constraint) self.height_constraint = NSLayoutConstraint.constraintWithItem( @@ -98,7 +93,7 @@ def container(self, value): attribute__2=NSLayoutAttributeTop, multiplier=1.0, constant=30, # Use a dummy, non-zero value for now - ).retain() + ) self.container.native.addConstraint(self.height_constraint) def update(self, x, y, width, height): diff --git a/iOS/src/toga_iOS/dialogs.py b/iOS/src/toga_iOS/dialogs.py index c2c97d6af3..13a043965e 100644 --- a/iOS/src/toga_iOS/dialogs.py +++ b/iOS/src/toga_iOS/dialogs.py @@ -34,7 +34,7 @@ def __init__(self, title, message): self.native = UIAlertController.alertControllerWithTitle( title, message=message, preferredStyle=UIAlertControllerStyle.Alert - ).retain() + ) self.populate_dialog() diff --git a/iOS/src/toga_iOS/icons.py b/iOS/src/toga_iOS/icons.py index 25a7b3e83f..53611e8869 100644 --- a/iOS/src/toga_iOS/icons.py +++ b/iOS/src/toga_iOS/icons.py @@ -23,14 +23,6 @@ def __init__(self, interface, path): if self.native is None: raise ValueError(f"Unable to load icon from {path}") - # Multiple icon interface instances can end up referencing the same native - # instance, so make sure we retain a reference count at the impl level. - self.native.retain() - - def __del__(self): - if self.native: - self.native.release() - def _as_size(self, size): renderer = UIGraphicsImageRenderer.alloc().initWithSize(NSSize(size, size)) diff --git a/iOS/src/toga_iOS/images.py b/iOS/src/toga_iOS/images.py index 5ab906ecf0..99872079d3 100644 --- a/iOS/src/toga_iOS/images.py +++ b/iOS/src/toga_iOS/images.py @@ -36,12 +36,6 @@ def __init__(self, interface, path=None, data=None, raw=None): else: self.native = raw - self.native.retain() - - def __del__(self): - if self.native: - self.native.release() - def get_width(self): return self.native.size.width From 94a3d0fed549c2abfeb7352dea2e07f3111ab047 Mon Sep 17 00:00:00 2001 From: Sam Schott Date: Sat, 23 Nov 2024 12:32:50 +0100 Subject: [PATCH 04/12] prevent duplicate release of NSImage --- cocoa/src/toga_cocoa/icons.py | 37 +++++++++------------- cocoa/src/toga_cocoa/images.py | 57 +++++++++++++--------------------- 2 files changed, 36 insertions(+), 58 deletions(-) diff --git a/cocoa/src/toga_cocoa/icons.py b/cocoa/src/toga_cocoa/icons.py index da25d207e3..039c2745d0 100644 --- a/cocoa/src/toga_cocoa/icons.py +++ b/cocoa/src/toga_cocoa/icons.py @@ -38,29 +38,20 @@ def __init__(self, interface, path): else: self.path = path - try: - # We *should* be able to do a direct NSImage.alloc.init...(), but if the - # image file is invalid, the init fails, returns NULL, and releases the - # Objective-C object. Since we've created an ObjC instance, when the - # object passes out of scope, Rubicon tries to free it, which segfaults. - # To avoid this, we retain result of the alloc() (overriding the default - # Rubicon behavior of alloc), then release that reference once we're - # done. If the image was created successfully, we temporarily have a - # reference count that is 1 higher than it needs to be; if it fails, we - # don't end up with a stray release. - image = NSImage.alloc().retain() - self.native = image.initWithContentsOfFile(str(path)) - if self.native is None: - raise ValueError(f"Unable to load icon from {path}") - finally: - # Calling `release` here disabled Rubicon's "release on delete" automation. - # We therefore add an explicit `release` call in __del__ if the NSImage was - # initialized successfully. - image.release() - - def __del__(self): - if self.native: - self.native.release() + # We *should* be able to do a direct NSImage.alloc.init...(), but if the + # image file is invalid, the init fails, returns NULL, and releases the + # Objective-C object. Since we've created an ObjC instance, when the + # object passes out of scope, Rubicon tries to free it, which segfaults. + # To avoid this, we retain result of the alloc() (overriding the default + # Rubicon behavior of alloc), then release that reference once we're + # done. If the image was created successfully, we temporarily have a + # reference count that is 1 higher than it needs to be; if it fails, we + # don't end up with a stray release. + image = NSImage.alloc().retain() + self.native = image.initWithContentsOfFile(str(path)) + if self.native is None: + raise ValueError(f"Unable to load icon from {path}") + image.release() def _as_size(self, size): image = self.native.copy() diff --git a/cocoa/src/toga_cocoa/images.py b/cocoa/src/toga_cocoa/images.py index 687a5e8dff..6e6105b360 100644 --- a/cocoa/src/toga_cocoa/images.py +++ b/cocoa/src/toga_cocoa/images.py @@ -23,43 +23,30 @@ class Image: def __init__(self, interface, path=None, data=None, raw=None): self.interface = interface - self._needs_release = False - try: - # We *should* be able to do a direct NSImage.alloc.init...(), but if the - # image file is invalid, the init fails, returns NULL, and releases the - # Objective-C object. Since we've created an ObjC instance, when the object - # passes out of scope, Rubicon tries to free it, which segfaults. - # To avoid this, we retain result of the alloc() (overriding the default - # Rubicon behavior of alloc), then release that reference once we're done. - # If the image was created successfully, we temporarily have a reference - # count that is 1 higher than it needs to be; if it fails, we don't end up - # with a stray release. - image = NSImage.alloc().retain() - if path: - self.native = image.initWithContentsOfFile(str(path)) - if self.native is None: - raise ValueError(f"Unable to load image from {path}") - else: - self._needs_release = True - elif data: - nsdata = NSData.dataWithBytes(data, length=len(data)) - self.native = image.initWithData(nsdata) - if self.native is None: - raise ValueError("Unable to load image from data") - else: - self._needs_release = True - else: - self.native = raw - finally: - # Calling `release` here disabled Rubicon's "release on delete" automation. - # We therefore add an explicit `release` call in __del__ if the NSImage was - # initialized successfully. - image.release() + # We *should* be able to do a direct NSImage.alloc.init...(), but if the + # image file is invalid, the init fails, returns NULL, and releases the + # Objective-C object. Since we've created an ObjC instance, when the object + # passes out of scope, Rubicon tries to free it, which segfaults. + # To avoid this, we retain result of the alloc() (overriding the default + # Rubicon behavior of alloc), then release that reference once we're done. + # If the image was created successfully, we temporarily have a reference + # count that is 1 higher than it needs to be; if it fails, we don't end up + # with a stray release. + image = NSImage.alloc().retain() + if path: + self.native = image.initWithContentsOfFile(str(path)) + if self.native is None: + raise ValueError(f"Unable to load image from {path}") + elif data: + nsdata = NSData.dataWithBytes(data, length=len(data)) + self.native = image.initWithData(nsdata) + if self.native is None: + raise ValueError("Unable to load image from data") + else: + self.native = raw - def __del__(self): - if self._needs_release: - self.native.release() + image.release() def get_width(self): return self.native.size.width From 0cc032db7a0d63ffcc29aafd0b6c066082d69480 Mon Sep 17 00:00:00 2001 From: samschott Date: Sun, 24 Nov 2024 22:55:59 +0100 Subject: [PATCH 05/12] add changenote --- changes/2978.misc.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changes/2978.misc.rst diff --git a/changes/2978.misc.rst b/changes/2978.misc.rst new file mode 100644 index 0000000000..6646b7227d --- /dev/null +++ b/changes/2978.misc.rst @@ -0,0 +1 @@ +Update to rubicon-objc v0.5.0. From 147a1a266f04b7a616cba00567b13da0119946c4 Mon Sep 17 00:00:00 2001 From: samschott Date: Sun, 24 Nov 2024 23:15:49 +0100 Subject: [PATCH 06/12] add comment to `copyWithZone_` about the retain call --- cocoa/src/toga_cocoa/widgets/internal/data.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cocoa/src/toga_cocoa/widgets/internal/data.py b/cocoa/src/toga_cocoa/widgets/internal/data.py index b474d0e3a9..bbb05a64a2 100644 --- a/cocoa/src/toga_cocoa/widgets/internal/data.py +++ b/cocoa/src/toga_cocoa/widgets/internal/data.py @@ -5,6 +5,9 @@ class TogaData(NSObject): @objc_method def copyWithZone_(self): # TogaData is used as an immutable reference to a row - # so the same object can be returned as a copy. + # so the same object can be returned as a copy. We need + # to manually `retain` the object before returning because + # the "copy" methods are assumed to return an object that + # is owned by the caller. self.retain() return self From aeff3030ae0aedf840a59ecaf902f58c963c2fd8 Mon Sep 17 00:00:00 2001 From: samschott Date: Thu, 28 Nov 2024 23:46:44 +0100 Subject: [PATCH 07/12] remove special handling for NSImage alloc init chains --- cocoa/src/toga_cocoa/icons.py | 13 +------------ cocoa/src/toga_cocoa/images.py | 16 ++-------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/cocoa/src/toga_cocoa/icons.py b/cocoa/src/toga_cocoa/icons.py index 039c2745d0..59dc2bb5aa 100644 --- a/cocoa/src/toga_cocoa/icons.py +++ b/cocoa/src/toga_cocoa/icons.py @@ -38,20 +38,9 @@ def __init__(self, interface, path): else: self.path = path - # We *should* be able to do a direct NSImage.alloc.init...(), but if the - # image file is invalid, the init fails, returns NULL, and releases the - # Objective-C object. Since we've created an ObjC instance, when the - # object passes out of scope, Rubicon tries to free it, which segfaults. - # To avoid this, we retain result of the alloc() (overriding the default - # Rubicon behavior of alloc), then release that reference once we're - # done. If the image was created successfully, we temporarily have a - # reference count that is 1 higher than it needs to be; if it fails, we - # don't end up with a stray release. - image = NSImage.alloc().retain() - self.native = image.initWithContentsOfFile(str(path)) + self.native = NSImage.alloc().initWithContentsOfFile(str(path)) if self.native is None: raise ValueError(f"Unable to load icon from {path}") - image.release() def _as_size(self, size): image = self.native.copy() diff --git a/cocoa/src/toga_cocoa/images.py b/cocoa/src/toga_cocoa/images.py index 6e6105b360..f3dd0565bf 100644 --- a/cocoa/src/toga_cocoa/images.py +++ b/cocoa/src/toga_cocoa/images.py @@ -24,30 +24,18 @@ class Image: def __init__(self, interface, path=None, data=None, raw=None): self.interface = interface - # We *should* be able to do a direct NSImage.alloc.init...(), but if the - # image file is invalid, the init fails, returns NULL, and releases the - # Objective-C object. Since we've created an ObjC instance, when the object - # passes out of scope, Rubicon tries to free it, which segfaults. - # To avoid this, we retain result of the alloc() (overriding the default - # Rubicon behavior of alloc), then release that reference once we're done. - # If the image was created successfully, we temporarily have a reference - # count that is 1 higher than it needs to be; if it fails, we don't end up - # with a stray release. - image = NSImage.alloc().retain() if path: - self.native = image.initWithContentsOfFile(str(path)) + self.native = NSImage.alloc().initWithContentsOfFile(str(path)) if self.native is None: raise ValueError(f"Unable to load image from {path}") elif data: nsdata = NSData.dataWithBytes(data, length=len(data)) - self.native = image.initWithData(nsdata) + self.native = NSImage.alloc().initWithData(nsdata) if self.native is None: raise ValueError("Unable to load image from data") else: self.native = raw - image.release() - def get_width(self): return self.native.size.width From 18ffc54ccb87f1fea740f8d96cbaad02daa9fa33 Mon Sep 17 00:00:00 2001 From: samschott Date: Fri, 29 Nov 2024 18:59:28 +0100 Subject: [PATCH 08/12] use rubicon-objc from development branch --- cocoa/pyproject.toml | 2 +- iOS/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cocoa/pyproject.toml b/cocoa/pyproject.toml index 1f12c8c313..46c3c63ddc 100644 --- a/cocoa/pyproject.toml +++ b/cocoa/pyproject.toml @@ -62,7 +62,7 @@ root = ".." [tool.setuptools_dynamic_dependencies] dependencies = [ "fonttools >= 4.42.1, < 5.0.0", - "rubicon-objc >= 0.4.9, < 0.5.0", + "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@updated-memory-management", "toga-core == {version}", ] diff --git a/iOS/pyproject.toml b/iOS/pyproject.toml index 78c9a3e176..fe6a7fa097 100644 --- a/iOS/pyproject.toml +++ b/iOS/pyproject.toml @@ -61,7 +61,7 @@ root = ".." [tool.setuptools_dynamic_dependencies] dependencies = [ "fonttools >= 4.42.1, < 5.0.0", - "rubicon-objc >= 0.4.9, < 0.5.0", + "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@updated-memory-management", "toga-core == {version}", ] From e4a29f148d2142bd521fa5b9afcd3c8888b2a989 Mon Sep 17 00:00:00 2001 From: samschott Date: Fri, 29 Nov 2024 19:48:58 +0100 Subject: [PATCH 09/12] switch from partial to direct method call for TogaSlider --- iOS/src/toga_iOS/widgets/slider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/src/toga_iOS/widgets/slider.py b/iOS/src/toga_iOS/widgets/slider.py index 6db9758378..5a063b3b66 100644 --- a/iOS/src/toga_iOS/widgets/slider.py +++ b/iOS/src/toga_iOS/widgets/slider.py @@ -81,7 +81,7 @@ def get_value(self): def set_value(self, value): self.value = value - self.native.setValue(value, animated=True) + self.native.setValue_animated_(value, True) def get_min(self): # Use the shadow copy, not the native value, to ensure round tripping. From 0ca7125102c114cdb46ac81038aedb4700a1f87f Mon Sep 17 00:00:00 2001 From: samschott Date: Fri, 29 Nov 2024 22:59:37 +0100 Subject: [PATCH 10/12] Revert "switch from partial to direct method call for TogaSlider" This reverts commit e4a29f148d2142bd521fa5b9afcd3c8888b2a989. --- iOS/src/toga_iOS/widgets/slider.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOS/src/toga_iOS/widgets/slider.py b/iOS/src/toga_iOS/widgets/slider.py index 5a063b3b66..6db9758378 100644 --- a/iOS/src/toga_iOS/widgets/slider.py +++ b/iOS/src/toga_iOS/widgets/slider.py @@ -81,7 +81,7 @@ def get_value(self): def set_value(self, value): self.value = value - self.native.setValue_animated_(value, True) + self.native.setValue(value, animated=True) def get_min(self): # Use the shadow copy, not the native value, to ensure round tripping. From f04d08d3793e2e464833191cd8532804a512af0a Mon Sep 17 00:00:00 2001 From: samschott Date: Fri, 6 Dec 2024 12:35:38 +0100 Subject: [PATCH 11/12] point to method-loading branch --- cocoa/pyproject.toml | 2 +- iOS/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cocoa/pyproject.toml b/cocoa/pyproject.toml index 46c3c63ddc..1743ca6f9f 100644 --- a/cocoa/pyproject.toml +++ b/cocoa/pyproject.toml @@ -62,7 +62,7 @@ root = ".." [tool.setuptools_dynamic_dependencies] dependencies = [ "fonttools >= 4.42.1, < 5.0.0", - "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@updated-memory-management", + "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@method-loading", "toga-core == {version}", ] diff --git a/iOS/pyproject.toml b/iOS/pyproject.toml index fe6a7fa097..18f29af2f1 100644 --- a/iOS/pyproject.toml +++ b/iOS/pyproject.toml @@ -61,7 +61,7 @@ root = ".." [tool.setuptools_dynamic_dependencies] dependencies = [ "fonttools >= 4.42.1, < 5.0.0", - "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@updated-memory-management", + "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@method-loading", "toga-core == {version}", ] From 07d373402c337501d1f3eb6aa0a7d6ea02b701a8 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Tue, 7 Jan 2025 08:30:13 +0800 Subject: [PATCH 12/12] Use Rubicon 0.5.0. --- cocoa/pyproject.toml | 2 +- iOS/pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cocoa/pyproject.toml b/cocoa/pyproject.toml index 1743ca6f9f..45802f27af 100644 --- a/cocoa/pyproject.toml +++ b/cocoa/pyproject.toml @@ -62,7 +62,7 @@ root = ".." [tool.setuptools_dynamic_dependencies] dependencies = [ "fonttools >= 4.42.1, < 5.0.0", - "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@method-loading", + "rubicon-objc >= 0.5.0, < 0.6.0", "toga-core == {version}", ] diff --git a/iOS/pyproject.toml b/iOS/pyproject.toml index 18f29af2f1..04c4be6657 100644 --- a/iOS/pyproject.toml +++ b/iOS/pyproject.toml @@ -61,7 +61,7 @@ root = ".." [tool.setuptools_dynamic_dependencies] dependencies = [ "fonttools >= 4.42.1, < 5.0.0", - "rubicon-objc @ git+https://github.com/samschott/rubicon-objc@method-loading", + "rubicon-objc >= 0.5.0, < 0.6.0", "toga-core == {version}", ]