【问题标题】:Trying to store data in a class, returning nil when changing view controllers尝试将数据存储在类中,更改视图控制器时返回 nil
【发布时间】:2017-10-27 23:52:44
【问题描述】:

我正在制作一个应用程序,用户可以从 3 个不同的数组中进行选择,这些数组会更改下一页上某些 UI 按钮内的文本。我构建了一个应用程序的粗略演示,将数组硬编码到视图控制器,根本没有真正使用模型。现在我已经从视图控制器中取出所有功能并将其放入一个单独的类cardDatabase

下面是cardDatabase 类。

class cardDatabase {

public func updateCardSelection(cardSet: Int){
    print("updateCardSelection called")
    switch cardSet {
    case 0:
        selectedCardArray = cardSetOne
        selectedCardNum = 0
    case 1:
        selectedCardArray = cardSetTwo
        selectedCardNum = 1
    case 2:
        selectedCardArray = cardSetThree
        selectedCardNum = 2
    default:
        print("Debug Error - Card set not recognised")
    }
    print(selectedCardNum)
}


public var selectedCardNum: Int!
public var selectedCardArray: Array<String>!

//Create arrays for each card dataset
public let cardSetOne = [
    "Word 1",
    "Word 2",
    "Word 3",
    "Word 4",
    "Word 5",
    "Word 6",
    "Word 7",
    "Word 8",
    "Word 9"
]

public let cardSetTwo = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9"
]

public let cardSetThree = [
    "a",
    "b",
    "c",
    "d",
    "e",
    "f",
    "g",
    "h",
    "i"
]

}

如您所见,有 3 个数组填充了不同的单词,它们将显示在另一个屏幕上。我正在努力让我的数据库实际存储任何数据。当我移动到显示数组的屏幕时,我不是直接从数据库中提取信息,而是通过 segue 发送信息。

我设想数据库充当应用程序的模型,控制器可以从模型中提取信息并将其显示在视图中。相反,每次我推送一个新视图时,数据库中的值都会设置为 nil,从而使数据库实际上毫无用处!

下面我已经包含了初始视图的代码。这真的让我很烦,因为我发誓我在以前的应用程序中使用了一个独立的类来存储变量,我从来没有遇到过这个问题!

import Foundation
import UIKit

var firstLoad = true

class MainMenuVC: UIViewController {

var cardEngine: cardDatabase!

override func viewDidLoad() {
    super.viewDidLoad()

    cardEngine = cardDatabase()

    if firstLoad == true {
        cardEngine.selectedCardArray = cardEngine.cardSetOne
        cardEngine.selectedCardNum = 0
        firstLoad = false
    }

    print("selected cardNum = \(cardEngine.selectedCardNum), sender MainMenuVC")
    cardSelector.selectedSegmentIndex = cardEngine.selectedCardNum

}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "Present Card Selection" {
        let destinationVC = (segue.destination as! CardSelectionVC)
        destinationVC.cardList = cardEngine.selectedCardArray
    }
}



@IBOutlet weak var cardSelector: UISegmentedControl!
@IBAction func cardSetSelected(_ sender: UISegmentedControl) {
    cardEngine.updateCardSelection(cardSet: sender.selectedSegmentIndex)
}

}

【问题讨论】:

  • 您能否说明您尝试访问卡数据库的位置,即值为零。我不确定我是否完全理解这个问题。您是从 MainMenuVC 推送视图并始终使用相同的cardEngine,还是每次都以某种方式创建新的 cardDatabases?您包含的代码没有显示

标签: ios swift class


【解决方案1】:

如果您每次加载新视图时都创建一个新的 cardDatabase 实例,它当然会将该 cardDatabase 实例的未初始化变量(selectedCardNum 和 selectedCardArray)设置为 nil。相反,你可以—— 要么将您的 cardDatabase 转换为 Singleton 类,因此只有通过调用 cardDatabase.shared 生成并传递实例,这将保持值可用(因为该实例被保留),如下所示:

class cardDatabase {
     private static var instance : cardDatabase? = nil
     private static var __once: () = {
       instance = cardDatabase()
     }
     class var shared:cardDatabase{
        get{
            _ = cardDatabase.__once
            return instance!
        }
     }
     //Add your vars and functions below
}

-- 或者,如果您不关心继承,请将所有内容设为静态,这样您就不需要创建 cardDatabase 的任何实例,并且它们的值将保留在类级别(cardDatabase.selectedCardArray、cardDatabase.selectedCardNum),例如这个:

class cardDatabase {

  public static func updateCardSelection(cardSet: Int){
      print("updateCardSelection called")
      switch cardSet {
      case 0:
        selectedCardArray = cardSetOne
        selectedCardNum = 0
      case 1:
        selectedCardArray = cardSetTwo
        selectedCardNum = 1
     case 2:
        selectedCardArray = cardSetThree
        selectedCardNum = 2
    default:
     print("Debug Error - Card set not recognised")
   }
   print(selectedCardNum)
 }


 public static var selectedCardNum: Int!
 public static var selectedCardArray: Array<String>!

//Create arrays for each card dataset
 public static let cardSetOne = [
    "Word 1",
    "Word 2",
    "Word 3",
    "Word 4",
    "Word 5",
    "Word 6",
    "Word 7",
    "Word 8",
    "Word 9"
  ]

 public static let cardSetTwo = [
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9"
  ]

 public static let cardSetThree = [
    "a",
    "b",
    "c",
    "d",
    "e",
    "f",
    "g",
    "h",
    "i"
  ]
}

【讨论】:

  • 谢谢,当我添加共享的东西时它工作了,而且一切正常。这样做我有点困惑,为了澄清当我设置cardEngine = cardDatabase() 我正在创建一个全新的类实例?我在我的第一个应用程序中使用了这样的类,实际上我在全局声明了该类var className: classType!,并在第一次加载className = classType() 时对其进行了初始化。我听说过很多关于全局变量是个坏主意的说法,在这种情况下是不是很糟糕?这样我就不需要将代码添加到我不太了解的cardDatabase 类中?干杯!
  • @Axemasta 是的,当您设置cardEngine = cardDatabase() 时,您正在创建该类的新实例。它与全局或本地变量无关。它更多地是关于保留(或保留其状态)您向其中添加值并传递它的实例,以便您可以访问之前设置的值。除了我提到的两种方法之外,我能想到的唯一其他方法:如果您的 MainMenuVC 实例在您想要访问 cardDatabase 的任何地方都可以访问(并且状态保留),那么您可以访问它的属性 cardEngine 以及它的变量。跨度>
  • 好的,谢谢你清理它。我实际上并没有意识到我正在创建新实例,因此我为什么会感到困惑,因为我之前没有遇到过这个错误。我已经阅读了单例课程,现在我明白了我们为什么要制作它们。我实际上以为我正在创建一个供所有人阅读的类,而不是初始化同一个类 3 次!干杯
  • @Axemasta 当然。如果您认为答案正确,请采纳:)
  • 没想到我能做到:p,我现在接受了!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-30
  • 2018-08-06
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
相关资源
最近更新 更多