gpt4 book ai didi

ios - Realm <结果> 在函数之外丢失数据

转载 作者:行者123 更新时间:2023-11-29 05:55:54 25 4
gpt4 key购买 nike

我对编码还是新手,并且在使用 Realm Cloud 时遇到了一些问题,无论我如何努力,似乎都无法解决。我正在尝试创建“Click & Collect”订单跟踪器的示例,当 orderState对象属性在1-4之间变化(数字代表不同阶段),它会将UI更改为相应的屏幕。我已订阅 Results<Order> 的 Realm 观察对象,在发生观察和通知的函数中 currentOrder包含正确的Order目的。不过我有一个开关 changes根据观察,调用函数来更新到正确的 UI。在这个被调用的函数中 currentOrder突然没有数据了,currentOrder是在全局范围内定义的,所以我无法理解为什么会发生这种情况。我过滤了Results<Order>只查询匹配的 ID(当通过主键匹配并绕过 Results 时,观察似乎对我根本不起作用)。

我将在这里添加整个 VC,唯一重要的说明是 currentOrderID属性是从之前将对象写入 Realm 的 VC 传递过来的。如果向下滚动直到 func prepareRealm & func changeUIBasedOnStatus这就是问题所在,我还在末尾包含了控制台消息。打印语句结果。

//
// TrackerViewController.swift
// HG Demo
//
// Created by Adam Woodcock on 12/03/2019.
// Copyright © 2019 Adam Woodcock. All rights reserved.
//

import UIKit
import RealmSwift
import Lottie
import MapKit
import CoreLocation

class TrackerViewController: UIViewController {
//Lottie Views
@IBOutlet weak var orderPlacedAnimation: LOTAnimationView!
@IBOutlet weak var orderConfirmedAnimation: LOTAnimationView!
@IBOutlet weak var orderPickedAnimation: LOTAnimationView!
@IBOutlet weak var orderCompleteAnimation: LOTAnimationView!

//Outlets
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var headingLabel: UILabel!
@IBOutlet weak var bodyLabel: UILabel!
@IBOutlet weak var progressImage: UIImageView!


let config = SyncUser.current?.configuration()
var realm : Realm!

var currentOrder : Results<Order>!
var currentOrderID : String!
var subscription : SyncSubscription<Order>!
var subscriptionToken : NotificationToken?
var notificationToken : NotificationToken?

override func viewDidLoad() {
super.viewDidLoad()
realm = try! Realm(configuration: config!)
currentOrder = realm.objects(Order.self).filter("orderID = %@", currentOrderID!)
prepareRealm()
startOrderPlacedAnimation()

}

//Lottie functions
func startOrderPlacedAnimation() {
orderPlacedAnimation.setAnimation(named: "orderPlaced")
orderPlacedAnimation.play()
orderPlacedAnimation.loopAnimation = true
orderConfirmedAnimation.isHidden = true
orderCompleteAnimation.isHidden = true
headingLabel.text = "Thank you! Your order has been placed!"
bodyLabel.text = "Your order has been successfully placed, we'll notify you once this has been accepted!"
progressImage.image = UIImage(named: "singleCheck")
}

func startOrderConfirmedAnimation() {
orderConfirmedAnimation.isHidden = false
orderConfirmedAnimation.setAnimation(named: "undedited")
orderConfirmedAnimation.play()
orderConfirmedAnimation.loopAnimation = true
orderPlacedAnimation.isHidden = true
orderCompleteAnimation.isHidden = true
headingLabel.text = "It's Official! Your order is confirmed!"
bodyLabel.text = "A team member has confirmed your order, we'll start packing soon!"
progressImage.image = UIImage(named: "doubleCheck")
}

func startOrderPickedAnimation() {
orderPickedAnimation.isHidden = false
orderPickedAnimation.setAnimation(named: "orderPicked")
orderPickedAnimation.play()
orderPickedAnimation.loopAnimation = true
orderPlacedAnimation.isHidden = true
orderConfirmedAnimation.isHidden = true
orderCompleteAnimation.isHidden = true
headingLabel.text = "Woosh! Your order is being packed!"
bodyLabel.text = "A team member with extremely steady hands is currently packing your order!"
progressImage.image = UIImage(named: "tripleCheck")

}

func startOrderCompleteAnimation() {
orderCompleteAnimation.isHidden = false
orderCompleteAnimation.setAnimation(named: "orderComplete")
orderCompleteAnimation.play()
orderCompleteAnimation.loopAnimation = true
orderPlacedAnimation.isHidden = true
orderConfirmedAnimation.isHidden = true
orderPickedAnimation.isHidden = true
headingLabel.text = "Woohoo! Your order is ready to collect!"
bodyLabel.text = "We're as excited as you, so what're you waiting for? Come and grab it!"
progressImage.image = UIImage(named: "quadrupleCheck")
}

func startOrderHasBeenCollectedAnimation() {

}

func startErrorWithOrderAnimation() {

}

//Realm functions

//Assigning the current order to the Order object variable
func prepareRealm() {
subscription = currentOrder.subscribe(named: "current-order", limit: nil)
subscriptionToken = subscription.observe(\.state, options: .initial, { (state) in })
notificationToken = currentOrder.observe({ (changes) in
switch changes {
case .initial:
self.changeUIBasedOnStatus(sender: "Initial")
case .update :
self.changeUIBasedOnStatus(sender: "Update")
case .error(let error):
fatalError(error.localizedDescription)
}
})
print("Realm prepared, this is the object: \(currentOrder!)")
titleLabel.text = "\(String(currentOrder.first!.firstName))'s Order #\(currentOrder.first!.orderID!)"
}

func changeUIBasedOnStatus(sender: String) {
print("The switch realm object contains: \(currentOrder!), sender: \(sender)")
switch currentOrder.first!.orderStatus {
case 1:
startOrderPlacedAnimation()
case 2:
startOrderConfirmedAnimation()
case 3:
startOrderPickedAnimation()
case 4:
startOrderCompleteAnimation()
case 5:
startOrderHasBeenCollectedAnimation()
default:
startErrorWithOrderAnimation()
}
}

//IBActions
@IBAction func callUsTapped(_ sender: Any) {
guard let number = URL(string: "tel://+441522684865") else { return }
UIApplication.shared.open(number, options: [:], completionHandler: nil)
}

@IBAction func openingHoursTapped(_ sender: Any) {
}

@IBAction func directionsTapped(_ sender: Any) {
//Creating an action sheet to ask the user whether they'd like to use Apple Maps or Google Maps
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
//Adding the action and functionality to load Apple maps
alert.addAction(UIAlertAction(title: "Apple Maps", style: .default, handler: { (action) in
//Creating a placemark object to pass into the map item
let placemark = MKPlacemark(coordinate: CLLocationCoordinate2DMake(53.203498, -0.611785))
//Initialising a new map item object with the pre-made placemark object
let mapItem = MKMapItem(placemark: placemark)
mapItem.phoneNumber = "+44 (0) 1522 684865"
//Setting the launch options to default to driving directions
let launchOptions = [MKLaunchOptionsDirectionsModeKey:MKLaunchOptionsDirectionsModeDriving]
//Telling the map item object to open that specific location in maps
mapItem.openInMaps(launchOptions: launchOptions)
}))
alert.addAction(UIAlertAction(title: "Google Maps", style: .default, handler: { (action) in
//Add Google maps functionality
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (_) in
alert.dismiss(animated: true, completion: nil)
}))
present(alert, animated: true, completion: nil)
}

}

