From d2c59c17189fddd902dad41467ab9190c03d227c Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Mon, 16 Sep 2024 07:56:37 +0800 Subject: [PATCH] Correct leaks on Switch and Divider on iOS. --- changes/2849.bugfix.rst | 1 + iOS/src/toga_iOS/widgets/box.py | 9 +++++++++ iOS/src/toga_iOS/widgets/divider.py | 6 ++++-- iOS/src/toga_iOS/widgets/switch.py | 7 ++++++- testbed/tests/widgets/test_divider.py | 2 +- testbed/tests/widgets/test_switch.py | 2 +- 6 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 changes/2849.bugfix.rst diff --git a/changes/2849.bugfix.rst b/changes/2849.bugfix.rst new file mode 100644 index 0000000000..430b9afbef --- /dev/null +++ b/changes/2849.bugfix.rst @@ -0,0 +1 @@ +A memory leak when using Divider or Switch widgets on iOS was resolved. diff --git a/iOS/src/toga_iOS/widgets/box.py b/iOS/src/toga_iOS/widgets/box.py index fa57d6542c..7a110c303c 100644 --- a/iOS/src/toga_iOS/widgets/box.py +++ b/iOS/src/toga_iOS/widgets/box.py @@ -1,11 +1,20 @@ +from rubicon.objc import objc_property from travertino.size import at_least from toga_iOS.libs import UIView from toga_iOS.widgets.base import Widget +class TogaView(UIView): + interface = objc_property(object, weak=True) + impl = objc_property(object, weak=True) + + class Box(Widget): def create(self): + # This should be a TogaView - but making it a TogaView causes segfaults when + # content is added and removed from containers like OptionContainer and + # ScrollContainer. self.native = UIView.alloc().init() self.native.interface = self.interface self.native.impl = self diff --git a/iOS/src/toga_iOS/widgets/divider.py b/iOS/src/toga_iOS/widgets/divider.py index 7a281aa7cc..cd785d3396 100644 --- a/iOS/src/toga_iOS/widgets/divider.py +++ b/iOS/src/toga_iOS/widgets/divider.py @@ -1,12 +1,14 @@ from travertino.size import at_least -from toga_iOS.libs import UIColor, UIView +from toga_iOS.libs import UIColor from toga_iOS.widgets.base import Widget +from .box import TogaView + class Divider(Widget): def create(self): - self.native = UIView.alloc().init() + self.native = TogaView.alloc().init() self.native.interface = self.interface self.native.impl = self diff --git a/iOS/src/toga_iOS/widgets/switch.py b/iOS/src/toga_iOS/widgets/switch.py index 9e42c7b016..89cc6cdb3b 100644 --- a/iOS/src/toga_iOS/widgets/switch.py +++ b/iOS/src/toga_iOS/widgets/switch.py @@ -13,6 +13,11 @@ from toga_iOS.widgets.base import Widget +class TogaStackView(UIStackView): + interface = objc_property(object, weak=True) + impl = objc_property(object, weak=True) + + class TogaSwitch(UISwitch): interface = objc_property(object, weak=True) impl = objc_property(object, weak=True) @@ -26,7 +31,7 @@ class Switch(Widget): SPACING = 10 def create(self): - self.native = UIStackView.alloc().init() + self.native = TogaStackView.alloc().init() self.native.interface = self.interface self.native.impl = self self.native.axis = UILayoutConstraintAxis.Horizontal diff --git a/testbed/tests/widgets/test_divider.py b/testbed/tests/widgets/test_divider.py index 848aadbe33..b02a43a4c2 100644 --- a/testbed/tests/widgets/test_divider.py +++ b/testbed/tests/widgets/test_divider.py @@ -16,7 +16,7 @@ async def widget(): return toga.Divider() -test_cleanup = build_cleanup_test(toga.Divider, xfail_platforms=("iOS",)) +test_cleanup = build_cleanup_test(toga.Divider) async def test_directions(widget, probe): diff --git a/testbed/tests/widgets/test_switch.py b/testbed/tests/widgets/test_switch.py index fe115ac7e8..023c865df8 100644 --- a/testbed/tests/widgets/test_switch.py +++ b/testbed/tests/widgets/test_switch.py @@ -29,7 +29,7 @@ async def widget(): test_cleanup = build_cleanup_test( - toga.Switch, args=("Hello",), xfail_platforms=("android", "iOS", "linux") + toga.Switch, args=("Hello",), xfail_platforms=("android", "linux") )