我使用swift编写了一些应用程序,我使用用户默认值保存了属性,随着我开始使用更多变量,代码变得有点长。我现在正在开发一个具有6个属性且有100个播放器的播放器类的应用程序,所以不是为用户默认编写600个保存和600个加载行,我想尝试使用CoreData和SQLite来保存数据。 / p>
我开始创建一个较小的概念证明应用程序,以确保我可以为2名玩家保存并加载player.name和player.attack,以保持简单,我遇到了麻烦。我尝试了以下内容:
主视图控制器的示例代码如下
import UIKit
import CoreData
import GameplayKit
var player = Character(context: CoreDataStack.context)
var monster = Character(context: CoreDataStack.context)
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var statsLabel: UILabel!
@IBOutlet weak var playerAttackButton: UIButton!
@IBOutlet weak var playerNameField: UITextField!
@IBOutlet weak var playerHealthButton: UIButton!
@IBOutlet weak var montserAttackButton: UIButton!
@IBOutlet weak var monsterNameField: UITextField!
@IBOutlet weak var monsterHealthButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
if player.name == nil {player.name = ""}
if monster.name == nil {monster.name = ""}
updateStatsLabel()
// Dismiss keyboard on return when typing character name
//Looks for single or multiple taps.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tap)
self.playerNameField.delegate = self
self.monsterNameField.delegate = self
}
// MARK: Fetching Data
func fetchData() -> Void {
let moc = CoreDataStack.context
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Character")
do {
let fetchedPerson = try moc.fetch(fetchRequest) as! [Character]
print(fetchedPerson.count)
for object in fetchedPerson {
player.name = object.name
print(object.name!)
}
} catch {
fatalError("Failed to fetch characters: \(error)")
}
}
// MARK: Delete Data Records
func deleteRecords() -> Void {
let moc = CoreDataStack.context
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Character")
let result = try? moc.fetch(fetchRequest)
let resultData = result as! [Character]
for object in resultData {
moc.delete(object)
}
do {
try moc.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
// MARK: Update Data
func updateRecords() -> Void {
let moc = CoreDataStack.context
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Character")
let result = try? moc.fetch(fetchRequest)
let resultData = result as! [Character]
for object in resultData {
object.name! = player.name!
print(object.name!)
}
do{
try moc.save()
print("saved")
}catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
@IBAction func deleteButton(_ sender: Any) {
deleteRecords()
}
@IBAction func saveButton(_ sender: Any) {
fetchData()
updateRecords()
}
@objc func dismissKeyboard() {
player.name = playerNameField.text!
monster.name = monsterNameField.text!
updateStatsLabel()
//Causes the view (or one of its embedded text fields) to resign the first responder status.
view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}
@IBAction func playerRollAttackButton(_ sender: Any) {
let random = GKRandomSource()
let roll = GKGaussianDistribution(randomSource: random, lowestValue: 1, highestValue: 20)
player.attack = Int64(roll.nextInt())
updateStatsLabel()
}
@IBAction func playerRollHealth(_ sender: Any) {
let random = GKRandomSource()
let roll = GKGaussianDistribution(randomSource: random, lowestValue: 1, highestValue: 8)
player.health = Int64(roll.nextInt())
updateStatsLabel()
}
@IBAction func monsterRollAttackButton(_ sender: Any) {
let random = GKRandomSource()
let roll = GKGaussianDistribution(randomSource: random, lowestValue: 1, highestValue: 12)
monster.attack = Int64(roll.nextInt())
updateStatsLabel()
}
@IBAction func monsterRollHealth(_ sender: Any) {
let random = GKRandomSource()
let roll = GKGaussianDistribution(randomSource: random, lowestValue: 1, highestValue: 20)
monster.health = Int64(roll.nextInt())
updateStatsLabel()
}
func updateStatsLabel() {
statsLabel.text = "\(player.name!) health: \(player.health)\n\n\(player.name!)'s attack: \(player.attack)\n\n\(monster.name!) health: \(monster.health)\n\n\(monster.name!)'s attack: \(monster.attack)"
}
}
对于CoreDataStack视图控制器:
import CoreData
class CoreDataStack {
static let persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "CoreDataSample")
container.loadPersistentStores { (_, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
}
return container
}()
static var context: NSManagedObjectContext { return persistentContainer.viewContext }
class func saveContext () {
let context = persistentContainer.viewContext
guard context.hasChanges else {
return
}
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
我希望我能够为播放器和持有于player.name和monster.name变量的怪物指定一个名称,使用CoreData保存它们,然后将它们加载回变量中app打开下一个(其他变量也一样)。更改名称将导致CoreData模型中的覆盖,使旧数据丢失并被新数据替换。我遇到了以下困难:
任何帮助将不胜感激!感谢您查看我的问题:)