控制台消息:

2019-03-14 17:00:52.132718+0000 HG Demo[51949:3038807] Sync: Connection[1]: Connected to endpoint '3.121.59.66:443' (from '192.168.0.21:64953')
Realm prepared, this is the object: Results<Order> <0x7fdce8c2d370> (
[0] Order {
firstName = Adam;
lastName = Woodcock;
orderID = 4431295;
timestamp = 2019-03-14 17:00:54 +0000;
orderStatus = 1;
isFulfilled = 0;
}
)
The switch realm object contains: Results<Order> <0x7fdce8c2d370> (

), sender: Initial
(lldb)

fatal error 出现在 changeUIBased... 中的 switch 语句上特别是 switch currentOrder.first!.orderStatus这是它抛出“意外发现 nil...”错误的地方。

我知道这有点啰嗦,所以提前感谢您的帮助。

[编辑]

为了澄清起见,我已从prepareRealm中删除了与 Realm 通知有关的所有代码。函数,我分配 currentOrder[0]到一个名为 thisOrder 的变量使其类型为 Object且不是 Results 类型。然后我打印 thisOrder 的值订单正确打印值的位置。唉,然后我打印 thisOrder在计时器闭包内,它现在打印为[无效对象]。计时器是象征性的,因为每当值 currentOrderthisOrder被传递到 prepareRealm 之外函数或闭包对象变得无效。我已经在不同的应用程序中多次执行此操作,甚至在单独的 VC 上的此应用程序中,它工作 100% 顺利,所以我真的无法理解为什么会发生这种情况。

func prepareRealm() {
realm = try! Realm(configuration: config!)
currentOrder = realm.objects(Order.self).filter("orderID = %@", currentOrderID)
thisOrder = currentOrder[0]
print("This is thisOrder: \(thisOrder!)")

let timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { (timer) in
print(self.thisOrder)
}

}

[编辑2]我将 Realm 更新到最新版本,一切都开始工作了!我认为这是问题的原因,但是我从那时起就继续构建不同的元素和测试等,突然之间,它每次都开始再次这样做,我觉得这可能是 Realm 的问题,所以会向他们提交错误。

最佳答案

这里的问题是,后台发生了很多事情,这些事情可能以不一致的顺序发生,因为它涉及到与服务器的通信。导致问题的一种可能的事件顺序是:

  1. 创建Order本地对象
  2. 写入交易已上传到服务器
  3. View Controller 查询该对象并找到它。
  4. View Controller 在本地创建订阅。
  5. View Controller 记录指示对象存在的消息。
  6. 服务器处理创建对象的写入事务。新创建的对象与服务器知道的任何订阅都不匹配,因此它告诉客户端删除新添加的对象。
  7. 客户端使观察到的对象无效。
  8. 服务器处理新的订阅并告诉客户端恢复对象
  9. 客户端恢复对象,但这不会恢复对其或观察者的无效引用。

如果这些发生的顺序略有不同(例如,服务器碰巧同时处理对象创建和订阅创建),则一切都会正常。

有几个选项可以解决此问题:

  1. 只需遵守 Results<Order>并在 .first 时进行处理是 nil暂时
  2. 在创建对象之前创建该对象的订阅,以便它不会暂时从客户端中删除。
  3. 在 View Controller 中观察订阅并等待它到达 .complete设置对象观察者之前的状态。

关于ios - Realm <结果> 在函数之外丢失数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55168305/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com