42

I have an extension:

extension UILabel {
    func animateHidden(flag: Bool) {
        self.hidden = flag
    }
}

I need to make the same one for UIImageView but I don't want to copy that whole code. Is it possible to make an extension for multiple classes?

Thanks.

2
  • 4
    Can you just use extension UIView? It will depend on the implementation of animateHidden Commented Jul 19, 2016 at 16:43
  • @Kevin all code of animateHidden will be useful for both classes UILabel, UIImageView Commented Jul 19, 2016 at 16:45

2 Answers 2

88

You could make a protocol and extend it.

Something like:

protocol Animations {
    func animateHidden(flag: Bool)
}

extension Animations {
    func animateHidden(flag: Bool) {
        // some code
    }
}

extension UILabel: Animations {}

extension UIImageView: Animations {}

Your method will be available for the extended classes:

let l = UILabel()
l.animateHidden(false)

let i = UIImageView()
i.animateHidden(false)

In a comment, you've asked: "in this case how to call self for UILabel and UIImageView in animateHidden function?". You do that by constraining the extension.

Example with a where clause:

extension Animations where Self: UIView {
    func animateHidden(flag: Bool) {
        self.hidden = flag
    }
}

Thanks to @Knight0fDragon for his excellent comment about the where clause.

Sign up to request clarification or add additional context in comments.

5 Comments

In this case how to call self for UILabel and UIImageView in animateHidden function?
@Danny, add a where clause. extension Animations where Self: UIView
But then won't you have to do extension Animations where Self: UIImageView and reproduce the same implementation for animateHidden(flag:) anyway? That sort of destroys the purpose of reusing the implementation code.
@HuaTham No you don't have to do this, because UIImageView is extended with the Animations extension, so by composition it includes animateHidden, that's the whole point indeed. :)
the example with the where clause is nice. I was going to do it with a conditional cast, but pushing this back to compile-time is nicer/better. @Knight0fDragon big ups!
10

Best Method to Extend UILabel & UIImageView Together

Swift 4.1 / Xcode 9.4

A much better way to do this in your case would be to just extend UIView. This works because both UILabel and UIImageView both inherit from UIView.


Extension

extension UIView {
    func animateHidden(flag: Bool) {
        self.hidden = flag
    }
}

Usage of animateHidden(flag: Bool) Extension

Declaration of label and imageView:

label = UILabel()
imageView = UIImageView()

Actual usage of extension

label.animateHidden(flag: true)
imageView.animateHidden(flag: false)

Bonus - Other Classes that many UI Components Conform to

If you would like to have your extension be able to conform with many different types of UI components, there are 4 types that a very large amount of UI components conform to:

  1. CVarArg
  2. Equatable
  3. Hashable
  4. NSCoding

Some of the many UI components include:

  • UILabel: CVarArg, Equatable, Hashable, NSCoding

  • UITextField: CVarArg, Equatable, Hashable, NSCoding

  • UITableViewCell: CVarArg, Equatable, Hashable, NSCoding

  • UITextView: CVarArg, Equatable, Hashable, NSCoding

  • UITableView: CVarArg, Equatable, Hashable, NSCoding

  • UIImage: CVarArg, Equatable, Hashable, NSCoding

  • UIPickerView: CVarArg, Equatable, Hashable, NSCoding

  • UIView: CVarArg, Equatable, Hashable, NSCoding

  • UIImageView: CVarArg, Equatable, Hashable, NSCoding

  • UINavigationBar: CVarArg, Equatable, Hashable, NSCoding

  • UIButton: CVarArg, Equatable, Hashable, NSCoding

  • UIBarButtonItem: CVarArg, Equatable, Hashable, NSCoding

  • UIStackView: CVarArg, Equatable, Hashable, NSCoding

  • UIToolbar: CVarArg, Equatable, Hashable, NSCoding

  • UITabBar: CVarArg, Equatable, Hashable, NSCoding

  • UITabBarItem: CVarArg, Equatable, Hashable, NSCoding

  • UIScrollView: CVarArg, Equatable, Hashable, NSCoding

  • UISplitViewController: CVarArg, Equatable, Hashable, NSCoding

  • UIViewController: CVarArg, Equatable, Hashable, NSCoding

  • UIScreen: CVarArg

  • UISwitch: CVarArg, Equatable, Hashable, NSCoding

  • UISlider: CVarArg, Equatable, Hashable, NSCoding

  • UIAlertAction: CVarArg

  • UIAlertController: CVarArg, Equatable, Hashable, NSCoding

  • UIImageAsset: CVarArg, Equatable, Hashable, NSCoding

  • UIDatePicker: CVarArg, Equatable, Hashable, NSCoding

  • UINib: CVarArg

  • UIResponder: CVarArg

  • UIWindow: CVarArg, Equatable, Hashable, NSCoding

  • UIRegion: CVarArg, Equatable, Hashable, NSCoding

  • UIControl: CVarArg, Equatable, Hashable, NSCoding

  • UIBezierPath: CVarArg, Equatable, Hashable, NSCoding

  • UIVisualEffect: CVarArg, Equatable, Hashable, NSCoding

  • UISearchBar: CVarArg, Equatable, Hashable, NSCoding

  • UIMenuItem: CVarArg

  • UIMenuController: CVarArg

  • UIStoryboard: CVarArg

  • And many more...


This means that by extending either CVarArg, Equatable, Hashable, or NSCoding, you can extend most (if every not every) UI component.



Well anyways, I hope this all helps you resolve your issue and if you have absolutely any questions, suggestions, etc., feel free to ask!



5 Comments

Although your approach works well in this particular case I would not consider this programming style being a best practise for well structured code. Reasons for this are: 1) You don't want to have all UIViews being extended by the functions that you only need in a UILabel or UIImageView 2) With the way the accepted answer is implemented you are able to functionally separate your code into a swift file that is easier to find within your codebase since your extension will have an identifiable name.
Hii, i have a quick question. i want to do like this extension UITableViewCell, UICollectionViewCell{ // Methods }. How can achieved this. Please help Thanks !!
@YogeshPatel You can try to find a common subclass of both UITableViewCell and UICollectionViewCell that has all the functionality you need in your extension and just extend that . For example, extending UIView will do so for all of its subclasses like UILabel, UITextField, etc., but the extension method will be limited to using only methods defined on UIView and any of its superclasses, thus limiting what you can actually do. Ideally you'll be able to use the first common superclass between the two types. Note that if you do this it extends all subclasses of the extended class.
@YogeshPatel, if the common superclass does not incorporate the functionality you wish to use in your extension or if you would like it to extend UITableViewCell and UICollectionViewCell in exclusion of any unnecessary subclasses of their common superclass, then you should use a protocol. In the protocol, define the methods you need to access in your joint extension. Then conform UITableViewCell and UICollectionViewCell to the protocol individually. After they are conformed to it, you can extend the protocol. This also allows you to write functions that are generic over the protocol.
Hii thanks for your response. i did this thing using Protocol. Now it's working!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.