iOS Optional wrapping in Swift - ios

I'm saving an array into a model, when saving the data is not wrapped with Optional (...) however when the data is being read I get the Optional(...) wrapping around it.
Appreciate your help.
saveOperativesInModel: Test Name
saveOperativesInModel: test team 999
getOperativesFromModel: Optional(Test Name)
getOperativesFromModel: Optional(test team 999)
func saveOperativesInModel() {
if (self.operativesResult?.operativesList.count > 0) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("Operatives", inManagedObjectContext: managedContext)
// Remove all records in entity
let fetchRequest = NSFetchRequest()
fetchRequest.entity = entity
fetchRequest.includesPropertyValues = false
var error:NSError?
if let results = managedContext.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject] {
for result in results {
managedContext.deleteObject(result)
}
}
var item: NSManagedObject!
//var itemInArray: Operative!
if let operativesList = self.operativesResult?.operativesList {
self.operativesTable.removeAll()
for itemInArray in operativesList {
item = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)
item.setValue(itemInArray.id, forKey: "id")
item.setValue(itemInArray.firstName, forKey: "firstName")
item.setValue(itemInArray.lastName, forKey: "lastName")
item.setValue(itemInArray.mobile, forKey: "mobile")
var error: NSError?
if !managedContext.save(&error) {
println("saveOperativesInModel - Could not save \(error), \(error?.userInfo)")
} else {
self.operativesTable.append(item!)
println("saveOperativesInModel: \(itemInArray.firstName)")
}
}
}
//println("saveOperativesInModel : \(operativesTable.count) items")
let fetchRequest1: NSFetchRequest! = NSFetchRequest(entityName:"Operatives")
var error1: NSError?
let fetchedResults = managedContext.executeFetchRequest(fetchRequest1, error: &error1) as? [NSManagedObject]
if let operativesTable = fetchedResults {
if operativesTable.count > 0 {
println("getOperativesFromModel : \(operativesTable.count)")
}
if operativesTable.count > 0 {
for item in operativesTable {
let operative: Operative! = Operative()
operative.id = String (stringInterpolationSegment: item.valueForKey("id"))
operative.firstName = String (stringInterpolationSegment: item.valueForKey("firstName"))
operative.lastName = String (stringInterpolationSegment: item.valueForKey("lastName"))
println("getOperativesFromModel: \(operative.firstName)")
}
}
} else {
println("Could not fetch \(error1), \(error1!.userInfo)")
}
}
}

The firstName attribute from Operative class should be an optional (probably declared like this var firstName: String?. So if you're sure you have a string inside firstName, you can replace your print line with this:
println("getOperativesFromModel: \(operative.firstName!)")

Related

How can you get attribute names from an Entity from CoreData at an iOS app

I am reading data with following code from CoreData but instead of that can we read first attribute names "firstName", "lastName", "age" from CoreData into an array and read their values instead of writing all the names in code.
It is repeated work because they are written in DataModel as well.
loadData() {
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Entity")
do {
let result = try context.fetch(fetchRequest)
dump(result)
for data in result as! [NSManagedObject] {
fNames = data.value(forKey: "firstName") as! String
lNames = data.value(forKey: "lastName") as! String
age = data.value(forKey: "age") as! Int
print("first \(fNames), last : \(lNames), last : \(age)")
}
} catch {
print("Could not load data: \(error.localizedDescription)")
}
}
Use the class that Xcode has generated for you that has the same name as the entity name
loadData() {
//Declare fetch request to hold the class you want to fetch
let fetchRequest = NSFetchRequest<Entity>(entityName: "Entity")
do {
let result = try context.fetch(fetchRequest)
dump(result)
for data in result {
// result is now [Entity] so you can access properties directly
// and without casting
let firstName = data.firstName
let lastName = data.lastName
let age = data.age
print("first \(firstName), last : \(lastName), age : \(age)")
}
} catch let error as NSError {
print("Could not load data: \(error.localizedDescription)")
}
}
Try this, access your entity name from NSManagedObject
e.g.
For AppDelegate.SharedInstance(), just declare this func in AppDelegate.swift
class func sharedInstance() -> AppDelegate
{
return UIApplication.shared.delegate as! AppDelegate
}
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"CallHistory") //Here CallHistory is my entity name which i can access as NSManagedObject
let arr_callhistory = try AppDelegate.sharedInstance().persistentContainer.viewContext.fetch(fetchRequest) as! [CallHistory]
if arr_callhistory.count != 0
{
for callhistory_dict in arr_callhistory
{
let callStatus = callhistory_dict.callStatus
}
}

