簡體   English   中英

如何使用從 Controller 中提取的項目初始化惰性 UISegmentedControl?

[英]How do I initialize a lazy UISegmentedControl with items drawn from the Controller?

我是整個 MVC 事情的初學者,所以請多多包涵。

我正在嘗試通過以下方式初始化 UISegmentedControl:

final class MyView: UIView {
    lazy var selector: UISegmentedControl = {
        let segmentedControl = UISegmentedControl(items: ["A", "B"])

        return segmentedControl
    }

    [...]

    override init(frame: CGRect) {
        super.init(frame: .zero)
        //autolayout, addsubview, etc..
    }
}

這工作得很好。 但是我現在想將真實數據設置為分段控件的項目,我認為這些應該來自 Controller。 我嘗試使用這樣的委托模式:

protocol SegmentedControlDataSourceDelegate: class {
    func getData() -> [String]
}

final class MyView: UIView {
    weak var segmentedControlDataSource: SegmentedControlDataSourceDelegate!
    lazy var selector: UISegmentedControl = {
        let segmentedControl = UISegmentedControl(items: self.segmentedControlDataSource.getData())

        return segmentedControl
    }

    [...]

    override init(frame: CGRect) {
        super.init(frame: .zero)
        //autolayout, addsubview, etc..
    }
}

這是行不通的,因為委托是在視圖初始化之后添加的,就像在 ViewController 中這樣:

let myView = MyView()
self.view = myView
myView.segmentedControlDataSource = self

(並且 ViewController 實現了委托的getData()方法)

由於分段控件是一個惰性變量,因此不會再次計算它,並且在實際設置委托之前將其初始化為沒有委托,從而引發錯誤。

我應該如何修改我的代碼以便能夠從 ViewController 中查詢項目,同時保留 MVC 分離? 或者我對 MVC 的假設在哪里出錯了?

您可以像這樣在視圖中實現updateSegmentedControl()方法:

func updateSegmentedControl() {
    self.selector.removeAllSegments()
    for segment in self.segmentedControlDataSource?.getData() {
        self.selector.insertSegment(withTitle: segment, at: self.selector.numberOfSegments, animated: false)

    }
}

並在數據更改時調用它(以及在設置委托之后)

此外,您正在使用myView.delegate = self設置視圖的委托,您需要myView.segmentedControlDataSource = self

您的 segmentedControlDataSource 已隱式展開,這可能會導致崩潰。 你應該像這樣聲明它:

weak var segmentedControlDataSource: SegmentedControlDataSourceDelegate?

另一件事 - 選擇器名稱有效,但它代表 swift: link中的其他內容,這可能會造成混淆

可以使用兩種方法。 我提到他們都使用最適合您的用例的一個。

1)為您的自定義視圖 class 編寫一個方便的初始化程序,其中段項作為參數,即

class MyView: UIView {

    var items: [String]

    lazy var selector: UISegmentedControl = {
        let segmentedControl = UISegmentedControl(items: self.items)
        return segmentedControl
    }()

    init(items: [String]) {
        self.items = items
        super.init(frame: .zero)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

僅當您在初始化視圖時擁有這些項目並且您不需要為某些服務器或后端獲取它們時,上述方法才有效。

2)您可以在 UISegmentedControl 初始化時添加虛擬段並使用實際值更新它們,或者在沒有任何段的情況下初始化 UISegmentedControl 並稍后插入它們,即

lazy var selector: UISegmentedControl = {
   let segmentedControl = UISegmentedControl()
   segmentedControl.frame = CGRect(x: 100, y: 100, width: 80, height: 50)
   return segmentedControl
}()

如上所述初始化 segmentedControl 並添加以下方法以從數據源進行更新。

func updateSegmentControlWithItems(_ items: [String]) {
    //If no segments were added
    items.enumerated().forEach { (offset, element) in
        self.selector.insertSegment(withTitle: element, at: offset, animated: true)
    }

    //If dummy segments were added
    items.enumerated().forEach { (offset, element) in
        self.selector.setTitle(element, forSegmentAt: offset)
    }
}

當您需要從任何異步任務中獲取分段標題時,上述方法最有效。 我認為不需要委托,因為創建該視圖(MyView)的 class 有它的引用,所以為什么不存儲該引用並在有項目時調用 updateSegmentControlWithItems()。 當您需要反向發送數據時,委托是有效的,即從 MyView 到創建該視圖的 class。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM