Как сделать расширение для нескольких классов Swift

У меня есть расширение:

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

Мне нужно сделать такой же для UIImageView, но я не хочу копировать весь код. Можно ли сделать расширение для нескольких классов?

Спасибо.


person Danny    schedule 19.07.2016    source источник
comment
Можете ли вы просто использовать extension UIView? Это будет зависеть от реализации animateHidden   -  person Kevin    schedule 19.07.2016
comment
@Kevin весь код animateHidden будет полезен для обоих классов UILabel, UIImageView   -  person Danny    schedule 19.07.2016


Ответы (2)


Вы можете составить протокол и расширить его.

Что-то типа:

protocol Animations {
    func animateHidden(flag: Bool)
}

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

extension UILabel: Animations {}

extension UIImageView: Animations {}

Ваш метод будет доступен для расширенных классов:

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

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

В комментарии вы спросили: «Как в этом случае вызывать self для UILabel и UIImageView в функции animateHidden?». Вы делаете это, ограничивая расширение.

Пример с предложением where:

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

Спасибо @Knight0fDragon за отличный комментарий о пункте where.

person Eric Aya    schedule 19.07.2016
comment
В этом случае, как вызвать self для UILabel и UIImageView в функции animateHidden? - person Danny; 19.07.2016
comment
@ Дэнни, добавь предложение where. extension Animations where Self: UIView - person Knight0fDragon; 19.07.2016
comment
Но тогда вам все равно не придется делать extension Animations where Self: UIImageView и воспроизводить ту же реализацию для animateHidden(flag:)? Это разрушает цель повторного использования кода реализации. - person HuaTham; 23.11.2016
comment
@HuaTham Нет, вам не нужно этого делать, потому что UIImageView расширен расширением Animations, поэтому по составу он включает animateHidden, в этом и есть весь смысл. :) - person Eric Aya; 23.11.2016

Лучший способ расширить UILabel и UIImageView вместе

Свифт 4.1/Xcode 9.4

Гораздо лучший способ сделать это в вашем случае — просто расширить UIView. Это работает, потому что и UILabel, и UIImageView наследуются от UIView.


Расширение

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

Использование расширения animateHidden(flag: Bool)

Объявление label и imageView:

label = UILabel()
imageView = UIImageView()

Фактическое использование расширения

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

Бонус — другие классы, которым соответствуют многие компоненты пользовательского интерфейса.

Если вы хотите, чтобы ваше расширение могло соответствовать многим различным типам компонентов пользовательского интерфейса, существует 4 типа, которым соответствует очень большое количество компонентов пользовательского интерфейса:

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

Некоторые из многих компонентов пользовательского интерфейса включают в себя:

  • 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

  • УИНиб: 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

  • И многое другое...


Это означает, что, расширяя CVarArg, Equatable, Hashable или NSCoding, вы можете расширить большинство (если не каждый) компонент пользовательского интерфейса.



В любом случае, я надеюсь, что все это поможет вам решить вашу проблему, и если у вас есть абсолютно какие-либо вопросы, предложения и т. д., не стесняйтесь спрашивать!



person Noah Wilder    schedule 28.03.2018
comment
Хотя ваш подход хорошо работает в этом конкретном случае, я бы не считал этот стиль программирования лучшим методом для хорошо структурированного кода. Причины для этого: 1) Вы не хотите, чтобы все UIView были расширены функциями, которые вам нужны только в UILabel или UIImageView 2) Благодаря тому, как реализован принятый ответ, вы можете функционально разделить свой код на swift, который легче найти в вашей кодовой базе, поскольку ваше расширение будет иметь идентифицируемое имя. - person Dennis Stücken; 31.08.2019
comment
Привет, у меня есть быстрый вопрос. я хочу сделать как это расширение UITableViewCell, UICollectionViewCell{//Методы}. Как можно этого добиться. Пожалуйста, помогите Спасибо!! - person Yogesh Patel; 27.02.2020
comment
@YogeshPatel Вы можете попытаться найти общий подкласс как UITableViewCell, так и UICollectionViewCell, который имеет все функции, которые вам нужны в вашем расширении, и просто расширить его. Например, расширение UIView будет делать это для всех его подклассов, таких как UILabel, UITextField и т. д., но метод расширения будет ограничен использованием только методов, определенных в UIView и любом из его суперклассов, таким образом ограничивая то, что вы на самом деле можете сделать. В идеале вы сможете использовать первый общий суперкласс между двумя типами. Обратите внимание, что если вы сделаете это, он расширит все подклассы расширенного класса. - person Noah Wilder; 27.02.2020
comment
@YogeshPatel, если общий суперкласс не включает функции, которые вы хотите использовать в своем расширении, или если вы хотите, чтобы он расширял UITableViewCell и UICollectionViewCell, исключая любые ненужные подклассы их общего суперкласса, вам следует использовать протокол. В протоколе определите методы, к которым вам нужно получить доступ в вашем совместном расширении. Затем индивидуально согласуйте UITableViewCell и UICollectionViewCell с протоколом. После того, как они соответствуют ему, вы можете расширить протокол. Это также позволяет вам писать функции, которые являются общими для протокола. - person Noah Wilder; 27.02.2020
comment
Привет спасибо за ваш ответ. Я сделал это, используя протокол. Теперь это работает! - person Yogesh Patel; 28.02.2020