admin管理员组文章数量:1125291
I have a UIButton
with an action. If I click the button, I see a stack view with two views. And if I click on some view on stack view, I perform a new action of some kind. But for views in stack view, I don't use an action button. I'm using TouchesBegan
to detect a touch and perform an action. I use next code:
class SomeC: UIViewController {
lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.spacing = 32
stackView.alignment = .fill
stackView.distribution = .equalSpacing
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
var button: UIButton = {
let button = UIButton()
button.layer.shadowColor = UIColor.black.withAlphaComponent(0.5).cgColor
button.layer.shadowOffset = CGSize.zero
button.layer.shadowOpacity = 0.2
button.layer.shadowRadius = 3
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let settingsMenu = UIStackView()
var itemStackView = UIStackView()
let settingsBackground = UIVisualEffectView(effect: UIBlurEffect(style: .light))
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton()
button.backgroundColor = .red.withAlphaComponent(0.25)
button.widthAnchor.constraint(equalToConstant: 56).isActive = true
button.heightAnchor.constraint(equalToConstant: 56).isActive = true
button.addTarget(self, action: #selector(self.rightButtonAction), for: .touchUpInside)
stackView.addArrangedSubview(button)
stackView.widthAnchor.constraint(equalToConstant: ((72+32) * 2) - 32).isActive = true
}
@objc func rightButtonAction(sender: UIButton!) {
settingsBackground.frame = UIScreen.main.bounds
settingsBackground.clipsToBounds = true
settingsBackground.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(settingsBackground)
settingsMenu.axis = .vertical
settingsMenu.spacing = 16
settingsMenu.distribution = .fillEqually
settingsMenu.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(settingsMenu)
for index in 0...1 {
itemStackView = UIStackView()
itemStackView.tag = index
itemStackView.backgroundColor = .white.withAlphaComponent(0.75)
settingsMenu.addArrangedSubview(itemStackView)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if touch?.view == self.settingsBackground { /*off settingsBackground,settingsMenu*/ }
if touch?.view == self.settingsMenu.subviews[0] { /*action*/ }
if touch?.view == self.settingsMenu.subviews[1] { /*action*/ }
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if touch?.view == self.settingsMenu.subviews[0] { /*action*/ }
if touch?.view == self.settingsMenu.subviews[1] { /*action*/ }
}
}
But when I click outside button
area my app crashed:
Thread 1: "***-[_NSArrayO objectAtIndex:]: index 0 beyond bounds for empty array"
problem in this lines (I remove this all works fine):
if touch?.view == self.settingsMenu.subviews[0] { /*action*/ }
if touch?.view == self.settingsMenu.subviews[1] { /*action*/ }
Maybe I get error if I click outside the button because settingsMenu.subviews[0]
and settingsMenu.subviews[1]
doesn't exist. But how to fix the problem? How not call subviews if these not exist?
I have a UIButton
with an action. If I click the button, I see a stack view with two views. And if I click on some view on stack view, I perform a new action of some kind. But for views in stack view, I don't use an action button. I'm using TouchesBegan
to detect a touch and perform an action. I use next code:
class SomeC: UIViewController {
lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.spacing = 32
stackView.alignment = .fill
stackView.distribution = .equalSpacing
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
var button: UIButton = {
let button = UIButton()
button.layer.shadowColor = UIColor.black.withAlphaComponent(0.5).cgColor
button.layer.shadowOffset = CGSize.zero
button.layer.shadowOpacity = 0.2
button.layer.shadowRadius = 3
button.translatesAutoresizingMaskIntoConstraints = false
return button
}()
let settingsMenu = UIStackView()
var itemStackView = UIStackView()
let settingsBackground = UIVisualEffectView(effect: UIBlurEffect(style: .light))
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton()
button.backgroundColor = .red.withAlphaComponent(0.25)
button.widthAnchor.constraint(equalToConstant: 56).isActive = true
button.heightAnchor.constraint(equalToConstant: 56).isActive = true
button.addTarget(self, action: #selector(self.rightButtonAction), for: .touchUpInside)
stackView.addArrangedSubview(button)
stackView.widthAnchor.constraint(equalToConstant: ((72+32) * 2) - 32).isActive = true
}
@objc func rightButtonAction(sender: UIButton!) {
settingsBackground.frame = UIScreen.main.bounds
settingsBackground.clipsToBounds = true
settingsBackground.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(settingsBackground)
settingsMenu.axis = .vertical
settingsMenu.spacing = 16
settingsMenu.distribution = .fillEqually
settingsMenu.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(settingsMenu)
for index in 0...1 {
itemStackView = UIStackView()
itemStackView.tag = index
itemStackView.backgroundColor = .white.withAlphaComponent(0.75)
settingsMenu.addArrangedSubview(itemStackView)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if touch?.view == self.settingsBackground { /*off settingsBackground,settingsMenu*/ }
if touch?.view == self.settingsMenu.subviews[0] { /*action*/ }
if touch?.view == self.settingsMenu.subviews[1] { /*action*/ }
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if touch?.view == self.settingsMenu.subviews[0] { /*action*/ }
if touch?.view == self.settingsMenu.subviews[1] { /*action*/ }
}
}
But when I click outside button
area my app crashed:
Thread 1: "***-[_NSArrayO objectAtIndex:]: index 0 beyond bounds for empty array"
problem in this lines (I remove this all works fine):
if touch?.view == self.settingsMenu.subviews[0] { /*action*/ }
if touch?.view == self.settingsMenu.subviews[1] { /*action*/ }
Maybe I get error if I click outside the button because settingsMenu.subviews[0]
and settingsMenu.subviews[1]
doesn't exist. But how to fix the problem? How not call subviews if these not exist?
1 Answer
Reset to default 0It's expected behavior because when you're tapping outside of the red button, touchesBegan
and touchesEnded
are also getting called. However, rightButtonAction
function are not executed, thus settingsMenu.subViews
is empty.
print(settingsMenu.subViews.isEmpty)
//true
By calling settingsMenu.subviews[0]
, you're trying to get the first subview of the settingsMenu
directly by its index. And since settingsMenu
has no subview at all, an exception is thrown.
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArray0 objectAtIndex:]: index 0 beyond bounds for empty array'
To prevent the exception, you should check whenever a view's subView array contains an element or not:
extension Array {
subscript(safe index: Int) -> Element? {
guard count > index, index >= 0 else { return nil }
return self[index]
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
...
if touch?.view == self.settingsMenu.subviews[safe: 0] { }
if touch?.view == self.settingsMenu.subviews[safe: 1] { }
}
Notice: Within the for loop, you will create two new stackViews, but itemStackView
always points to the 2nd one. You may want to update it.
本文标签: swiftApp crashed after using stack view subviewsStack Overflow
版权声明:本文标题:swift - App crashed after using stack view subviews - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736659578a1946349.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论