Завершение работы приложения из-за неисследованного исключения «RLMException», причина: «Объект был удален или признан недействительным». - PullRequest
0 голосов
/ 26 апреля 2019

В моем приложении есть функция покупки в интернет-магазине, использующая платежный адрес. У меня также есть список адресов для выставления счетов, и нажмите на ячейку адреса в списке, чтобы перейти на страницу редактирования адреса. Но после того, как я запустил функцию покупки, отредактировал адрес и вернусь на страницу списка адресов для выставления счетов, приложение перестанет работать. (Если я отредактирую адрес без покупки, все будет хорошо)

Ошибка показывает:

Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'

И

libc++abi.dylib: terminating with uncaught exception of type NSException

А также в AppDelegate.swift ,

"Thread 1: signal SIGABRT" 

Ошибка показа в этой строке:

class AppDelegate: UIResponder, UIApplicationDelegate {

Вот код списка адресов для выставления счетов (который содержит много ячеек с адресами для выставления счетов). Нажмите на ячейку, чтобы перейти к функции редактирования адреса:

import Foundation
import PKHUD

class ManageBillingAddressVC: _BaseViewController {

    @objc var billingAddress: [UserBillingAddress] = [] { //= Address.getAllAddressLists()
        didSet {
            emptyView.isHidden = billingAddress.count != 0
        }
    }

    let viewModel = BillingAddressViewModel()

    @IBOutlet weak var tblBillingAddress: UITableView!
    @IBOutlet weak var emptyView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()

        setUpNavBarWithAttributes(navtitle: "Manage Billing Address", setStatusBarStyle: .default, isTransparent: false, tintColor: .white, titleColor: Color.Tuna.instance(), titleFont: FontBook.AdobePro.navSize(), isBackHidden: false, isShadowIncluded: true, rightBarButton: [showGoldPlusBtn()])

        viewModelCallBack()
        initTableViews()
        observeAdressUpdateNotification()
    }


    @objc func viewModelCallBack() {

        viewModel.beforeApiCall = {
            HUD.show(.systemActivity)
        }

        viewModel.afterApiCall = {
            HUD.hide()
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.navigationController?.setNavigationBarHidden(false, animated: true)

        fetchBillingAddress()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.navigationController?.setNavigationBarHidden(true, animated: true)
    }

    @objc func updateDeliveryAddressTable() {
        fetchBillingAddress()
    }

    @objc func fetchBillingAddress() {
        viewModel.getBillingAddress(success: {
            self.billingAddress.removeAll()
            for address in $0{
                if address.crm_address_order != "postal_address"{
                    self.billingAddress.append(address)
                }
            }
            self.tblBillingAddress.reloadData()
        }) {
            self.showAlert($0)
        }
    }

    @objc func observeAdressUpdateNotification() {
        NotificationCenter.default.addObserver(self, selector: #selector(updateDeliveryAddressTable), name: Constants.billingAddress, object: nil)
    }

    override func rightBarButtonClicked() {

        viewModel.getBillingAddress(success: {
            self.billingAddress.removeAll()
            for address in $0{
                if address.crm_address_order != "postal_address"{
                    self.billingAddress.append(address)
                }
            }

            if self.billingAddress.count >= 3{
                self.showAlert("Addresses are limited to a maximum of 3")
            }else{
                self.pushViewControllerWithSlideUpEffect(vc: UIStoryboard.AddBillingAddress())
            }

            self.tblBillingAddress.reloadData()
        }) {
            self.showAlert($0)
        }
    }

    @objc func initTableViews() {

        tblBillingAddress.register(UINib(nibName : "BillingAddressCell", bundle : nil), forCellReuseIdentifier: "BillingAddressCell")

        tblBillingAddress.dataSource = self
        tblBillingAddress.delegate = self
        tblBillingAddress.separatorStyle = .none
        tblBillingAddress.contentInset = UIEdgeInsetsMake(20, 0, 20, 0)

        tblBillingAddress.rowHeight = UITableViewAutomaticDimension
        tblBillingAddress.estimatedRowHeight = 165 //108

    }

    deinit {
        NotificationCenter.default.removeObserver(self)
    }
}

extension ManageBillingAddressVC: DeliveryAddressCellDelegate {

    @objc func didSelectBillingAddress(address: UserBillingAddress, index: Int) {
        guard let vc = UIStoryboard.AddBillingAddress() as? AddBillingAddressVC else { return }
        vc.billingAddress = address
        pushViewControllerWithSlideUpEffect(vc: vc)
    }
}


extension ManageBillingAddressVC: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return billingAddress.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "BillingAddressCell" ) as! BillingAddressCell
        cell.delegate = self
        cell.billingAddress = billingAddress[indexPath.row]
        //cell.address = billingAddress[indexPath.row]
        return cell

    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: false)
    }

}

Вот моя ячейка платежного адреса в коде списка адресов:

import UIKit

class BillingAddressCell: DeliveryAddresCell {

    @objc var billingAddress: UserBillingAddress? {
        didSet {
            billingAddress.flatMap {
                lblName.text = "\($0.salutation ?? ""). \($0.firstname ?? "") \($0.lastname ?? "")"
                lblAddress.text = $0.street?.first
                lblPhoneNo.text = $0.telephone
                lblUnitNo.text = $0.unit_number
                lblStateCountry.text = "\($0.region?.first?.region ?? ""), \($0.postcode ?? "")"

                if let id = $0.country_id, let countryID = Int(id) {
                    lblCountry.text = CountryList.getCountryName(id: countryID)
                }
            }
        }
    }

    override func btnEditTapped(_ sender: UIButton) {
        delegate?.didSelectBillingAddress(address: billingAddress!, index: tag)
    }

}

