【问题标题】:Am having trouble moving code into a separate function将代码移动到单独的函数中时遇到问题
【发布时间】:2021-02-12 13:39:33
【问题描述】:

在我的 GameViewController 的 viewDidLoad() 函数中,我做了两件事:

1-我创建了一个子UIVIew,myView,添加到主视图中,

2- 我调用我的函数 addConstraints,它在 GameViewController 的代码中。

当我创建 GameScene 时,self.myView.frame.widthself.myView.frame.height 包含正确的值,并遵守 safeAreaLayout 指南。

我想让我的代码更清晰,所以我将 addConstraints 函数移到了一个单独的文件中。但是当我以这种方式运行我的应用程序时,self.myView.frame.width & self.myView.frame.height 为零。

所以我很好奇我是否以某种方式错误地翻译了函数,或者这可能是我无法在主代码之外移动的东西?

第一块是原代码,第二块是函数

//located with GameViewControl    
private func addConstraints(){
        var constraints = [NSLayoutConstraint]()
        
        constraints.append(myView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor))
        constraints.append(myView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor))
        constraints.append(myView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor))
        constraints.append(myView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor))
        NSLayoutConstraint.activate(constraints)
    }

翻译成函数

//called from GameViewControl
    createConstraints(view: myView)
    ....
        
//located outside of GameViewControl
func createConstraints(view: UIView) {
    var constraints = [NSLayoutConstraint]()
                    
    constraints.append(view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor))
    constraints.append(view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor))
    constraints.append(view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor))
    constraints.append(view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor))
                    
    NSLayoutConstraint.activate(constraints)
}

这里是 GameViewControl 的完整文件

import UIKit
import SpriteKit

class GameViewController: UIViewController {
    
    private let myView : UIView = {
        let myView = UIView()
        setViewAttributes(view: myView)
        return myView
    }()

    private func addConstraints(){
         var constraints = [NSLayoutConstraint]()

        //add
         constraints.append(myView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor))
         constraints.append(myView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor))
         constraints.append(myView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor))
         constraints.append(myView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor))
        
        //activate
         NSLayoutConstraint.activate(constraints)
     }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        #if DEBUG
            print ("viewDidLoad")
        #endif
        
        if let view = self.view as! SKView? {
            getScreenDimensions (screen: &screenDims)
            view.addSubview(myView)
            addConstraints()

            var scene : GameScene!
            DispatchQueue.main.async { scene = GameScene(size: CGSize(width: self.myView.frame.width, height: self.myView.frame.width))
                scene.anchorPoint = CGPoint(x: 0.0, y: 0.0)
                scene.backgroundColor = .clear
                scene.scaleMode = .aspectFit
                view.isHidden = false
                view.presentScene(scene)
            }
            view.ignoresSiblingOrder    = true
            view.showsFPS               = true
            view.showsNodeCount         = true
            view.showsPhysics           = true
        }
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()

        #if DEBUG
            print ("GVC viewDidLayoutSubviews")
        #endif

        myGlobalVars.sceneRect = view.frame
        
        if #available(iOS 11.0, *) {
            myGlobalVars.topSafeArea    = view.safeAreaInsets.top
            myGlobalVars.bottomSafeArea = view.safeAreaInsets.bottom
        } else {
            myGlobalVars.topSafeArea    = topLayoutGuide.length
            myGlobalVars.bottomSafeArea = bottomLayoutGuide.length
        }
    }
    
    override var shouldAutorotate: Bool {
        #if DEBUG
            print ("shouldAutorotate")
        #endif
        return false
    }
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        #if DEBUG
            print ("supportedInterfaceOrientations")
        #endif
        if UIDevice.current.userInterfaceIdiom == .phone {
            return .allButUpsideDown
        } else {
            return .all
        }
    }
    override var prefersStatusBarHidden: Bool {
        #if DEBUG
            print ("prefersStatusBarHidden")
        #endif
        return false
    }
}

对函数 setViewAttributes 的调用确实将视图传递给函数,并且我已验证该函数正在工作。

func setViewAttributes(view: UIView)
{
    view.alpha                = 0.0
    view.frame.size.height    = UIScreen.main.nativeBounds.height
    view.frame.size.width     = UIScreen.main.nativeBounds.width
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor      = .clear
}

【问题讨论】:

    标签: swift uikit safearealayoutguide


    【解决方案1】:

    您不能只移动这种函数,因为其中的view 变量引用了GameViewController.view

    如果您想进行这样的重构,您可以将此方法移至扩展并在您的 GameViewController 中调用它。

    public extension UIView {
        func createConstraints() {
            guard let superview = superview else { return }
    
            view.translatesAutoresizingMaskIntoConstraints = false
            var constraints = [NSLayoutConstraint]()
                            
            constraints.append(leadingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.leadingAnchor))
            constraints.append(trailingAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.trailingAnchor))
            constraints.append(bottomAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.bottomAnchor))
            constraints.append(topAnchor.constraint(equalTo: superview.safeAreaLayoutGuide.topAnchor))
                            
            NSLayoutConstraint.activate(constraints)
        }
    }
    

    然后,您应该调用myView.createConstraints(),而不是在viewDidLoad() 中调用addConstraints()。它应该和以前一样工作。

    你可以从Extensions — The Swift Programming Language阅读更多关于扩展的信息。

    你也应该阅读这篇文章Programmatically Creating Constraints

    【讨论】:

    • 只是为了确保,我正在尝试将视图传递给函数。直接试了一下,作为参考。
    • 那里有一个函数已经通过视图没有问题。刚刚更新了OP
    • 你最好使用约束而不是设置框架。扩展是这种解决方案的好方法。它被称为自动布局,这是您的另一种阅读方式:)
    • 我没有使用故事板。从技术上讲,我可以离开这个,留下我的原始代码。这更像是一个“为什么我不能把它正确地放在一个函数中”的问题。
    • 你可以。但是您正在尝试在视图之间添加约束。第二个应该是superview。 view.leadingAnchor.constraint(equalTo: superview.leadingAnchor)
    【解决方案2】:

    在浏览完代码之后,我一遍又一遍地意识到我正在调用 safeAreaLayout 例程之前 viewDidLayoutSubviews。现在我可以将我的调用转移到一个函数并且它可以工作。现在我很想知道它为什么在我过早地调用它之前工作。但也许我应该感谢我发现了一个重大错误。

    所以现在我的代码看起来与 OP 中的代码相同,除了每个关于屏幕尺寸和 safeAreaLayout 的调用都在 viewDidLayoutSubviews 函数中完成。

    而且 addConstraints 现在是一个外部函数

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    
        getScreenDimensions (screen: &screenDims)
        view.addSubview(myView)
        addConstraints()
        myGlobalVars.sceneRect = view.frame
        createConstraints(view: myView)
        
        if #available(iOS 11.0, *) {
            myGlobalVars.topSafeArea    = view.safeAreaInsets.top
            myGlobalVars.bottomSafeArea = view.safeAreaInsets.bottom
        } else {
            myGlobalVars.topSafeArea    = topLayoutGuide.length
            myGlobalVars.bottomSafeArea = bottomLayoutGuide.length
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2017-04-28
      • 1970-01-01
      • 2020-09-23
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 2019-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多