0

I have identical methods in different view controller classes which basically it adds a blur effect to the view controllers. Now I'm trying to use other swift types to simplify my code but am confused how to implement this so that adding subviews work properly. What's a good methodology to approach such cases ? Extension , protocol, struct, class or other func?

Here's a view controller (simplified here) :

import UIKit
class MyClass: UIViewController { 
     weak var blurEffectView : UIVisualEffectView?

     .... other methods .... 
       func addBlurrEffect() {

        let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
        let blurEffectVw = UIVisualEffectView(effect: blurEffect)
        blurEffectVw.frame = self.view.bounds
        blurEffectVw.autoresizingMask = [.flexibleWidth, .flexibleHeight]     // for supporting device rotation
        self.view.addSubview(blurEffectVw)
        blurEffectView = blurEffectVw
    }
    ... other methods .... 
} 

I have other similar view controller. How can I refactor them to only use addBlurEffect() once in the entire project?

TheBen
  • 3,410
  • 3
  • 26
  • 51

6 Answers6

2

Create NSObject class in your project for the blur function and add your method at there.

To call method , first create object of that model class in your VC and use like this obj.addBlur().

Note: if you need any variable from vc then send that variable as a param of addBlur function.

Example : addBlur(self.Viewblur)

dahiya_boy
  • 9,298
  • 1
  • 30
  • 51
1

You can use subclassing.

create a class that is a subclass of UIViewController like so:

class CustomViewController: UIViewController {

    weak var blurEffectView : UIVisualEffectView?

    func addBlurrEffect() {
        //layout for the pool of clnts that can be selected to add files
        let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
        let blurEffectVw = UIVisualEffectView(effect: blurEffect)
        blurEffectVw.frame = self.view.bounds
        blurEffectVw.autoresizingMask = [.flexibleWidth, .flexibleHeight]     // for supporting device rotation
        self.view.addSubview(blurEffectVw)
        blurEffectView = blurEffectVw

    }
}

Then you can use this class for all your View Controllers and access the addBlurrEffect function like this:

class ViewControllerOne: CustomViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        addBlurrEffect()

    }
}

class ViewControllerTwo: CustomViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        addBlurrEffect()

    }
} 
Kenny Gunderman
  • 490
  • 6
  • 18
  • 1
    Requiring a subclass just to gain this one method is really limiting. A protocol or extension would be much more appropriate. – Alexander Feb 08 '17 at 18:01
  • 1
    @Alexander, what do you mean by limiting? What is the limit if you don't mind expanding a bit , thanks a lot – TheBen Feb 08 '17 at 18:02
  • @TheeBen What if I want to subclass SomeOtherViewController, but still use a blur effect? – Alexander Feb 08 '17 at 18:03
  • have `SomeOtherViewController` be a sublcass of `CustomViewController` – Kenny Gunderman Feb 08 '17 at 18:04
  • @KennyGunderman And if `SomeOtherViewController ` is a library class that I can't control? – Alexander Feb 08 '17 at 18:04
  • @Alexander, I'm not sure. But I don't think that is what he is asking. This method is limited, but simple and works for the question posted. – Kenny Gunderman Feb 08 '17 at 18:07
  • 1
    @KennyGunderman, you're right that would answer the question, but I think it's my bad, I am looking sort of , for a more general answer to a general question , I am trying to edit the question to be more general – TheBen Feb 08 '17 at 18:09
  • @KennyGunderman See my answer: an equally short and simple answer, that's compassable and more flexible. – Alexander Feb 08 '17 at 18:09
1

Declare this behaviour in a protocol:

protocol Blurrable {
      var view: UIView { get set }
      var blurEffectView: UIVisualEffectView? { get set }

      func addBlurrEffect()
}

Define the behaviour in an extension to that protocol:

extension Blurrable {
      func addBlurrEffect()
        //layout for the pool of clnts that can be selected to add files
        let blurEffect = UIBlurEffect(style: .dark)
        blurEffectView = UIVisualEffectView(effect: blurEffect)
        blurEffectView.frame = self.view.bounds
        blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]     // for supporting device rotation
        self.view.addSubview(blurEffectView)
    }
}

And add conformance to this protocol to all relevant ViewControllers:

class MyVC1: UIViewController, Blurrable {
    weak var blurEffectView : UIVisualEffectView?

    // ...
}

class MyVC2: UIViewController, Blurrable {
    weak var blurEffectView : UIVisualEffectView?

