I'm just starting to learn to work with Core Data in Swift 3. I am trying to save and retrieve some variables for a basic game to learn, however every time it saves/retrieves it creates an additional value. Now i'm up to 75 entries, each with a set of the variables. I'd like to have 1 that i can work with. Is there a way to keep the total to 1 (delete the old before new one saved).
Or is there a better way to data handle between viewControllers?
Thanks.
func retrieveCoreData() {
// let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Variables")
request.returnsObjectsAsFaults = false
do
{
let results = try context.fetch(request)
if results.count > 0 {
for result in results as! [NSManagedObject]
{
atHome = result.value(forKey: "atHome") as! Int
playerGold = result.value(forKey: "playerGold") as! Int
battleBoss = result.value(forKey: "battleBoss") as! Bool
enemyAttack = result.value(forKey: "enemyAttack") as! Int
enemyDefense = result.value(forKey: "enemyDefense") as! Int
enemyHealth = result.value(forKey: "enemyHealth") as! Int
enemyHealthMax = result.value(forKey: "enemyHealthMax") as! Int
inBattle = result.value(forKey: "inBattle") as! Bool
playerAttack = result.value(forKey: "playerAttack") as! Int
playerDefense = result.value(forKey: "playerDefense") as! Int
playerGold = result.value(forKey: "playerGold") as! Int
playerHealth = result.value(forKey: "playerHealth") as! Int
playerLevel = result.value(forKey: "playerLevel") as! Int
playerLevelUpgradeValue = result.value(forKey: "playerLevelUpgradeValue") as! Int
}
}
}
catch {
fatalError("Failed to recover CoreData: \(error)")
}
}
Here is a list of the values printed: (note "p12")
<Variables: 0x1466d150> (entity: Variables; id: 0x14644960 <x-coredata://2E613846-F77C-4492-B27E-5A79AEC58949/Variables/p12> ; data: {
atHome = 1;
battleBoss = 0;
enemyAttack = 1;
enemyDefense = 1;
enemyHealth = 1;
enemyHealthMax = 1;
inBattle = 0;
playerAttack = 6;
playerDefense = 3;
playerGold = 0;
playerHealth = 200;
playerHealthMax = 0;
playerLevel = 1;
playerLevelUpgradeValue = 350;
})
Related
I am trying to call 2 different core data strings and place them each on separate labels. Right now I am getting the error Cannot invoke initializer for type 'init(_:)' with an argument list of type '([NSManagedObject])'. This error is coming from j1.text = String(itemsName). I added both view controllers for saving and displaying.
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet var j1 : UITextField!
#IBOutlet var j2 : UITextField!
#IBAction func save(){
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Team", in : context)!
let theTitle = NSManagedObject(entity: entity, insertInto: context)
theTitle.setValue(j1.text, forKey: "score")
theTitle.setValue(j2.text, forKey: "alba")
do {
try context.save()
}
catch {
print("Tom Corley")
}
}}
class twoVC: UIViewController {
#IBOutlet var j1 : UILabel!
#IBOutlet var j2 : UILabel!
var itemsName : [NSManagedObject] = []
var itemsName2 : [NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let appD = UIApplication.shared.delegate as! AppDelegate
let context = appD.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Team")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "score", ascending: true)]
let fetchRequest2 = NSFetchRequest<NSManagedObject>(entityName: "Team")
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "alba", ascending: true)]
do {
itemsName = try context.fetch(fetchRequest)
itemsName2 = try context.fetch(fetchRequest2)
if let score = itemsName[0].value(forKey: "score") {
j1.text = (score as! String)
}
if let alba = itemsName2[0].value(forKey: "alba") {
j2.text = (alba as? String)
}
}catch {
print("Ashley Tisdale")
}
}}
Loop over the result from the fetch and append to a string that is then used as value for the label, this goes inside the do{...} where you do the fetch today. Note that I am only using one fetch request here.
itemsName = try context.fetch(fetchRequest)
var mergedScore: String = ""
var mergedAlba: String = ""
for item in itemsName {
if let score = item.value(forKey: "score") as? String {
mergedScore.append(score)
mergedScore.append(" ") //separator
}
if let alba = item.value(forKey: "alba") as? String {
mergedScore.append(alba)
mergedScore.append(" ") //separator
}
}
j1.text = mergedScore
j2.text = mergedAlba
Try this one it's Working for me Swift 4 I think You need to store the value as int which are used as sortDescriptor.
func FetchManagedObjectFromDatabaseForStoreData(Entity :NSEntityDescription) ->
[NSManagedObject]
{
let fetchRequest = NSFetchRequest<NSFetchRequestResult>()
// Add Sort Descriptor
let sortDescriptor = NSSortDescriptor(key: "order", ascending: true)
let sortDescriptor1 = NSSortDescriptor(key: "is_favourite", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor,sortDescriptor1]
// Create Entity Description
fetchRequest.entity = Entity
let result : [NSManagedObject] = []
// Execute Fetch Request
do{
let result = try appDelegate.managedObjectContext.fetch(fetchRequest) as! [NSManagedObject]
if result.count > 0
{
return result
}
else
{
// return result
}
}
catch{
let fetchError = error as NSError
print(fetchError)
}
return result
}
For Fetch Data
// Create Entity Description
let entityDescription = NSEntityDescription.entity(forEntityName: "Your Entity Name Here", in: appDel.managedObjectContext)
let DataObject = FetchManagedObjectFromDatabaseForStoreData(Entity: entityDescription!)
//Convert Array of NSManagedObject into array of [String:AnyObject]
for item in DataObject{
let keys = Array(item.entity.attributesByName.keys)
// Here is your result
print((item.dictionaryWithValues(forKeys: keys) as NSDictionary).value(forKey: "id") as Any) // And so On Whatewer you Fetch
}
I am trying to re-use a code from swift 7.3. I feel I am very close.
When I try the code on the simulator, the picker view it is empty, but when I try to use it I have only one data show up.
I also try to adapt and other code to load data from core data to it, didn't work.
Any Idea?
Thank you
import CoreData
class ViewController: UIViewController, UIPickerViewDelegate, UIImagePickerControllerDelegate {
#IBOutlet weak var TextField: UITextField!
#IBOutlet weak var stylePicker: UIPickerView!
var styleData = [PilotBase]()
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "PilotBase")
do {
styleData = try context.fetch(fetchRequest) as! [PilotBase]
} catch let err as NSError {
print(err.debugDescription)
}
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "PilotBase")
request.returnsObjectsAsFaults = false
do{
let result = try context.fetch(request)
for data in result as! [NSManagedObject]{
print(data.value(forKey: "name") as! String)
}
}catch{
print("Failed")
}
}
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == 0 {
return styleData.count
} else {
return 0
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == 0 {
return styleData[row].name
} else {
return nil
}
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
print(styleData[row])
stylePicker.selectRow(row, inComponent: 0, animated: true)
TextField.text = styleData[row].name
}
}
Below the code to add data to Core Data.
#IBAction func Save(_ sender: Any) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "PilotBase", in: context)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
newUser.setValue(TextField.text!, forKey: "name")
do{
try context.save()
}catch{
print("failed saving")
}
}
I am parsing large kml file(18 MB) using NSXMLParser and simultaneously storing coordinates of every place in core data, what i am observing is memory is not being released after parsing 3/4th of the file memory piles up and application crashes, i have tried most of the answers given on stackoverflow but were not useful. Any help is mostly welcomed.
var currentElement : String = ""
var place:Place?
var polygon:Polygon?
var placeName = ""
var shouldAddCoordinates = false
private lazy var privateManagedObjectContext: NSManagedObjectContext = {
var managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext.persistentStoreCoordinator
return managedObjectContext
}()
override init() {
super.init()
}
// Xml Parser delegate methods
func parserDidStartDocument(_ parser: XMLParser) {
print("..Xml parsing has started")
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
currentElement = elementName
if elementName == "Placemark" {
place = NSEntityDescription.insertNewObject(forEntityName: "Place", into: privateManagedObjectContext) as? Place
place?.placeName = ""
}
if elementName == "Polygon" {
polygon = NSEntityDescription.insertNewObject(forEntityName: "Polygon", into: privateManagedObjectContext) as? Polygon
let fetchRequest = NSFetchRequest<Place>(entityName: "Place")
fetchRequest.predicate = NSPredicate(format: "placeName == %#", placeName)
do{
let fetchResult = try privateManagedObjectContext.fetch(fetchRequest) as [Place]
polygon?.place = place
polygon?.placeName = placeName
shouldAddCoordinates = fetchResult.first?.placeName == placeName ? true:false
}
catch{}
}
if elementName == "coordinates" {
let fetchRequest = NSFetchRequest<Place>(entityName: "Place")
fetchRequest.predicate = NSPredicate(format: "placeName == %#", placeName)
let fetchResult = try? privateManagedObjectContext.fetch(fetchRequest) as [Place]
shouldAddCoordinates = fetchResult?.first?.placeName == placeName ? true:false
}
if elementName == "name"{
placeName = ""
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
currentElement = elementName
if elementName == "coordinates" {
let fetchRequest = NSFetchRequest<Place>(entityName: "Polygon")
let sortDescriptor = NSSortDescriptor(key: "polygonID", ascending: true )
fetchRequest.sortDescriptors = [sortDescriptor]
let fetchResult = try? privateManagedObjectContext.fetch(fetchRequest as! NSFetchRequest<NSFetchRequestResult>) as! [Polygon]
if fetchResult?.count == 0{
polygon?.polygonID = 1
}
else{
polygon?.polygonID = Int64(fetchResult!.count)
}
polygon?.place = place
}
if elementName == "coordinates" || elementName == "Polygon" || elementName == "name"{
if self.privateManagedObjectContext.hasChanges{
privateManagedObjectContext.performAndWait {
do{
try self.privateManagedObjectContext.save()
}
catch{}
}
}
}
else if elementName == "Placemark"{
placeName = ""
privateManagedObjectContext.performAndWait {
do{
try self.privateManagedObjectContext.save()
}
catch{}
}
privateManagedObjectContext.reset()
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
if currentElement == "name" {
if string == "\n" {
return
}
place?.placeName? += string
placeName += string
}
if currentElement == "coordinates"{
if shouldAddCoordinates {
privateManagedObjectContext.performAndWait{
if string == "\n" {
return
}
else{
let coordinates = NSEntityDescription.insertNewObject(forEntityName: "Coordinates", into: self.privateManagedObjectContext) as! Coordinates
let longitude = (string.components(separatedBy: ",") as [NSString]).first!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) as NSString
let latitude = (string.components(separatedBy: ",") as [NSString]).last!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) as NSString
let latitudeDegrees : CLLocationDegrees = latitude.doubleValue
let longitudeDegrees: CLLocationDegrees = longitude.doubleValue
coordinates.latitude = latitudeDegrees as NSNumber?
coordinates.longitude = longitudeDegrees as NSNumber?
coordinates.coordinatesDate = Date() as NSDate
coordinates.polygon = self.polygon
print("\(String(describing: coordinates.polygon?.placeName!)) has coordinates \(coordinates.latitude!),\(coordinates.longitude!)")
}
}
}
}
}
func parserDidEndDocument(_ parser: XMLParser) {
print("..Parser has finished parsing..")
}
func getManagedObject() -> NSManagedObjectContext{
let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
return managedObjectContext
}
func saveCoordinates(){
let url = Bundle.main.url(forResource: "IND_adm1_1", withExtension: "kml")
let xmlParser = XMLParser(contentsOf: url!)
xmlParser?.delegate = self
_ = xmlParser?.parse()
}
I am using Xcode 8 with Swift 3
Core Data setting all the attributes to nil for first time on load with no relationships.
Here is the screenshot.
In Console, i am getting this if App is installed for first time. I have deleted and try to run & install from Xcode number of times. Every time it sets all the values to nil.
"author_id" = nil;
"channel_id" = 0;
"created_at" = nil;
desc = nil;
id = 0;
images = nil;
"is_approved" = 0;
"is_bookmarks" = 0;
"is_like" = 0;
"is_wired" = 0;
"like_count" = 0;
link = nil;
"meta_des" = nil;
"post_id" = 0;
pubDate = nil;
"publisher_id" = 0;
"rss_url" = nil;
"share_cat" = nil;
"share_title" = nil;
"tiny_url" = nil;
title = nil;
"title_tag" = nil;
type = nil;
"updated_at" = nil;
url = nil;
Don't understand whats happening there. Anyone has any idea or hint what am i doing wrong or missing here. And this is only happening for "NewsPost" Entity.
Here is the code where i am adding data to core data.
func addData(entityName: String, entityValues: Any) {
var contextt = NSManagedObjectContext()
if #available(iOS 10.0, *) {
contextt = self.persistentContainer.viewContext
} else {
contextt = self.managedObjectContext
}
/// add data
switch entityName {
case EntityName.NewsEntity:
let singlePost = entityValues as! NSDictionary
let id = singlePost.value(forKey: "id") as! NSNumber
let title = singlePost.value(forKey: "title") as! String
let description = singlePost.value(forKey: "description") as! String
let link = singlePost.value(forKey: "link") as! String
let url = singlePost.value(forKey: "url") as! String
let is_approved = singlePost.value(forKey: "is_approved") as! NSNumber
let meta_des = singlePost.value(forKey: "meta_des") as! String
let title_tag = singlePost.value(forKey: "title_tag") as! String
let share_cat = singlePost.value(forKey: "share_cat") as! String
let author_id = singlePost.value(forKey: "author_id") as! String
let type = singlePost.value(forKey: "type") as! String
let publisher_id = singlePost.value(forKey: "publisher_id") as! NSNumber
let channel_id = singlePost.value(forKey: "channel_id")
let share_title = singlePost.value(forKey: "share_title") as! String
let rss_url = singlePost.value(forKey: "rss_url")
let pubDate = singlePost.value(forKey: "pubDate") as! String
let created_at = singlePost.value(forKey: "created_at") as! String
let updated_at = singlePost.value(forKey: "updated_at") as! String
let like_count = singlePost.value(forKey: "like_count") as! NSNumber
let tiny_url = singlePost.value(forKey: "tiny_url") as! String
let publisher = singlePost.value(forKey: "publisher") as! NSDictionary
let pubName = publisher.value(forKey: "name") as! String
let post = NSEntityDescription.insertNewObject(forEntityName: "NewsPost", into: contextt) as! NewsPost
post.id = Int64(id)
post.title = title
post.desc = description
post.link = link
post.url = url
post.is_approved = Int16(is_approved)
post.meta_des = meta_des
post.title_tag = title_tag
post.share_cat = share_cat
post.author_id = author_id
post.type = type
post.publisher_id = Int64(publisher_id)
post.channel_id = (channel_id as? Int64) ?? 0
post.share_title = share_title
post.rss_url = rss_url as? String ?? ""
post.pubDate = pubDate
post.created_at = created_at
post.updated_at = updated_at
post.like_count = Int64(like_count)
post.tiny_url = tiny_url
let images = singlePost.value(forKey: "images") as! NSArray
do {
let data = try JSONSerialization.data(withJSONObject: images, options: .prettyPrinted)
let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
post.images = string as? String
} catch {
}
print("post data -\(post.managedObjectContext)")
break
case EntityName.Categories:
entity.setValue(entityValues[0], forKey: EntityName.Entities.catName)
break
default:
break
}
/// we save our entity
do {
try contextt.save()
} catch {
fatalError("Failure to save context: \(error)")
}
}
This is how i am fetching data from Core Data.
func fetchData(entityToFetch: String, completion: #escaping (_ result: [NSManagedObject]?)->()) {
var context = NSManagedObjectContext()
if #available(iOS 10.0, *) {
context = CoreDataStack().persistentContainer.viewContext
} else {
context = DataController().managedObjectContext
}
// Fetching core data
let request = NSFetchRequest<NSFetchRequestResult>(entityName: entityToFetch)
request.returnsObjectsAsFaults = false
do {
let results = try context.fetch(request)
print("fetch results- \(results as! [NSManagedObject])")
if results.count > 0 {
completion(results as? [NSManagedObject])
} else {
completion(nil)
}
} catch let error {
completion(nil)
print("fetch error -\(error.localizedDescription)")
}
}
Thank in advance.
i successfully saved the array of images as nsdata in coredata.
MY Question is - how can i check if there is an image exists at particular index(2) or not ??
Here is my code for retrieving data
var tableImageArray = NSData
func ShowCoreData(){
// core data - show
let appDel:AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
let context:NSManagedObjectContext = appDel.managedObjectContext
var request = NSFetchRequest(entityName: "SavedIdea")
request.returnsObjectsAsFaults = false;
do {
var result:NSArray = try context.executeFetchRequest(request)
if (result.count > 0) {
self.tableTitleArray = result.valueForKey("heading") as! [String]
print(tableTitleArray)
self.tableDetailArray = result.valueForKey("detail") as! [String]
self.tableTypeArray = result.valueForKey("type") as! [String]
self.tableHoursArray = result.valueForKey("time") as! [String]
self.tableImageArray = result.valueForKey("image") as! [NSData]
// print(" image array nsdata -- \(tableImageArray)")
}else{
// print("0 result appear....error")
}
tableView.reloadData()
}catch {
let fetchError = ("returned error is \(error as! NSError)")
print(fetchError)
}
}
I got the whole array as NSdata in tableImageArray Then Suppose there is no image or value at index 2 but index 1,3 of tableImageArray have values. This is giving me BAD_Exc error at this line -
if tableImageArray[indexPath.row].length > 0 whenever no image found
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell")! as! OTPTableViewCell
cell.LabelTitle.text = tableTitleArray[indexPath.row]
cell.LabelDetail.text = tableDetailArray[indexPath.row]
cell.LabelType.text = tableTypeArray[indexPath.row]
cell.LabelHours.text = String(tableHoursArray[indexPath.row])
// print(tableImageArray[indexPath.row])
if tableImageArray[indexPath.row].length > 0 {
cell.ImgView.image = UIImage(data: tableImageArray[indexPath.row])//(named: tableImageArray[indexPath.row])
}else{
cell.imageWidthConstraints.constant = 0
}
return cell
}