Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Extensions must not contain stored properties" preventing me from refactoring code

I have a 13 lines func that is repeated in my app in every ViewController, which sums to a total of 690 lines of code across the entire project!

/// Adds Menu Button
func addMenuButton() {
    let menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
    let menuImage = UIImage(named: "MenuWhite")
    menuButton.setImage(menuImage, for: .normal)

    menuButton.addTarget(self, action: #selector(menuTappedAction), for: .touchDown)
    self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: menuButton)
}
/// Launches the MenuViewController
@objc func menuTappedAction() {
    coordinator?.openMenu()
}

for menuTappedAction function to work, I have to declare a weak var like this:

extension UIViewController {

weak var coordinator: MainCoordinator?

But by doing this I get error Extensions must not contain stored properties What I tried so far:

1) Removing the weak keyword will cause conflicts in all my app. 2) Declaring this way:

weak var coordinator: MainCoordinator?
extension UIViewController {

Will silence the error but the coordinator will not perform any action. Any suggestion how to solve this problem?

like image 898
Jessica Kimble Avatar asked Sep 15 '19 13:09

Jessica Kimble


People also ask

Why can't I add stored properties in extension?

Extensions cannot contain stored properties. If you need to add a property to a native component, you must create your own button inheriting from UIButton. In my opinion, creating your own button using a UIButton inheritance is the best way to resolve this situation.

Can we have stored property in extension?

Extensions can add new computed properties, but they can't add stored properties, or add property observers to existing properties.

Can we add stored property in extension Swift?

As you may know Swift does not allow stored properties into extensions. That's by design: “Extensions may not contain stored properties.”

Can we override function in extension in Swift?

It is not possible to override functionality (like properties or methods) in extensions as documented in Apple's Swift Guide. Extensions can add new functionality to a type, but they cannot override existing functionality.


2 Answers

You can move your addMenuButton() function to a protocol with a protocol extension. For example:

@objc protocol Coordinated: class {
    var coordinator: MainCoordinator? { get set }
    @objc func menuTappedAction()
}

extension Coordinated where Self: UIViewController {
    func addMenuButton() {
        let menuButton = UIButton(frame: CGRect(x: 0, y: 0, width: 30, height: 30))
        let menuImage = UIImage(named: "MenuWhite")
        menuButton.setImage(menuImage, for: .normal)

        menuButton.addTarget(self, action: #selector(menuTappedAction), for: .touchDown)
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(customView: menuButton)
    }
}

Unfortunately, you can't add @objc methods to class extensions (see: this stackoverflow question), so you'll still have to setup your view controllers like this:

class SomeViewController: UIViewController, Coordinated {
    weak var coordinator: MainCoordinator?
    /// Launches the MenuViewController
    @objc func menuTappedAction() {
        coordinator?.openMenu()
    }
}

It'll save you some code, and it will allow you to refactor the bigger function addMenuButton(). Hope this helps!

like image 199
Zoe Avatar answered Nov 25 '22 12:11

Zoe


For it to work in an extension you have to make it computed property like so : -

extension ViewController {

   // Make it computed property
    weak var coordinator: MainCoordinator? {
        return MainCoordinator()
    }

}

like image 35
Mussa Charles Avatar answered Nov 25 '22 11:11

Mussa Charles