    // ...
}
Alexander
  • 59,041
  • 12
  • 98
  • 151
  • Thanks for reply, I am just not sure how you use this in one of the original classes then? – TheBen Feb 08 '17 at 18:11
  • @TheeBen What do you mean? You just call `addBlurrEffect` normally – Alexander Feb 08 '17 at 18:12
  • 2
    You can't add stored properties to a class using an extension. Your `weak var blurEffectView` won't work as written. That would have to be written as a computed property. – Duncan C Feb 08 '17 at 18:12
  • @DuncanC Oh you're right. I thought for a moment that you could, if the classes you're extending are your own. I'll fix this now. – Alexander Feb 08 '17 at 18:13
  • @TheeBen It's fine, just declare the conformance in the class declaration, rather than an extension. I've updated my answer. – Alexander Feb 08 '17 at 18:15
  • @Alexander Now here's a philosophic question, extension or conformance to a protocol? – TheBen Feb 08 '17 at 18:17
  • @TheeBen In this case, I think a protocol is more appropriate. For one, an extension can't contain a stored property, such as `blurEffectView`. But supposing you didn't even want to store that view in a property, I would still opt for a protocol. I think it's nicer to have a protocol that defines "opt-in" behaviour, rather than using an extension to make it universal to all view controller subclasses – Alexander Feb 08 '17 at 18:19
  • @Alexander, you sound right :P plus I think a protocol is more suitable to such a case based on what I can remember from Apple Doc and Ray Wenderlich's – TheBen Feb 08 '17 at 18:21
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/135201/discussion-between-alexander-and-theeben). – Alexander Feb 08 '17 at 18:21
  • @Alexander I don't think you can have methods implemented in a protocol, protocols can only have a method signature not with body, so this results in a compiler error; the body must be implemented in form of a class or struct – TheBen Feb 08 '17 at 18:43
  • @Alexander, sorry but I think your answer won't work. You can't use addSubview on self in the extension that value doesn't have view – TheBen Feb 08 '17 at 18:53
  • @TheeBen Then add `view` to the protocol's requirements. I've updated my answer – Alexander Feb 08 '17 at 18:57
1

You should create add an extension to UIViewController:

extension UIViewController {
    func addBlurrEffect() {
        //layout for the pool of clnts that can be selected to add files
        let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
        let blurEffectVw = UIVisualEffectView(effect: blurEffect)
        blurEffectVw.frame = self.view.bounds
        blurEffectVw.autoresizingMask = [.flexibleWidth, .flexibleHeight]     // for supporting device rotation
        self.view.addSubview(blurEffectVw)
        blurEffectView = blurEffectVw

    }
}

Note that you can't add instance variables in extensions however. You should probably refactor your function to return the resulting blur effect view rather than relying on an instance variable.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
0

Something like this will work. You could use an @IBInspectable too.

import UIKit

extension UIView {
  weak var blurEffectView : UIVisualEffectView?

  .... other methods .... 
         func addBlurrEffect() {
          //layout for the pool of clnts that can be selected to add files
          let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
          let blurEffectVw = UIVisualEffectView(effect: blurEffect)
          blurEffectVw.frame = self.view.bounds
          blurEffectVw.autoresizingMask = [.flexibleWidth, .flexibleHeight]     // for supporting device rotation
          self.view.addSubview(blurEffectVw)
          blurEffectView = blurEffectVw
      }
      ... other methods .... 
  } 
}
mrabins
  • 197
  • 1
  • 2
  • 10
0

You could make a second class like this

class BlurManager {
     weak var blurEffectView: UIVisualEffectView?
     weak var viewController: UIViewController
     var isBlurred:Bool = false

     init(viewController:UIViewController){
        self.viewController = viewController
     }

     func addBlurEffect() {
        if !isBlurred {
            isBlurred = true
            let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.dark)
            let blurEffectVw = UIVisualEffectView(effect: blurEffect)
            blurEffectVw.frame = self.view.bounds
            blurEffectVw.autoresizingMask = [.flexibleWidth, .flexibleHeight]     // for supporting device rotation
            viewController.view.addSubview(blurEffectVw)
            blurEffectView = blurEffectVw
        }
    }     

    func removeBlurEffect() {
       if isBlurred {
           isBlurred = false
           ...cleanup...
       }
    }
}

class MyClass: UIViewController { 
     lazy var blurManager: BlurManager = {
         return BlurManager(viewController:self)
     }()

     .... other methods .... 
    blueManager.addBlurEffect()
     ... other methods .... 
} 
dmorrow
  • 5,152
  • 5
  • 20
  • 31