Ios 在Swift中的不同线程上加载UI
我有一个具有复杂UI视图的子控制器。我的视图是在故事板中设计的。这会导致屏幕冻结,如果用户继续点击冻结的屏幕,则会增加崩溃的可能性 我是否可能在不同的线程中加载UI并向用户显示活动指示器 <>我知道中间的复选框是兼容的。复选框是自定义的UI按钮。我在drawRect上画它们。根据选择、边框宽度、动态边框颜色、动态选定边框颜色、背景颜色、选择背景颜色 编辑: 请注意,superview标记不是500。这是一种多重选举观点Ios 在Swift中的不同线程上加载UI,ios,swift,xcode,storyboard,background-thread,Ios,Swift,Xcode,Storyboard,Background Thread,我有一个具有复杂UI视图的子控制器。我的视图是在故事板中设计的。这会导致屏幕冻结,如果用户继续点击冻结的屏幕,则会增加崩溃的可能性 我是否可能在不同的线程中加载UI并向用户显示活动指示器 我知道中间的复选框是兼容的。复选框是自定义的UI按钮。我在drawRect上画它们。根据选择、边框宽度、动态边框颜色、动态选定边框颜色、背景颜色、选择背景颜色 编辑: 请注意,superview标记不是500。这是一种多重选举观点 func setupCheckBox(checkbox: CheckBox) {
func setupCheckBox(checkbox: CheckBox) {
checkbox.setCornerRadius(radius: CGSize(width: checkbox.frame.size.width * 0.5, height: checkbox.frame.size.height * 0.5))
checkbox.setBorderWidth(width: 2.0)
checkbox.setBorderColor(border_color: UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0))
checkbox.setSelection(selection_color: UIColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 0.9))
checkbox.setSelected(selection: false)
checkbox.setHit(edgeInsets: UIEdgeInsets(top: -4, left: -4, bottom: -4, right: -4))
checkbox.delegate = self
}
复选框实现:
圆角实施:
苹果的文档说 如果您的应用程序具有图形用户界面,建议使用 接收与用户相关的事件并启动界面更新 从应用程序的主线程。这种方法有助于避免 与处理用户事件和事件相关的同步问题 绘图窗口内容。一些框架,如Cocoa,通常 需要这种行为,但即使是那些不需要的,也要保持这种行为 主线程上的行为具有简化逻辑的优点 用于管理用户界面
有关详细信息,任何时候,当您需要触摸涉及UI的任何内容时,请将该代码放入到主队列的分派中。对于Swift 3,请参阅新的DispatchQueue机制,否则,请使用良好的ol'dispatch\u async。。。并提供主队列。这方面的一个很好的教程是 我有一个具有复杂UI视图的子控制器 你在这里展示的并没有那么复杂。我想你的意思是,计算所有东西的去向是复杂的。如果这是真的,则需要计算绘图周期以外的时间 这会导致屏幕冻结,如果用户继续点击冻结的屏幕,则会增加崩溃的可能性 如果由于用户与冻结视图交互而导致崩溃,那么您的问题并不是您所认为的问题。如果挂起事件循环,所有用户触摸都将被忽略,因为它们也在事件循环中。但是,正如我所记得的那样,如果你花太长时间从事件循环返回,你可能会遇到崩溃,尽管现在可能更短。见上文;您必须将任何复杂的计算移到其他地方 <>我知道中间的复选框是兼容的。复选框是自定义的UI按钮。我在drawRect上画它们。根据选择、边框宽度、动态边框颜色、动态选定边框颜色、背景颜色、选择背景颜色 好极了。找出问题发生的地方是大多数解决方案。不过,您的drawRect对于这些应用程序来说应该非常简单。它们只是圆圈。如果您的drawRect除了检查预先计算的值之外,还执行其他操作,那么您需要将所有计算移到其他地方。drawRect通常不应该计算太多。它必须非常快 如果您的问题是要计算的内容很多,而且计算本身需要很长时间,那么您需要将其移动到后台队列,在计算时显示占位符视图,并在完成后绘制真实视图 如果您的问题是子视图比我们看到的要多得多,您可能需要减少子视图的数量并进行更多的自定义绘图,但是您提供的屏幕截图看起来并不复杂 但在一天结束时,您必须更新主队列上的UI,并且不能阻止主队列。因此,如果您有任何复杂的事情要做,您需要在另一个队列上完成,并在完成时更新UI
如果您的问题是从情节提要中拖出内容所需的实际时间,您可以尝试将此片段提取到自己的情节提要或笔尖中,或者以编程方式绘制它,或者只是减少情节提要中的元素数量,但我个人从未遇到过这样的情况。请参阅:第一,ty了解信息。第二,是的,我知道。我们不应该从后台线程更新ui。我的问题不同。用户界面本身很复杂,我已经给你。。。我知道的一件事是,如果应用程序没有例外,并且没有大量的数据,那么当点击应用程序的不同屏幕时,它将永远不会崩溃。这取决于应用程序的逻辑。我可以通过使用dispatch禁用当前视图来解决崩溃问题。但是,我不能解决这个问题。在iPhone4上,它至少需要5秒。你应该真正使用仪器来找出应用程序到底在哪里暂停,然后看看你是否可以改进负责的代码。在我注入用户数据之前,我的UI本身很复杂。要我深入了解你写的内容吗?如果你正在用复杂的视图更新你的用户界面,唯一显示活动指示器块用户界面并在
只有主线程。好的,我可以设置用户交互。我可以显示活动指示器。但冻结问题不会得到解决。活动指示器本身将被冻结。对吗?如果我在调度中执行,活动指示器将显示没有问题。但是,它也会被冻结。谢谢你的帮助。还有其他想法吗?问题是所有方法都需要不必要的布局调用。我把它取了下来,效果很好。强制调用drawrect setneedsdisplay就足够了。我需要帮助。应用程序在所有设备上运行缓慢。我没有触摸任何东西。视图很重,它会冻结屏幕直到加载。我想解决冻结问题。有什么想法吗?是的,任何时候你更新任何涉及UI的东西,从主队列开始。任何繁重的处理、网络请求等都应该从后台队列中完成。一旦这些后台队列上的处理完成,通常会分派到主队列以更新UI(如活动微调器)。如果你在主队列上执行任何任务,请将它们放入后台队列。你还没有了解情况,兄弟。UI很复杂,它加载在主线程中。但是,因为它很重,所以会冻结屏幕。我不在主线程上做任何处理或http连接。你发送的屏幕截图中的UI本身看起来不太重;我已经创造了许多类似的布局和这样没有任何问题。也许你可以从你的管理员那里发布相关代码,否则我想这里的任何人都不知道该如何帮助。一个沉重的UI也可能是你当前视图控制器做得太多的一个指标,你可能会考虑将行为分解成单独的控制器/场景。11我不做任何计算的东西去哪里。所有的故事板都与嵌入的序列相连。我发现我指出的撞车事件是无效的。这并不是我重新调查的坠机原因。我将把它从问题中移除,为什么你说我知道顺从性在中间的复选框中?你这是什么意思?问题是所有方法都需要不必要的layoutifn调用。我把它取了下来,效果很好。强制调用drawrect setneedsdisplay就足够了。我需要帮助。应用程序在所有设备上运行速度都很慢。@hasan83啊,你几乎不应该直接调用layoutIfNeeded,除非你真的需要在进入下一行代码之前计算布局,这通常是因为你已经在使用布局代码了。你几乎总是说setNeedsLayout,即使这样也常常不需要。
protocol CheckBoxProtocol: class {
func checkbox(checkBox: UIView, selection: Bool)
}
class CheckBox: RoundedCornersButton {
var checked_icon: String?
var unchecked_icon: String?
weak var delegate: CheckBoxProtocol?
var selectedd: Bool = false
var allow_none: Bool = false
var hitEdgeInsets: UIEdgeInsets?
var selection_color: UIColor?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setHit(edgeInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0))
selection_color = .clear
backgroundColor = .clear
addTarget(self, action: #selector(didTouchButton), for: .touchUpInside)
}
func setCheckedIcon(checked_icon: String) {
self.checked_icon = checked_icon
setSelectionTo(button: self, selected: selectedd, inform: nil)
}
func setUncheckedIcon(unchecked_icon: String) {
self.unchecked_icon = unchecked_icon
setSelectionTo(button: self, selected: selectedd, inform: nil)
}
func setSelection(selection_color: UIColor) {
self.selection_color = selection_color
setNeedsDisplay()
layoutIfNeeded()
}
// if superview tag is equal to 500. all other checkbox in the superview will deselected.
func didTouchButton() {
if superview?.tag == 500 {
for button: UIView in (superview?.subviews)! {
if button is CheckBox && button != self {
setSelectionTo(button: button as! CheckBox, selected: false, inform:delegate)
}
}
setSelectionTo(button: self as CheckBox, selected: allow_none ? (!selectedd) : true, inform:delegate)
} else {
setSelectionTo(button: self as CheckBox, selected: !selectedd, inform:delegate)
}
}
func setSelectionTo(button: CheckBox, selected: Bool, inform: CheckBoxProtocol?) {
button.selectedd = selected
if selected {
if checked_icon != nil {
(button as CheckBox).setImage(UIImage.init(named: checked_icon!), for: .normal)
}
if color != .clear {
button.setTitleColor(color, for: .normal)
}
} else {
if unchecked_icon != nil {
(button as CheckBox).setImage(UIImage.init(named: unchecked_icon!), for: .normal)
}
if selection_color != .clear {
button.setTitleColor(selection_color, for: .normal)
}
}
button.setNeedsDisplay()
button.layoutIfNeeded()
inform?.checkbox(checkBox: button, selection: selected)
}
func setSelected(selection: Bool) {
super.isSelected = selection
setSelectionTo(button: self, selected: selection, inform: nil)
setNeedsDisplay()
layoutIfNeeded()
}
func setHit(edgeInsets: UIEdgeInsets)
{
hitEdgeInsets = edgeInsets
}
// handeling hits on checkbox. taking in count the hitEdgeInsets. if hitEdgeInsets have minus values hits around the checkbox will be considered as a valid hits.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
if UIEdgeInsetsEqualToEdgeInsets(hitEdgeInsets!, .zero) || !isEnabled || isHidden {
return super.point(inside: point, with: event)
}
let relativeFrame: CGRect = self.bounds
let hitFrame: CGRect = UIEdgeInsetsInsetRect(relativeFrame, hitEdgeInsets!)
return hitFrame.contains(point)
}
func isSelectedd() -> Bool {
return selectedd
}
func setAllowNone(_ allow: Bool) {
allow_none = allow
}
override func draw(_ rect: CGRect) {
super.draw(rect)
let context: CGContext = UIGraphicsGetCurrentContext()!
context.setFillColor((selection_color?.cgColor)!)
context.setStrokeColor((selection_color?.cgColor)!)
let circlePath: UIBezierPath = UIBezierPath.init(arcCenter: CGPoint(x: frame.size.width * 0.5, y: frame.size.width * 0.5), radius: frame.size.width * 0.5 - borderWidth, startAngle: 0, endAngle: CGFloat(2.0 * Float(M_PI)), clockwise: true)
if isSelectedd() {
circlePath.fill()
circlePath.stroke()
}
}
}
class RoundedCornersButton: UIButton {
var cornorRadius: CGSize!
var borderWidth: CGFloat!
var borderColor: UIColor!
var color: UIColor!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
cornorRadius = CGSize(width: 12, height: 12)
borderWidth = 0
borderColor = UIColor.clear
self.titleLabel?.numberOfLines = 1
self.titleLabel?.adjustsFontSizeToFitWidth = true
self.titleLabel?.lineBreakMode = .byClipping
self.titleLabel?.baselineAdjustment = .alignCenters
self.titleLabel?.textAlignment = .center
// clear the background color to draw it on the graphics layer
color = self.backgroundColor
self.backgroundColor = UIColor.clear
}
func setColor(_color: UIColor) {
color = _color
self.setNeedsDisplay()
self.layoutIfNeeded()
}
func setCornerRadius(radius: CGSize) {
cornorRadius = radius
self.setNeedsDisplay()
self.layoutIfNeeded()
}
func setBorderWidth(width: CGFloat) {
borderWidth = width
self.setNeedsDisplay()
self.layoutIfNeeded()
}
func setBorderColor(border_color: UIColor) {
borderColor = border_color
self.setNeedsDisplay()
self.layoutIfNeeded()
}
// redraw without increasing or decreasing hiting area.
override func draw(_ rect: CGRect) {
// Drawing code
super.draw(rect)
// drawing context
let context: CGContext = UIGraphicsGetCurrentContext()!
// set fill color
context.setFillColor(color.cgColor)
// theme color
let themeColor: UIColor = borderColor
// set stroke color
context.setStrokeColor(themeColor.cgColor.components!)
// corners to round
let corners: UIRectCorner = UIRectCorner.allCorners
// bezier path rect
let bezierRect: CGRect = CGRect(x: rect.origin.x+borderWidth*0.5, y: rect.origin.y+borderWidth*0.5, width: rect.size.width-borderWidth, height: rect.size.height-borderWidth)
// rounded path
let roundedPath: UIBezierPath = UIBezierPath.init(roundedRect: bezierRect, byRoundingCorners: corners, cornerRadii: cornorRadius)
// set stroke width
roundedPath.lineWidth = borderWidth
// fill coloring
roundedPath.fill()
// stroke coloring
roundedPath.stroke()
}
}