#ios #swift
Вопрос:
Я пытаюсь передать значение gyroX в другую функцию, но оно просто заканчивается тем, что оно имеет значение 0, когда я использую его в качестве гирокса в этой другой функции.
Вот код:
var gyroX = Float()
motion.startGyroUpdates(to: .main) { (data, error) in
if let myData = data {
gyroX = Float(myData.rotationRate.x)
}
}
Комментарии:
1. Закрытие обновления вызывается асинхронно при обновлении значения (что будет происходить очень часто). Вам было бы лучше вызвать функцию, которой требуется значение из замыкания, а не пытаться использовать значение вне замыкания
2. @Paulw11 спасибо.. Я пытался это сделать, но это приводило меня к ошибкам.. Я попробую еще раз, хотя на случай, если я что-то пропустил.. Спасибо
Ответ №1:
С бета-версией Xcode 13 и Swift 5.5
Это проблема, которую мы теперь можем решить с помощью продолжения Async/Await
Сначала мы бы создали функцию, которая преобразует обратный вызов в ожидаемый результат, например:
func getXRotation(from motion: CMMotionManager) async throws -> Float {
try await withCheckedThrowingContinuation { continuation in
class GyroUpdateFailure: Error {} // make error to throw
motion.startGyroUpdates(to: .main) { (data, error) in
if let myData = data {
continuation.resume(returning: Float(myData.rotationRate.x))
} else {
throw GyroUpdateFailure()
}
}
}
}
Затем мы можем назначить переменную и использовать ее следующим образом:
let gyroX = try await getXRotation(from: motion)
callSomeOtherFunction(with: gyroX)
С помощью Xcode
В текущей версии Swift и Xcode мы можем использовать платформу Combine, чтобы немного упростить обработку обратного вызова. Сначала мы преобразуем закрытие из менеджера движения в «Будущее». Тогда мы сможем использовать это будущее в цепочке объединения.
func getXRotation(from motion: CMMotionManager) -> Future<CMGyroData, Error> {
Future { promise in
class GyroUpdateFailure: Error {} // make error to throw
motion.startGyroUpdates(to: .main) { (data, error) in
if let myData = data {
promise(.success(myData))
} else {
promise(.failure(GyroUpdateFailure()))
}
}
}
}
// This is the other function you want to call
func someOtherFunction(_ x: Float) {}
// Then we can use it like so
_ = getXRotation(from: motion)
.eraseToAnyPublisher()
.map { Float($0.rotationRate.x) }
.map(someOtherFunction)
.sink { completion in
switch completion {
case .failure(let error):
print(error.localizedDescription)
default: break
}
} receiveValue: {
print($0)
}
В потоке комбайна есть несколько важных частей. Это _ =
один из них. Результатом «погружения» издателя является «отменяемый» объект. Если мы не сохраним это в локальной переменной, система сможет очистить задачу до ее выполнения. Так что вы наверняка захотите это сделать.
Я настоятельно рекомендую вам оформить заказ SwiftBySundell.com чтобы узнать больше о комбинировании или асинхронности/ожидании и RayWenderlich.com для мобильной разработки в целом.
Комментарии:
1. Ух ты! Большое вам спасибо! Я посмотрю, смогу ли я заставить его работать. Очень признателен!
2. С удовольствием! Дай мне знать, если повесишь трубку.
3. Кстати, с решением xcode 12 вам нужно будет добавить
import Combine
в начало вашего файла.4. Хорошо, я вставил туда комбинацию / XCode 12 и заставил ее работать… как бы я использовал его вне этих функций? Например, я попробовал: «печать(getXRotation(от: движение))», и это дало мне «Объединить. Будущее Ошибка>» вывод.
5. Вы получаете ответ особого рода, который фактически не выполняется до
sink
тех пор, пока не будет вызван. Я бы сделал это в цепочке издателей, как будто.map { print($0); return $0 }
в combine может быть.print()
функция… Хотя ИДК.