{"id":40255,"date":"2023-08-04T13:31:56","date_gmt":"2023-08-04T17:31:56","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=40255"},"modified":"2023-08-15T10:24:45","modified_gmt":"2023-08-15T14:24:45","slug":"avoiding-implicit-retain-cycles-when-using-swift-function-references","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2023\/08\/04\/avoiding-implicit-retain-cycles-when-using-swift-function-references\/","title":{"rendered":"Avoiding Implicit Retain Cycles When Using Swift Function References"},"content":{"rendered":"<p><a href=\"https:\/\/sveinhal.github.io\/2016\/03\/16\/retain-cycles-function-references\/\">Svein Halvor Halvorsen<\/a>:<\/p>\n<blockquote cite=\"https:\/\/sveinhal.github.io\/2016\/03\/16\/retain-cycles-function-references\/\"><p>Even though we capture <code>self<\/code> unonwed in the outer closure, the callbacks that gets registered with the socket, are captured strongly. So even when the object above is released from where ever it was created, the object is still kept alive.<\/p><p>[&#8230;]<\/p><p>The <code>[unowned self] in<\/code> and argument list is just boilerplate, repeated over, with no other purpose than to pass arguments from one function (the in-line closure) on to the next (the actual event handler functions).<\/p><p>[&#8230;]<\/p><p>What if we took <code>self.dynamicType.onChatMessageReceived<\/code> from the second event handler above, but without the argument <code>(self)<\/code>, and passed that as a <em>parameter<\/em> to our wrapper function, together with a <em>reference<\/em> to <code>self<\/code>? Maybe we could then capture that reference unowned, and pass the <em>unowned instance reference<\/em> to the <em>class function<\/em> to get an <em>instance function<\/em>, without creating a retain cycle.<\/p><\/blockquote>\n<p>As he says, this works but it is far from optimal. I wonder if there&rsquo;s a way to make it better with macros.<\/p>\n\n<p><a href=\"https:\/\/mastodon.social\/@bigzaphod\/110741565798443739\">Sean Heber<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.social\/@bigzaphod\/110741565798443739\"><p>In the first line, Swift will helpfully tell me that I&rsquo;m accidentally capturing <code>self<\/code>, but in the second line there&rsquo;s no warning whatsoever.<\/p><\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/05\/18\/weak-self-closure-rules-of-thumb\/\">Weak Self: Closure Rules of Thumb<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2018\/03\/23\/dealing-with-weak-in-closure-based-delegation\/\">Dealing With Weak in Closure-based Delegation<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2016\/07\/25\/swift-closure-capture-semantics\/\">Swift Closure Capture Semantics<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2013\/01\/22\/blocks-operations-and-retain-cycles\/\">Blocks, Operations, and Retain Cycles<\/a><\/li>\n<\/ul>\n\n<p id=\"avoiding-implicit-retain-cycles-when-using-swift-function-references-update-2023-08-09\">Update (2023-08-09): <a href=\"https:\/\/hachyderm.io\/@rustle\/110832802009221990\">Doug<\/a>:<\/p>\n<blockquote cite=\"https:\/\/hachyderm.io\/@rustle\/110832802009221990\"><p>I&rsquo;ve hit that enough to make a <a href=\"https:\/\/github.com\/rustle\/TargetAction\">helper library<\/a> and there&rsquo;s a <a href=\"https:\/\/forums.swift.org\/t\/pitch-weak-method-storage-modifiers-aka-weak-references\/12161\/17\">forum discussion<\/a> proposing a syntax for weakly capturing a method that&rsquo;s quite relevant.<\/p><\/blockquote>\n<p>However, the last post was more than 5 years ago.<\/p>\n\n<p id=\"avoiding-implicit-retain-cycles-when-using-swift-function-references-update-2023-08-15\">Update (2023-08-15): See also: <a href=\"https:\/\/forums.swift.org\/t\/revisiting-requiring-explicit-self-when-passing-a-method-as-an-escaping-closure\/12149\/18\">Revisiting requiring explicit <code>self.<\/code> when passing a method as an escaping closure<\/a> (via <a href=\"https:\/\/hachyderm.io\/@robinkunde\/110890768152318637\">Robin Kunde<\/a>).<\/p>","protected":false},"excerpt":{"rendered":"<p>Svein Halvor Halvorsen: Even though we capture self unonwed in the outer closure, the callbacks that gets registered with the socket, are captured strongly. So even when the object above is released from where ever it was created, the object is still kept alive.[&#8230;]The [unowned self] in and argument list is just boilerplate, repeated over, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2023-08-04T17:31:58Z","apple_news_api_id":"b2c39abf-19ad-451f-b5f0-209698f1f82e","apple_news_api_modified_at":"2023-08-15T14:24:48Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAQ==","apple_news_api_share_url":"https:\/\/apple.news\/AssOavxmtRR-18CCWmPH4Lg","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[55,27,46,571,71,901],"class_list":["post-40255","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-arc","tag-craft","tag-languagedesign","tag-memory-management","tag-programming","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/40255","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=40255"}],"version-history":[{"count":3,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/40255\/revisions"}],"predecessor-version":[{"id":40338,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/40255\/revisions\/40338"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=40255"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=40255"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=40255"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}