Я новичок в IOS и Swift, поэтому я начал с портирования примерного кода акселерометра Apple на Swift.Делегат CALayer вызывается только иногда, когда используется Swift
Все это было довольно просто. Поскольку API Accelerometer устарел, я вместо этого использовал Core Motion, и он работает отлично. Я также переключился на раскадровку.
Проблема заключается в том, что делегат моего слоя редко вызывает. Это пойдет на несколько минут и никогда не будет вызвано, а затем его вызовут 40 раз в секунду, а затем вернутся к тому, чтобы его не вызывали. Если я переключаю контекст, делегат будет вызван, и один из подслоев будет отображаться, но есть 32 подслоя, и я еще не видел, чтобы все их рисовали. То, что нарисовано, кажется, все в порядке - проблема заключается в том, что делегат фактически получает вызов, когда я вызываю setNeedsDisplay(), и получаю все подсловы, чтобы нарисовать их.
Я проверял, что каждый подуровень имеет правильные границы и размеры рамки, и я проверил, чтобы удостовериться, что setNeedsDisplay() вызывается после того, как каждая точка акселерометра получена.
Если я прикрепляю инструмент, я вижу, что частота кадров обычно равна нулю, но иногда это будет некоторое большее число.
Я предполагаю, что цикл цикла не работает на велосипеде. На самом деле ничего нет в цикле запуска, и я не уверен, где его поставить. В делегате ViewDidLoad я установил скорость обновления для акселерометра и вызываю функцию, которая обновляет подслои в представлении. Все остальное связано с событиями, поэтому я не знаю, что бы я сделал с циклом запуска.
Я пробовал создавать CALayers и добавлять их в качестве подслоев. Я также попытался сделать класс GraphViewSegment UIView, поэтому он имеет собственный слой.
Версия, написанная в Objective C, работает надежно.
Способ, которым работает это приложение, заключается в том, что значения ускорения отображаются в левой части экрана и прокручиваются вправо. Чтобы сделать его эффективным, новые значения ускорения записываются в небольшой подслой, который содержит график для 32 временных значений. Когда он заполнен, весь подуровень просто перемещается по пикселям за раз вправо, а новый (или переработанный) сегмент занимает свое место в левой части экрана.
Вот код, который движется без изменений сегментов вправо на пиксель:
for s: GraphViewSegment in self.segments {
var position = s.layer.position
position.x += 1.0;
s.layer.position = position;
//s.layer.hidden = false
s.layer.setNeedsDisplay()
}
Я не думаю, что setNeedsDisplay строго необходимо здесь, так как это называется для слоя, когда сегмент слева получает новый сегмент линии.
Вот как добавляются новые слои:
public func addSegment() -> GraphViewSegment {
// Create a new segment and add it to the segments array.
var segment = GraphViewSegment(coder: self.coder)
// We add it at the front of the array because -recycleSegment expects the oldest segment
// to be at the end of the array. As long as we always insert the youngest segment at the front
// this will be true.
self.segments.insert(segment, atIndex: 0)
// this is now a weak reference
// Ensure that newly added segment layers are placed after the text view's layer so that the text view
// always renders above the segment layer.
self.layer.insertSublayer(segment.layer, below: self.text.layer)
// Position it properly (see the comment for kSegmentInitialPosition)
segment.layer.position = kSegmentInitialPosition;
//println("New segment added")
self.layer.setNeedsDisplay()
segment.layer.setNeedsDisplay()
return segment;
}
На данный момент я очень смущен. Я попытался вызвать setNeedsDisplay повсюду, включая принадлежащий UIView. Я попытался сделать UIViews подслоев, и я попытался сделать их не UIViews. Независимо от того, что я делаю, поведение всегда одно и то же.
Все устанавливается в viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
pause.possibleTitles?.setByAddingObjectsFromArray([kLocalizedPause, kLocalizedResume])
isPaused = false
useAdaptive = false
self.changeFilter(LowpassFilter)
var accelerometerQueue = NSOperationQueue()
motionManager.accelerometerUpdateInterval = 1.0/kUpdateFrequency
motionManager.startAccelerometerUpdatesToQueue(accelerometerQueue,
withHandler:
{(accelerometerData: CMAccelerometerData!, error: NSError!) -> Void in
self.accelerometer(accelerometerData)})
unfiltered.isAccessibilityElement = true
unfiltered.accessibilityLabel = "unfiltered graph"
filtered.isAccessibilityElement = true
filtered.accessibilityLabel = "filtered graph"
}
func accelerometer (accelerometerData: CMAccelerometerData!) {
if (!isPaused) {
let acceleration: CMAcceleration = accelerometerData.acceleration
filter.addAcceleration(acceleration)
unfiltered!.addPoint(acceleration.x, y: acceleration.y, z: acceleration.z)
filtered!.addPoint(filter.x, y: filter.y, z: filter.z)
//unfiltered.setNeedsDisplay()
}
}
Любая идея?
Мне очень нравится Swift как язык - он занимает лучшие части Java и C# и добавляет приятный синтаксический сахар. Но это сводит меня с ума! Я уверен, что это кое-что, что я забыл, но я не могу понять, что.
Большое спасибо! – Andromeda
Я потратил пару дней, разрывая волосы на это, но я неправильно предположил, что мой обработчик выполняет в mainThread. Вы сохранили то, что у меня осталось. Теперь я получаю согласованные 60 кадров в секунду. – Andromeda