如何在视图控制器外以编程方式创建视图

时间:2018-02-13 21:50:08

标签: ios swift uiview uiprogressview

目前我正在尝试创建一个将使用经理类调用的UIProgressView:

 func addProgressBar() {

        let rect = CGRect(x: 10, y: 70, width: 250, height: 0)
        let progressView = UIProgressView(frame: rect)
        progressView.progress = 0.0
        progressView.tintColor = UIColor.blue
        self.view.addSubview(progressView)
    }

这个问题出现了这个问题:

 self.view.addSubview(progressView)

因为该函数不在viewController中我得到错误:

  

“NetworkHelper”类型的值没有成员“view”

任何想法如何在viewcontroller之外添加progressView?

4 个答案:

答案 0 :(得分:1)

嗯,你可能自己猜对了,你需要view来放置progressBar。我认为addProgressBar方法的调用者应该知道最适合的地方,所以我建议使用progressBar,其参数为UIViewController类型,这将是目标负责进行网络呼叫,因此是将进度条放入:

的目标
func addProgressBar(targetViewController: UIViewController) {
    // moreover, are you sure here that the height of the progressBar should be 0?
    let rect = CGRect(x: 10, y: 70, width: 250, height: 0)
    let progressView = UIProgressView(frame: rect)
    progressView.progress = 0.0
    progressView.tintColor = UIColor.blue
    targetViewController.view.addSubview(progressView)
}

答案 1 :(得分:0)

你需要有一个视图来放置它。要么你抓住顶部的viewcontroller并把它放在那个或你调用你的NetworkHelper类并传递一个它应该放置进度条的视图。

我使用此方法来抓取顶部viewcontroller

func topViewController() -> UIViewController? {
    guard var topVC = UIApplication.shared.keyWindow?.rootViewController else { return nil }
    while let presentedViewController = topVC.presentedViewController {
        topVC = presentedViewController
    }

    return topVC
}

答案 2 :(得分:0)

您可以获取最顶层的视图控制器,并将子视图添加到其视图属性中。

iPhone -- How to find topmost view controller

答案 3 :(得分:0)

您可以使用"回调",使用委托设计模式

https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/Delegation.html

或Swift的闭包(Objective-C块)

你可以退回"关闭"从函数中,这个闭包创造了进步。要在view / viewController上使用

 func addProgressBar() -> (UIView) -> () {

    return { view in
        let rect = CGRect(x: 10, y: 70, width: 250, height: 0)
        let progressView = UIProgressView(frame: rect)
        progressView.progress = 0.0
        progressView.tintColor = UIColor.blue
        view.addSubview(progressView)
    }
}

然后在视图控制器中使用此返回值,例如:

      (networkHelper.addProgressBar())(self.view)

如果您想在视图控制器上创建进度视图,并在那里进行管理,那就是。

class NetworkHelper {

    ...

    func doAnythingWithNetwork(withProgress: @escaping (NSProgress) -> (),
                               completion: @escaping (Data?, Error?) -> ()) {
        ...
        // When you get any progress (like in Alamofire for example).
        // Pass it to the callback
        withProgress(progress)
        ...
    }

}

然后在你的viewController中:

let networker = NetworkHelper()

...

@IBAction func buttonClicked(_ sender: Any?) {
    networker.doAnythingWithNetwork(withProgress: { [weak self] progress in
        // You can use your viewController here (note: use 'self?', not
        //     'self', here self is "weak", only to avoid memory leaks).
        // Note: Any update of the view must be in DispatchQueue.main
    }, completion: { [weak self] data, error in
        // Your usual completion handler.
    })
}

但推荐的解决方案是让您的NetworkHelper只是一个模型,只是为了处理Web请求和数据。 SOLID原则具有单一责任原则"即设计每个对象只有一个责任。

视图(或viewcontroller)应该处理addProgressBar,而NetworkHelper应该通过委托或闭包/块将此进度传递给更新视图的viewcontroller。