How to make weak reference when setting function to closure variable

44 Views Asked by At

How to weak self when setting function to closure as in 1. to work same as example 2. Any ideas?

class TabController: UITabBarController {
 func setupViewActions() {
  tabView.itemTapped = changeTab // 1. tabController cannot be deallocated

  tabView.itemTapped = { [weak self] tab in // 2. TabController can be deallocated
  changeTab(tab: tab)
  }
 }

 func changeTab(tab: TabItem) {
  self.selectedIndex = tab.index
 }
}
enum TabItem {
 var index: int
}

class TabView: UIView {
 var itemTapped: ((_ tab: TabItem) -> Void)?
}
1

There are 1 best solutions below

0
shivatinker On

I really don't see any problem with

tabView.itemTapped = { [weak self] tab in
    changeTab(tab: tab)
}

In my opinion, this is pretty common pattern in Swift and, especially, Cocoa.

However, if you really want to get rid of this curly braces, you can use this wrapper function using parameter packs:

func weakifySelf<T: AnyObject, each R>(
    _ self: T,
    _ target: @escaping (T) -> (repeat each R) -> Void
) -> ((repeat each R) -> Void) {
    { [weak self](input: repeat each R) in
        guard let self else { return }
        
        target(self)(repeat each input)
    }
}

Example usage:


class Top {
    let bottom = Bottom()
    
    func setup() {
        self.bottom.handler = weakifySelf(self, Top.doJob)
    }
    
    func doJob(int: Int, string: String) {
        print("\(int) \(string)")
    }
    
    deinit {
        print("Top deallocated")
    }
}

class Bottom {
    var handler: ((Int, String) -> Void)?
    
    func foo() {
        self.handler?(42, "Hello")
    }
    
    deinit {
        print("Bottom deallocated")
    }
}

func test() {
    let top = Top()
    top.setup()
    top.bottom.foo()
}

test()

Code above prints

42 Hello
Top deallocated
Bottom deallocated