- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
编辑:我简化了代码并添加了对 NSThread.isMainThread() 的调用,以查看这是否是问题所在。在下面查看更广泛的编辑
我正在开发一个相当简单的应用程序,以在暑假期间协助一位教授进行研究。该应用程序旨在根据 iPad 中的加速度计确定句子中的单词难度。
本质上,用户将倾斜 iPad,从而产生非零加速度,位于 scrollView
内的 UILabel
中的文本将滚动相应地。
这在 99% 的时间里都非常有效。在我们几乎所有的测试中,它都能完美运行,它可以毫无问题地遍历整个文本,并且没有发生任何不好的事情。然而在极少数情况下,它只是中断,抛出错误 EXC_BAD_ACCESS。我想强调的是,在极少数情况下它确实会中断,没有明显的模式,它有时会发生在滚动的中间、接近尾声或开始时。
显然,我希望该应用程序没有错误,这是一个相当重要的问题,我只是想不通,因此非常感谢您提供的任何帮助。
这是我的ScrollingLabel 类
的全部代码(错误总是发生在startScrolling 类
的末尾)。
import Foundation
import UIKit
import QuartzCore
import CoreMotion
public class ScrollingLabel {
//Instantiation of scroll view and label
var baseTextLabel:UILabel!
var baseScrollView:UIScrollView!
var frame:CGRect!
//Instantiation of accelerometer materials
var motionManager=CMMotionManager()
var queue=NSOperationQueue()
//To rectify the issue, I have changed this to:
//var queue=NSOperationQueue.mainQueue(), SEE EDIT BELOW
init(frame:CGRect) {
/*Initializes the object by calling 3 private setup functions,
each dealing one with a specific feature of the final label, and
finally calling the scroll function to activate the accelerometer
control*/
setupFrame(frame)
setupLabel()
setupScroll()
startScrolling()
}
private func startScrolling() {
//The main accelerometer control of the label
println(NSThread.isMainQueue) //THIS RETURNS TRUE
//Allows the start orientation to become default
var firstOrientation:Bool
var timeElapsed:Double=0
if letUserCreateDefaultOrientation {firstOrientation=true}
else {firstOrientation=false}
var standardAccel:Double=0
//Begins taking updates from the accelerometer
if motionManager.accelerometerAvailable{
motionManager.accelerometerUpdateInterval=updateTimeInterval
motionManager.startAccelerometerUpdatesToQueue(self.queue, withHandler: { (accelerometerData, error:NSError!) -> Void in
println(NSThread.isMainQueue) //THIS RETURNS FALSE
//Changes the input of acceleration depending on constant control variables
var accel:Double
if self.timerStarted {
timeElapsed+=Double(self.updateTimeInterval)
}
if !self.upDownTilt {
if self.invertTextMotion {accel = -accelerometerData.acceleration.y}
else {accel = accelerometerData.acceleration.y}
}
else {
if self.invertTextMotion {accel = -accelerometerData.acceleration.x}
else {accel = accelerometerData.acceleration.x}
}
//Changes default acceleration if allowed
if firstOrientation {
standardAccel=accel
firstOrientation=false
}
accel=accel-standardAccel
//Sets the bounds of the label to prevent nil unwrapping
var minXOffset:CGFloat=0
var maxXOffset=self.baseScrollView.contentSize.width-self.baseScrollView.frame.size.width
//If accel is greater than minimum, and label is not paused begin updates
if !self.pauseScrolling && fabs(accel)>=self.minTiltRequired {
//If the timer has not started, and accel is positive, begin the timer
if !self.timerStarted&&accel<0{
self.stopwatch.start()
self.timerStarted=true
}
//Stores the data, and moves the scrollview depending on acceleration and constant speed
if self.collectData {self.storeIndexAccelValues(accel,timeElapsed: timeElapsed)}
var targetX:CGFloat=self.baseScrollView.contentOffset.x-(CGFloat(accel) * self.speed)
if targetX>maxXOffset {targetX=maxXOffset;self.stopwatch.stop();self.doneWithText=true}
else if targetX<minXOffset {targetX=minXOffset}
self.baseScrollView.setContentOffset(CGPointMake(targetX,0),animated:true)
if self.baseScrollView.contentOffset.x>minXOffset&&self.baseScrollView.contentOffset.x<maxXOffset {
if self.PRIVATEDEBUG {
println(self.baseScrollView.contentOffset)
}
}
}
})
}
}
当它确实崩溃时,它发生在 startScrolling
的末尾,当时我将内容偏移量设置为目标 X。如果您需要更多信息,我很乐意提供,但作为错误发生得如此之少,我没有什么可说的,特别是什么时候发生或类似的事情......它看起来只是随机的。
编辑: 我已将代码简化为仅相关部分,并添加了我调用 NSThread.isMainQueue() 的两个位置。在 startScrolling
的第一行调用时,.isMainQueue() 返回 TRUE,但随后在 motionManager.startAccelerometerUpdatesToQueue
中调用时返回 假的。
为了纠正这个问题,我将 self.queue 从一个 NSOperationQueue() 更改为 NSOperationQueue.mainQueue(),并且在进行此切换之后,第二个 .isMainThread() 调用(在 motionManager.startAccelerometerUpdatesToQueue
) 现在如我们所愿返回 TRUE。
最佳答案
那是很多代码。我在基于 targetX 设置内容偏移量的行中没有看到任何内容。
有两种可能性
baseScrollView 正在被释放并且是一个僵尸(不太可能,因为它看起来像您将其定义为常规(强)实例变量。)
您正在从后台线程调用 startScrolling。如果您从后台线程更新 UI 对象,则一切都将失败。您可以使用 NSThread.isMainThread()
检查它。将该代码放在您的 startScrolling 方法中,如果它返回 false,那就是您的问题。
根据您在下面回复我的回答的评论,您从后台线程调用 startScrolling
。
这确实很可能是问题所在。编辑您的帖子以显示从后台线程调用的代码,包括上下文。 (您的“加速度计更新周期”代码)。
您不能从后台线程操作 UIKit 对象,因此您可能需要将 UIKit 更改包装在“加速度计更新周期”代码中,调用在主线程上运行的 dispatch_async。
您终于发布了足够的信息,以便我们可以帮助您。您的原始代码让您在后台队列中接收加速度计更新。您正在从该代码执行 UIKit 调用。这是一个禁忌,这样做的结果是不确定的。它们的范围从更新持续到永远,到根本没有发生,再到崩溃。
更改代码以使用 NSOperationQueue.mainQueue()
作为处理更新的队列应该可以解决问题。
如果您需要在处理程序中进行耗时的加速度计更新处理,那么您可以继续使用之前使用的后台队列,但将 UIKit 调用包装在 dispatch_async 中:
dispatch_async(dispatch_get_main_queue())
{
//UIKit code here
}
这样,您耗时的加速度计更新代码就不会使主线程陷入困境,但 UI 更新仍会在主线程上完成。
关于ios - Swift Accelerometer 与 ScrollView 不断崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31015306/
如果这不是一个错误,那就是另一个错误。如果不是那样的话,那就是别的东西了。我觉得我的项目已经改变了很多,现在只是试图解决代码签名问题,结果一切都搞砸了。我严格按照说明进行操作,但出现错误,例如当前的“
我不确定是否有一些我不知道的内置变量或规则,或者 make 是否有问题,或者我只是疯了。 对于我的一个项目,我有一个如下的 makefile: CC=g++ CFLAGS=-O3 `libpng-co
我有大约 10 个 div,它们必须不断翻转,每个 div 延迟 3 秒 这个 codrops 链接的最后一个效果是我正在寻找的,但无需单击 div http://tympanus.net/Devel
我如何使用 jQuery 持续运行 PHP 脚本并每秒获取响应,以及将鼠标上的少量数据发送到同一脚本? 我真的必须添加一些随机扩展才能让这么简单的计时器工作吗? 最佳答案 To iterate is
JBoss 4.x EJB 3.0 我见过如下代码(大大简化): @Stateless @TransactionAttribute(TransactionAttributeType.NOT_SUPPO
使用 PHPStorm,我试图忽略每次尝试进行 git 提交时 pop 的 workspace.xml。 我的 .gitignore 看起来像: /.idea/ .idea/workspace.xml
我是一名优秀的程序员,十分优秀!