【问题标题】:error "Value of type 'UIViewController' has no member..." when moving a func inside extension在扩展内移动 func 时出现错误“'UIViewController' 类型的值没有成员...”
【发布时间】:2021-01-05 03:54:54
【问题描述】:

我需要移动一个用于在扩展中添加和删除日志视图的方法,以便将它提供给每个控制器。为此,我在原始方法中添加了一个 inout UIVew 参数,其中我为视图使用了一个全局变量。不,我有这个错误

“UIViewController”类型的值没有成员“containerForLoading”

self.containerForLoading 中删除 self 会报错:

转义闭包捕获'inout'参数'containerForLoading'

在动画闭包内(见评论) 是整个过程都错了还是我在最后一步迷路了?

extension UIViewController {
        
    func showLoadingView(containerForLoading: inout UIView, uponView: UIView) {
        
           containerForLoading = UIView(frame: uponView.bounds)
           uponView.addSubview(containerForLoading)
           
           containerForLoading.backgroundColor = .white
           containerForLoading.alpha = 0
           UIView.animate(withDuration: 0.24) { self.containerForLoading.alpha = 0.8 } //here the error
           let activivityIndicator = UIActivityIndicatorView()
           containerForLoading.addSubview(activivityIndicator)
           
           activivityIndicator.translatesAutoresizingMaskIntoConstraints = false
           
           
           NSLayoutConstraint.activate([
               
               activivityIndicator.centerYAnchor.constraint(equalTo: uponView.centerYAnchor),
               activivityIndicator.centerXAnchor.constraint(equalTo: uponView.centerXAnchor)
               
           ])
           
           activivityIndicator.startAnimating()
       }
       
    func removeLoading(containerForLoading: inout UiView, uponView: UIView) {
           
           containerForLoading.removeFromSuperview()
           
       }
    
}

这是原始视图控制器中的代码

使用这个变量

var containerForLoading = UIView()

在需要时以这种方式调用

self.showLoadingView(uponView: self.view)
extension ViewController {
    
    func showLoadingView(uponView: UIView) {
        containerForLoading = UIView(frame: uponView.bounds)
        uponView.addSubview(containerForLoading)

        containerForLoading.backgroundColor = .white
        containerForLoading.alpha = 0
        UIView.animate(withDuration: 0.24) { self.containerForLoading.alpha = 0.8 }
        let activivityIndicator = UIActivityIndicatorView()
        containerForLoading.addSubview(activivityIndicator)

        activivityIndicator.translatesAutoresizingMaskIntoConstraints = false


        NSLayoutConstraint.activate([

            activivityIndicator.centerYAnchor.constraint(equalTo: uponView.centerYAnchor),
            activivityIndicator.centerXAnchor.constraint(equalTo: uponView.centerXAnchor)

        ])

        activivityIndicator.startAnimating()
    }

    func removeLoading(uponView: UIView) {

        containerForLoading.removeFromSuperview()

    }
    
    
}

【问题讨论】:

  • self.containerForLoading.alphaextension UIViewController {} 内调用,因此它期望它是 UIViewController 的属性。事实并非如此。你的意思是`containerForLoading.alpha`,因为它是你想要的前一个变量。
  • 但无法删除 self 否则我得到 Escapingclosure captures 'inout' parameter 'containerForLoading' 错误
  • 您能否展示您的代码在 放入扩展程序之前是什么样的?
  • 用旧代码更新,除了inout新参数外基本相同

标签: ios swift extension-methods inout


【解决方案1】:

您可以将loadingContainerTag 设为局部变量,并将参数名称更改为其他名称。然后在创建容器视图后分配给参数:

extension UIViewController {
    func showLoadingView(containerForLoadingProperty: inout UIView, uponView: UIView) {
        // local variable!
        let containerForLoading = UIView(frame: uponView.bounds)
        
        // also set property
        containerForLoadingProperty = containerForLoading
        
        uponView.addSubview(containerForLoading)
        containerForLoading.backgroundColor = .white
        containerForLoading.alpha = 0
        
        // no "self."!
        UIView.animate(withDuration: 0.24) { containerForLoading.alpha = 0.8 }
        // ... everything else is the same

removeLoading 可以只有一个非inout 参数:

func removeLoading(containerForLoadingProperty: UIView) {
    containerForLoadingProperty.removeFromSuperview()
}

但是...


显示加载指示器的方法需要inout 参数是非常奇怪的。它不应该分配给 caller 提供的特殊属性。它应该只显示加载指示器!

containerForLoading 属性的目的是让在removeLoading 中,您知道要删除哪个视图。如果您不将containerForLoading 视图存储在属性中的某个位置,您将不知道要删除哪个视图,对吧?好吧,我们可以使用视图的tag 属性来识别视图,所以您可以将containerForLoading 设为局部变量,然后在removeLoading 中,使用其标记找到它。

extension UIViewController {
    
    static let loadingContainerTag = <a number you like>

    func showLoadingView(uponView: UIView) {
        // local variable!
        let containerForLoading = UIView(frame: uponView.bounds)
        uponView.addSubview(containerForLoading)
        containerForLoading.backgroundColor = .white
        containerForLoading.alpha = 0
        
        // set tag
        containerForLoading.tag = UIViewController.loadingContainerTag
        
        // no "self."!
        UIView.animate(withDuration: 0.24) { containerForLoading.alpha = 0.8 }
        let activivityIndicator = UIActivityIndicatorView()
        containerForLoading.addSubview(activivityIndicator)
        activivityIndicator.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            activivityIndicator.centerYAnchor.constraint(equalTo: uponView.centerYAnchor),
            activivityIndicator.centerXAnchor.constraint(equalTo: uponView.centerXAnchor)
        ])
        activivityIndicator.startAnimating()
    }
    func removeLoading(uponView: UIView) {
        // find view with the tag
        uponView.viewWithTag(UIViewController.loadingContainerTag)?.removeFromSuperview()
    }
}

【讨论】:

  • 谢谢,这似乎有效!我想知道通过协议扩展是否可以实现相同的成就,存储属性是否有问题?
  • 是的,在扩展中添加存储属性没有非 hacky 的方式。如果有,您可以添加一个UIView 属性来存储装载容器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多