将代码移动到单独的函数时遇到问题
Am having trouble moving code into a separate function
在我的 GameViewController 的 viewDidLoad() 函数中,我做了两件事:
1-我创建了一个子UIVIew,myView,添加到主视图中,
2- 我调用我的函数 addConstraints,它在 GameViewController 的代码中。
当我创建GameScene时,self.myView.frame.width & self.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
}
不能只移动这种函数,因为里面的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)
}
}
然后不要在 viewDidLoad()
中调用 addConstraints()
,而应调用 myView.createConstraints()
。它应该和以前一样工作。
You can read more about extension from Extensions — The Swift
Programming Language.
And also you should read this too Programmatically Creating
Constraints
看完代码后,我一遍又一遍地意识到我正在调用 safeAreaLayout 例程 before 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
}
}
在我的 GameViewController 的 viewDidLoad() 函数中,我做了两件事:
1-我创建了一个子UIVIew,myView,添加到主视图中,
2- 我调用我的函数 addConstraints,它在 GameViewController 的代码中。
当我创建GameScene时,self.myView.frame.width & self.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
}
不能只移动这种函数,因为里面的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)
}
}
然后不要在 viewDidLoad()
中调用 addConstraints()
,而应调用 myView.createConstraints()
。它应该和以前一样工作。
You can read more about extension from Extensions — The Swift Programming Language.
And also you should read this too Programmatically Creating Constraints
看完代码后,我一遍又一遍地意识到我正在调用 safeAreaLayout 例程 before 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
}
}