1

I'm using Swift, and I find myself having to subclass UIKit classes such as UIView and UIButton. I don't care about setting the frame since I'm using AutoLayout, so I don't want/need to use init(frame: CGRect).

class customSubclass: UIView {
    var logo: UIImage
    init(logo: UIImage) {
       self.logo = logo

       //compiler yells at me since super.init() isn't called before return from initializer

       //so I end up doing this
       super.init(frame: CGRectZero)
       self.translatesAutoresizingMaskIntoConstraints = false
    }

I also don't find it very sexy to set it's frame to CGRectZero.

Is there a way to having a custom initializer for a subclass of a UIView or UIButton without explicitly setting it's frame?

Note Every subclass is instantiated in code, so required init(coder: aDecoder) is in my code, but isn't actually doing anything.

Thanks!

Laurent Rivard
  • 509
  • 4
  • 13
  • 1
    IMO it's better practice to not have the view itself set up in a way that it knows that you are going to be sizing it with autolayout. It should initialize it's frame to a sensible value based on the content you pass it in the initializer. Maybe origin 0,0 and size equal to logo.size in the case of your example. – dan Mar 03 '16 at 18:57
  • @dan so what would I gain by passing in a valid frame if I'll disregard it anyways? The other thing I can do is create an `init` function that takes in the `frame` as well as other parameters that I need like `init( frame: CGRect, logo: UIImage)` but then I have to define the frame in the view controller – Laurent Rivard Mar 03 '16 at 23:17
  • Your view shouldn't know that you are going to disregard the frame. It should set itself up so that it will have a sensible frame even if whatever creates it doesn't give it a new one. – dan Mar 03 '16 at 23:24
  • `init(frame frame: CGRect)` is the designated initializer for UIView. The rules for initialization say you must call it. This is what the compiler is enforcing. Don't blame the compiler, at best, blame UIView. And when you've decided that won't change anything, leave your code as is. Although I would init with a size in case I break the autolayout constraints and can't see it. – Michael Mar 04 '16 at 01:34

3 Answers3

1

During initialization of a subclass, you must call the designated initializer of a superclass. In your case, since you are creating these views programmatically, you must use super.init(frame: CGRect). As you mentioned, it would be useful to implement two designated initializers for your subclass, one of which takes in a frame:CGRect argument.

Please see the accepted answer to this question for a more thorough review.

Community
  • 1
  • 1
dbn
  • 458
  • 5
  • 12
0

If you're using autolayout in a storyboard or xib, then just override the init(coder:) method so that it calls the superclass's version, and have your convenience initializers pass CGRectZero or some other value in.

NRitH
  • 13,441
  • 4
  • 41
  • 44
  • I said in my question that I'm instantiating everything in code, so `init(coder:)` is useless. It just has to be there for me to maintain a good relationship with the compiler – Laurent Rivard Mar 03 '16 at 23:19
0

Instead of creating a new class and subclassing, you could try using extensions.

extension UIView {
    var logo: UIImage = myImage
    func myLogo() {
        // code here
    }
}
mccoyLBI
  • 171
  • 14