sort coreData fetch (swift4)

Right now my code is using NSPredicate or sort descriptor to basically just collect a name. I would like NSPredicate to sort all of the names from a-z thats it.
COREDATAHANDLER
class coreDataHandler: NSObject {
private class func getContext() -> NSManagedObjectContext{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
class func saveObject(username:String, password:String) -> Bool{
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(username, forKey: "username")
managedObject.setValue(password, forKey: "password")
do {
try context.save()
return true
} catch {
return false}
}
class func filterData() -> [User]? {
let conttext = getContext()
let fetchRequest:NSFetchRequest<User> = User.fetchRequest()
var user:[User]? = nil
var predicate = NSPredicate(format: "username contains[d] %#" ,"duke")
fetchRequest.predicate = predicate
do {
user = try conttext.fetch(fetchRequest)
return user
}catch {
return user
}
}
VIEWCONTROLLER
user = coreDataHandler.filterData()
for i in user! {
print("Judou : \(i.username!)")
}
If you want your user array to be sorted by username and then password, I would add a class function to your CoreDataHandler class to get a sorted array:
class func getSortedData() -> [User]? {
let conttext = getContext()
let fetchRequest:NSFetchRequest<User> = User.fetchRequest()
var user:[User]? = nil
var nameSort = NSSortDescriptor(key:"username", ascending:true)
var passwordSort = NSSortDescriptor(key:"password", ascending:false)
fetchRequest.sortDescriptors = [nameSort, passwordSort]
do {
user = try conttext.fetch(fetchRequest)
return user
} catch {
return user
}
}
Then in your view controller, use this new function to get the sorted array:
user = coreDataHandler.getSortedData()
for i in user! {
print("Judou : \(i.username!), Password:\(i.password)")
}
In swift 4 or swift 5, you can use
func sortlist(){
//1
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "User")
let sort = NSSortDescriptor(key: "username", ascending: false)
fetchRequest.sortDescriptors = [sort]
//3
do {
let langugeCodes = try managedContext.fetch(fetchRequest)
for result in langugeCodes as [NSManagedObject] {
var username:String = result.value(forKey: "username")! as! String
var password:String = result.value(forKey: "password")! as! String
print("username==>",username)
print("name==>",name)
}
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}

Syncing parse data with coredata, how do I figure out which objects to delete?

I have successfully written the code to download the parse objects, fetch the current objects in my database and then compare.
My algorithm:
I iterate through the parse objects and run a fetchrequest and compare their objectID's. If I get nothing, I make a new object for my database. Otherwise I then look at the modifiedDate I have in my database and the updatedAt from parse and compare to see if I need to set new values. This code works great.
The code:
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
let object = object as! PFObject
let name = object["name"] as! String
let email = object["email"] as! String
let subjectsTaught = object["subjectsTaught"] as [String: String]
let category = object["category"] as! String
let uniqueID = object.objectId!
let modifiedDate = object.updatedAt!
let fetchRequest2 = NSFetchRequest(entityName: "Teacher")
fetchRequest2.predicate = NSPredicate(format: "uniqueID == %#", uniqueID)
var error2: NSError?
if let foundTeachers = self.managedObjectContext.executeFetchRequest(fetchRequest2, error: &error2) as? [Teacher] {
if foundTeachers.isEmpty == true {
let teacher = NSEntityDescription.insertNewObjectForEntityForName("Teacher", inManagedObjectContext: self.managedObjectContext) as! Teacher
teacher.name = name
teacher.email = email
teacher.subjectsTaught = subjectsTaught
teacher.category = category
teacher.uniqueID = uniqueID
teacher.modifiedDate = modifiedDate
} else {
if let teacher = foundTeachers.first {
let date1 = teacher.modifiedDate
let date2 = modifiedDate
let compareResult = date1.compare(date2)
if compareResult == NSComparisonResult.OrderedAscending {
teacher.setValue(name, forKey: "name")
teacher.setValue(email, forKey: "email")
teacher.setValue(subjectsTaught, forKey: "subjectsTaught")
teacher.setValue(category, forKey: "category")
teacher.setValue(modifiedDate, forKey: "modifiedDate")
}
}
}
}
var error: NSError?
if !self.managedObjectContext.save(&error) {
println("Error \(error)")
abort()
}
}
}
My question is how should I figure out which objects where not in parse? I don't want to query parse for every object in my database as I assume that would be network intensive.
Should I do a fetchrequest for all Teacher objects in the beginning and as I iterate through the parse objects, delete them as I go? If I have objects left, those should be deleted?
Okay, I figured out what to do. I ended up running a fetchrequest first for all teacher and appending their names to an array. During the parse iteration, I deleted teachers from that list as I went through them and at the end, used that list to delete teachers from the database.
let fetchRequest = NSFetchRequest()
fetchRequest.entity = NSEntityDescription.entityForName("Teacher", inManagedObjectContext: self.managedObjectContext)
var error: NSError?
var foundTeacherNames = [String]()
if let foundTeachers = self.managedObjectContext.executeFetchRequest(fetchRequest, error: &error) as? [Teacher] {
for teacher in foundTeachers {
foundTeacherNames.append(teacher.name)
}
}
//Find teachers in parse database
let query = PFQuery(className: "TeacherList")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
if let objects = objects {
for object in objects {
let object = object as! PFObject
let name = object["name"] as! String
let email = object["email"] as! String
let subjectsTaught = object["subjectsTaught"] as! [String: String]
let category = object["category"] as! String
let uniqueID = object.objectId!
let modifiedDate = object.updatedAt!
let fetchRequest2 = NSFetchRequest(entityName: "Teacher")
fetchRequest2.predicate = NSPredicate(format: "uniqueID == %#", uniqueID)
var error2: NSError?
if let foundTeachers = self.managedObjectContext.executeFetchRequest(fetchRequest2, error: &error2) as? [Teacher] {
if foundTeachers.isEmpty == true {
let teacher = NSEntityDescription.insertNewObjectForEntityForName("Teacher", inManagedObjectContext: self.managedObjectContext) as! Teacher
teacher.name = name
teacher.email = email
teacher.subjectsTaught = subjectsTaught
teacher.category = category
teacher.uniqueID = uniqueID
teacher.modifiedDate = modifiedDate
} else {
if let teacher = foundTeachers.first {
let date1 = teacher.modifiedDate
let date2 = modifiedDate
let compareResult = date1.compare(date2)
if compareResult == NSComparisonResult.OrderedAscending {
teacher.setValue(name, forKey: "name")
teacher.setValue(email, forKey: "email")
teacher.setValue(subjectsTaught, forKey: "subjectsTaught")
teacher.setValue(category, forKey: "category")
teacher.setValue(modifiedDate, forKey: "modifiedDate")
}
}
}
if contains(foundTeacherNames, name) {
let i = find(foundTeacherNames, name)!
foundTeacherNames.removeAtIndex(i)
}
}
var error: NSError?
if !self.managedObjectContext.save(&error) {
println("Error \(error)")
abort()
}
if !foundTeacherNames.isEmpty {
for teacher in foundTeacherNames {
let request = NSFetchRequest(entityName: "Teacher")
request.predicate = NSPredicate(format: "name = %#", teacher)
if let fetchResults = self.managedObjectContext.executeFetchRequest(request, error: nil) as? [NSManagedObject] {
if fetchResults.count != 0 {
self.managedObjectContext.deleteObject(fetchResults[0])
}
}
}
}
Yes, the best way is to fetch all entities and then check for the unique ids. You could use key-value-coding (or its Swift equivalents such as map) to just get the ids you are interested in.
let existingIDs = entitiesFromParse.map() { $0.uniqueID as? String }
You can then check if an ID exists with
let idExists = existingIDs.contains(idToCheck)
This is preferable to multiple fetch requests which are expensive.

cant get the integer from core data atribute

I have a core data model, where I added entity named CurrentLevel and an attribute called currentLevel and of int16 type. I am trying to save a simple integer into it like this:
func saveCurrentLevel(cLevel: Int16){
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
let entity = NSEntityDescription.entityForName("CurrentLevel",
inManagedObjectContext:
managedContext)
let curLevel = NSManagedObject(entity: entity!,
insertIntoManagedObjectContext:managedContext)
curLevel.setValue(NSNumber(short: cLevel), forKey: "currentLevel")
var error: NSError?
if !managedContext.save(&error) {
println("Could not save \(error), \(error?.userInfo)")
}
}
and this is my method for fetching
func fetchTheStuff() {
//1
let appDelegate =
UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext!
//2
let fetchRequest = NSFetchRequest(entityName:"CurrentLevel")
//3
var error: NSError?
var fetchedResults =
managedContext.executeFetchRequest(fetchRequest,
error: &error) as? [NSManagedObject]
if let results = fetchedResults {
println(results)
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
}
I need that the fetched result would be just a simple integer and I cant find a way with core data to do so. Anyone know how ad/or what I am doing wrong?
executeFetchRequest() returns an array of managed objects.
You have to get a single element (e.g. the first), then retrieve the
value of the "currentLevel" attribute (which is a NSNumber)
and finally extract the Int16:
if let results = fetchedResults {
if count(results) > 0 {
let curLevel = results[0] // NSManagedObject
if let num = curLevel.valueForKey("currentLevel") as? NSNumber {
let cLevel = num.shortValue // Int16
println(cLevel)
} else {
println("level not set")
}
} else {
println("no objects found")
}
} else {
println("Could not fetch \(error), \(error!.userInfo)")
}
Instead of Key-Value coding with setValue/valueForKey() you can also
let Xcode create NSManagedObject subclasses. If you activate
the "use scalar properties for primitive data types" option then
you can access its
#NSManaged var currentValue: Int16
property directly.
With Objective-C you need to store the int as a NSNumber when using Core Data. So if I was using an int, I would do it like this:
coreDataClass.number = [NSNumber numberWithInt:100];
I'm not sure if it's the same with Swift though.

How to save and fetch one Object from Database in Swift?

I have a method which will save Object into Database. As per logic, whenever there is internet, it will save object by downloading from server.The method is as follows.
func saveConfiguration (config : ConfigDao){
let entity = NSEntityDescription.entityForName("AppConfig", inManagedObjectContext:self.del.managedObjectContext!)
let configurationContext = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: self.del.managedObjectContext!) as AppConfig
configurationContext.categoriesVer = Int32(config.categoriesVer)
configurationContext.fireBallIp = config.fireBallIP
configurationContext.fireBallPort = Int32(config.fireBallPort)
configurationContext.isAppManagerAvailable = config.isAppManagerAvailable
configurationContext.isFireBallAvailable = config.isFireballAvailable
configurationContext.timePerQuestion = config.timePerQuestion
}
Issue is that this adds all objects, and doesn't replace it, so my first query is
"How to add only one object in DB and replace when next Object comes?"
I also want to retrieve the same object, the only one object, normally in array, I do fetch last index, but how can I save only one and fetch same in DB.
func fetchAppConfig() -> AppConfig {
var fetchRequest = NSFetchRequest (entityName: "AppConfig")
var error : NSError?
let fetchResults = del.managedObjectContext?.executeFetchRequest(fetchRequest, error: &error) as [NSManagedObject]
if error != nil {
println ("Error \(error)")
}
return fetchResults
}
Thanks.
You can do as following.
//For storing only one object,
func saveConfiguration (config : ConfigDao){
let entity = NSEntityDescription.entityForName("AppConfig", inManagedObjectContext:self.del.managedObjectContext!)
var fetchRequest = NSFetchRequest (entityName: "AppConfig")
if let fetchResults = del.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [AppConfig] {
for ob: AppConfig in fetchResults
{
println("Delete object,,, ")
self.del.managedObjectContext?.deleteObject(ob as AppConfig)
}
self.del.saveContext()
}
let configurationContext = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: self.del.managedObjectContext!) as AppConfig
configurationContext.categoriesVer = Int32(config.categoriesVer)
configurationContext.fireBallIp = config.fireBallIP
configurationContext.fireBallPort = Int32(config.fireBallPort)
configurationContext.isAppManagerAvailable = config.isAppManagerAvailable
configurationContext.isFireBallAvailable = config.isFireballAvailable
configurationContext.timePerQuestion = config.timePerQuestion
del.saveContext()
}// end of the
//To fetch object at zero index. which will be only one, still you can use 0 index to be sure.
func fetchAppConfig() -> AppConfig {
var appConfig:AppConfig = AppConfig()
var fetchRequest = NSFetchRequest (entityName: "AppConfig")
var error : NSError?
if let fetchResults = del.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [AppConfig] {
if error != nil {
println ("Error \(error)")
}
appConfig = fetchResults[0]
}
return appConfig
}

Resources