Вот функция для получения / обновления адреса выставления счета:

class UserBillingAddress: UserBillingAddressInformation {

    @objc var id : String?
    @objc var customerID: String?

    required convenience init?(map: Map){
        self.init()
    }

    override func mapping(map: Map){
        super.mapping(map: map)
        id <- map["id"]
        customerID <- map["customer_id"]
    }
}

Вот код того, что произошло после нажатия кнопки «Оформить заказ» в процессе покупки:

@IBAction func btnCheckoutTapped(_ sender: UIButton) {

        guard let card = defaultCreditCard, let address = defaultAddress else { return }

        baseViewModel.checkCartLimit(success: { checkLimit in

            if let limitErrors = checkLimit.limit_errors {

                if limitErrors.count > 0 {
                    self.baseViewModel.handleCheckLimitError?(checkLimit)
                } else {

                    guard let processingVC = UIStoryboard.ProcessingOrderVC() as? ProcessingOrderVC else { return }
                    // present processing view
                    processingVC.modalPresentationStyle = .overCurrentContext
                    processingVC.defaultAddress = address
                    processingVC.defaultCreditCard = card
                    processingVC.isSkyDollarPurchaseForMembership = self.isSkyDollarPurchaseForMembership
                    processingVC.isMembershipProduct = self.isMembershipProduct
                    processingVC.isFullSkyDollarPurchase = self.isFullSkyDollarPurchase
                    self.present(processingVC, animated: true)
                }

            } else {

                guard let processingVC = UIStoryboard.ProcessingOrderVC() as? ProcessingOrderVC else { return }
                // present processing view
                processingVC.modalPresentationStyle = .overCurrentContext
                processingVC.defaultAddress = address
                processingVC.defaultCreditCard = card
                processingVC.isSkyDollarPurchaseForMembership = self.isSkyDollarPurchaseForMembership
                processingVC.isMembershipProduct = self.isMembershipProduct
                self.present(processingVC, animated: true)
            }

        }, failure: { (errorMessage) in
            self.showAlert(errorMessage)
        })
    }

А вот код для обработки покупки после нажатия на кнопку оформления заказа:

import UIKit

class ProcessingOrderVC: UIViewController {

    @IBOutlet weak var orderProcessingStackView: UIStackView!
    @IBOutlet weak var orderProcessErrorStackView: UIStackView!

    @IBOutlet weak var btnOkay: UIButton!
    @IBOutlet weak var lblError: UILabel!

    @objc var isMembershipProduct : Bool = false
    @objc var isSkyDollarPurchaseForMembership : Bool = false
    @objc var isFullSkyDollarPurchase: Bool = false

    let checkoutViewModel = CheckoutStep2ViewModel()
    @objc var defaultAddress = Address()
    @objc var defaultCreditCard = CreditCardData()

    override func viewDidLoad() {
        super.viewDidLoad()
        let attributedTitle = NSAttributedString(string: "TRY AGAIN", attributes: [NSAttributedStringKey.kern: 1.3, NSAttributedStringKey.font : FontBook.Bold.of(size: 13.0), NSAttributedStringKey.foregroundColor: UIColor.white])
        btnOkay?.setAttributedTitle(attributedTitle, for: .normal)
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        if isSkyDollarPurchaseForMembership{
            self.checkoutViewModel.placeOrderWithSkyDollarForMembership(address: defaultAddress, success: { orderID in
                (UIStoryboard.CheckoutStep3VC() as? CheckoutStep3VC).flatMap {
                    $0.orderID = orderID
                    $0.hero.modalAnimationType = .fade
                    self.present($0, animated: false, completion: nil)
                }
            }) { (error) in
                self.showError()
            }
        }else{
            self.checkoutViewModel.placeOrder(address: defaultAddress, card: defaultCreditCard, isFullSkyDollarPurchase: isFullSkyDollarPurchase, success: { orderID in
                (UIStoryboard.CheckoutStep3VC() as? CheckoutStep3VC).flatMap {
                    $0.orderID = orderID
                    $0.hero.modalAnimationType = .fade
                    self.present($0, animated: false, completion: nil)
                }
            }) { (error) in
                self.showError()
            }
        }


    }

    @IBAction func btnCloseTapped(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }

    @IBAction func btnOkayTapped(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }

    @objc func showError() {
        orderProcessErrorStackView.isHidden = false
        orderProcessingStackView.isHidden = true
    }

}

Вот переменная defaultAddress и адрес класса:

@objc var defaultAddress = Address()

class Address : Object, Mappable{

    @objc dynamic var id: Int = 0
    @objc dynamic var customerId: Int = 0
    @objc dynamic var region: Region? = nil
    @objc dynamic var region_id: Int = 0
    @objc dynamic var countryId: String = ""
    let streets = List<Street>()
    @objc dynamic var telephone: String = ""
    @objc dynamic var postcode: String = ""
    @objc dynamic var city: String = ""
    @objc dynamic var prefix: String = ""
    @objc dynamic var company: String = ""
    @objc dynamic var firstname: String = ""
    @objc dynamic var lastname: String = ""
    @objc dynamic var defaultShipping: Bool = false
    @objc dynamic var defaultBilling: Bool = false
    var addressAttributes = List<AddressAttributes>()


    required convenience init?(map: Map){
        self.init()
    }

По праву процесс покупки не обновит адрес, но если я не совершу покупку, то при редактировании адреса не возникнет ошибки. Ошибка происходит только после совершения покупки. Я действительно не знаю, что случилось. Кто-нибудь может подсказать в чем может быть проблема?

Я новичок в iOS, поэтому, пожалуйста, уточните, как решить проблему. Большое спасибо!

...