Два класса для использования одной и той же функции для создания пользовательского представления - Swift - PullRequest
0 голосов
/ 25 января 2020

Я новичок в Swift и не могу понять это. У меня есть два класса, где мне нужно использовать одну и ту же функцию для настройки пользовательского UIStackVIew (Rating Control, который показывает рейтинг звезд). Каждый класс имеет переменную с именем value, которую необходимо передать внутри функции. Я не хочу дублировать один и тот же код функции setUpStackView внутри каждого класса. У меня есть следующий код:

class Class1: UIStackView {

    var variable1 = "value1"

    override init(frame: CGRect){
      super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder){
      super.init(coder: aDecoder)
    }

    setUpStackView(value: variable1)

}

class Class2: UIStackView {

    var variable2 = "value2"

    override init(frame: CGRect){
      super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder){
      super.init(coder: aDecoder)
    }

    setUpStackView(value: variable2)

}




extension Class1 {

  func setUpStackView(value: String){
    //code to set UIStackView rating control and to use the variable value
  }

}

Как я могу реализовать расширение для Class2? Я застрял с этим. Любая помощь будет принята с благодарностью!

Ответы [ 2 ]

2 голосов
/ 25 января 2020

Одно решение может быть перемещено общим кодом в протокол, где вы можете абстрагироваться:

protocol  BaseStackView {
    var variable :String { get set }
}

class Class1: UIStackView,BaseStackView {



    var variable = "value1"

    override init(frame: CGRect){
      super.init(frame: frame)
        self.setUpStackView(value: variable)

    }

    required init(coder: NSCoder) {
        super.init(coder: coder)
        self.setUpStackView(value: variable)
    }
}

class Class2: UIStackView,BaseStackView {

    var variable = "value2"

    override init(frame: CGRect){
      super.init(frame: frame)
        self.setUpStackView(value: variable)
    }

    required init(coder: NSCoder) {
        super.init(coder: coder)
        self.setUpStackView(value: variable)
    }



}



extension UIStackView {
    func setUpStackView(value: String) {
        //Your setup here
    }
}
1 голос
/ 25 января 2020

У вас есть много вариантов.

Вы можете сделать Class2 наследуемым от Class1:

class Class2: Class1 {
    var value = "value2" //You have access to Class1's value, so you can change it here
    setUpStackView(value: value) //But there's a problem here
}

Но вы не можете просто вызвать функцию, когда находитесь в середине класса декларация. Но вы можете сделать это в инициализаторе:

class Class2: Class1 {

    override init(frame: CGRect) {
        super.init(frame: frame)
        value = "value2" 
        setUpStackView(value: value) 
    }

    required init(coder aDecoder: NSCoder){
        super.init(coder: aDecoder)
        value = "value2"
        setUpStackView(value: value) 
    }
}

Вышеприведенный пример является лишним, потому что вы ссылаетесь на свойства класса в его собственном инициализаторе. Вот еще одно решение:

Вы можете сделать свою функцию настройки расширением функции UIStackView:

extension UIStackView {
    func setUpStackView(value: String) { 
        //Your setup here
        self.someProperty = value //self is referring to the stackview itself
    }
}

Другой вариант - создать функцию stati c.

extension Class1 {
    static func setUpStackView(stackVw: UIStackView, value: String) {
        stackVw.someProperty = value 
        //Doing it like this still makes this function "belong" to Class1
        //It also makes it so anyone can set up their stack view like
        //this because they have to pass their stack view in here
    }
}

Использование будет таким, независимо от того, в каком классе вы находитесь и какая у вас иерархия наследования:

override init(frame: CGRect) {
    super.init(frame: frame)
    Class1.setUpStackVw(stackVw: self, value: self.variable)
}

required init(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    Class1.setUpStackVw(stackVw: self, value: self.variable)
}

Еще один вариант - создать протокол, которому соответствуют Class1 и Class2.

protocol StackVwWithSpecialSetUp where Self: UIStackView {
    var value: String {get}
}
extension StackVwWithSpecialSetUp {
    func setUpStackView() 
    {
        self.someProperty = self.value
    }
}

И тогда ваш класс будет соответствовать этому

class Class1Or2: UIStackView, StackVwWithSpecialSetUp {
    var value: String = "blah" //Compiler will force you to implement this
    override init(frame: CGRect) {
        super.init(frame: frame)

        //Now you can use this
        setUpStackVw()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)

        //You can use this here too
        setUpStackVw()
    }
}

Возможно, я бы просто сделал так, чтобы полностью исключить необходимость в свойстве value:

class Class1: UIStackView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUpStackVw()
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setUpStackVw()
    }

    func setUpStackVw()
    {
        self.accessibilityHint = "value1"
    }
}

//////////

class Class2: Class1 {
    override func setUpStackVw()
    {
        self.someProperty = "value2"
    }
}
...