Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 变量更改时更新UILabel文本_Ios_Swift_Uilabel_Uicontrol - Fatal编程技术网

Ios 变量更改时更新UILabel文本

Ios 变量更改时更新UILabel文本,ios,swift,uilabel,uicontrol,Ios,Swift,Uilabel,Uicontrol,我有一个UIControl类,需要根据UIImageView位置进行一些计算,该位置可以通过touchesBegind和touchesMoved(该类中的所有内容)移动。 然后我想将它显示为我通过编程创建的UILabel class control : UIControl{ ... let leftControl: UIImageView = UIImageView(image: UIImage(named: "left-control")) ... func leftV

我有一个UIControl类,需要根据UIImageView位置进行一些计算,该位置可以通过touchesBegind和touchesMoved(该类中的所有内容)移动。 然后我想将它显示为我通过编程创建的UILabel

class control : UIControl{
   ...
   let leftControl: UIImageView = UIImageView(image: UIImage(named: "left-control"))
   ...
   func leftValue() -> String{
       var leftValue : String = "0.0"
       leftValue = "\(leftControl.center.x)"
       return leftValue
   }
}
还有我的ViewController.swift

类ViewController:UIViewController{

let ctrl : Control = Control()
let leftLabel : UILabel = UILabel(frame: CGRect(x: 40, y: 300, width: 150, height: 30))

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    ctrl.frame.origin = CGPoint(x: 40, y: 400)

    leftLabel.text = "\(ctrl.leftValue())" //displays only starting value

    view.addSubview(slider)
    view.addSubview(leftLabel)
    view.addSubview(rightLabel)
}

我知道它在viewDidLoad中,因此无法正确更新。我想知道scheduledTimer,但不知道它是否是一个好的解决方案。

您可以使用协议和委派来实现这一点-在
控件的文件中添加以下内容:

protocol ControlDelegate: class {
    func controlPositionDidChange(leftValue: String)
}
并在
Control
类中添加一个
弱var委托:ControlDelegate?

在视图控制器的文件中,进行以下更改:

class ViewController: UIViewController, ControllDelegate {

let ctrl : Control = Control() 
let leftLabel : UILabel = UILabel(frame: CGRect(x: 40, y: 300, width: 150, height: 30))

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    ctrl.frame.origin = CGPoint(x: 40, y: 400)
    ctrl.delegate = self

    leftLabel.text = "\(ctrl.leftValue())" //displays only starting value

    view.addSubview(slider)
    view.addSubview(leftLabel)
    view.addSubview(rightLabel) 
}

func controlPositionDidChange(leftValue: String) {
    leftLabel.text = leftValue
}
}
现在,每当您想通知委托您的控件已更改位置时,只需在适当的位置调用
self.delegate?.controlPositionDidChange(self.leftValue())


通常,我强烈建议阅读它们,因为委托和协议在CocoaTouch中被广泛使用。

Losiowaty的答案描述了大多数开发人员选择的解决方案。但是(在我看来)更好的实现方法。我更喜欢面向对象的解决方案。它可能看起来像更多的代码,但它是一种更好的可维护方法,具有更多可重用的代码

问题的真正面向对象解决方案可能如下所示:

// reusable protocol set

protocol OOString: class {
    var value: String { get set }
}

// reusable functional objects

final class RuntimeString: OOString {

    init(initialValue: String = "") {
        self.value = initialValue
    }

    var value: String

}

final class ViewUpdatingString: OOString {

    init(_ decorated: OOString, view: UIView) {
        self.decorated = decorated
        self.view = view
    }

    var value: String {
        get {
            return decorated.value
        }
        set(newValue) {
            decorated.value = newValue
            view.setNeedsLayout()
        }
    }

    private let decorated: OOString
    private let view: UIView
}

// reusable ui objects

final class MyLabel : UILabel {

    init(frame: CGRect, imageXCenter: OOString) {
        self.imageXCenter = imageXCenter
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("Not supported")
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        text = imageXCenter.value
    }

    private let imageXCenter: OOString

}

final class MyControl : UIControl {

    init(frame: CGRect, imageXCenter: OOString) {
        self.imageXCenter = imageXCenter
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("Not supported")
    }

    private let imageXCenter: OOString
    private let leftControl = UIImageView(image: UIImage(named: "left-control"))

    // call this at change
    private func updateValue() {
        imageXCenter.value = "\(leftControl.center.x)"
    }

}

// non reusable business logic

final class MyViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let dependency = RuntimeString(initialValue: "unset")
        let leftLabel = MyLabel(
            frame: CGRect(x: 40, y: 300, width: 150, height: 30),
            imageXCenter: dependency
        )
        let control = MyControl(
            frame: CGRect(x: 40, y: 400, width: 400, height: 400),
            imageXCenter: ViewUpdatingString(dependency, view: leftLabel)
        )
        view.addSubview(leftLabel)
        view.addSubview(control)
    }

}
其主要思想是将两个对象的依赖关系提取到另一个对象中,然后使用装饰器在每个设置值上自动更新ui

注:

  • 这种方法遵循面向对象编码的规则(干净的编码、优雅的对象、装饰模式等等)
  • 可重用类的构造非常简单,只需完成一项任务
  • 类通过协议相互通信
  • 依赖项尽可能由依赖项注入提供
  • 内部对象功能是私有的(松耦合)
  • 所有东西(除了业务逻辑)都是为重用而设计的->如果您这样编码,那么可重用代码的组合将随着您编码的每一天而增长
  • 您的应用程序的业务逻辑更集中在一个地方(在我的实际编码中,甚至在UIViewController之外)
  • 当为协议使用假实现时,可重用对象的单元测试非常简单(在大多数情况下甚至不需要模拟)
  • 保留循环的问题较少,在大多数情况下,不再需要弱属性
  • 避免Null、nil和Optionals(它们会污染您的代码)

关键值Observing@AleksandrMedvedevKVO更多的是一个Objective-c特性。虽然它在Swift中是可能的,但并不简单。@Losiowaty,KVO并不是一个简单的特性..曾经:)dzięki za pomoc;)Nie ma za co:)但是让我们用英语在这里;)还有一个问题-你为什么要写
协议控制委派:class{}
。这是否意味着此ControlDelegate继承自类?其目的是什么?这是因为只有
协议可以是
弱的
-您可以和往常一样