I am trying to use Core Data to save some of my application data. I have following classes. Basically I want to store the properties of each job, and use it later on.
Following is the class I currently use in my application.
class Job {
var name:String?
var count = 1
var id:String
var startDate:NSDate?
var finishDate:NSDate?
var expected:NSDate?
var detail:Array<JobDetail> = []
var isFinished:Bool?
var sender:String?
var receiver:String?
init(name:String?, id:String) {
self.name = name
self.id = id
self.isFinished = false
self.startDate = NSDate()
}
func addDetail (message:String?, date:NSDate?, location:String?, status: DetailStatus) {
detail.append(JobDetail(message: message, date: date, location: location, status: status))
if status == DetailStatus.OK {
self.isFinished = true
self.finishDate = date
}
}
}
enum DetailStatus {
case OK
case Error
case Exception
case Unknown
}
class JobDetail {
var message:String?
var date:NSDate?
var location:String?
var status:DetailStatus
init(message:String?, date:NSDate?, location:String?, status: DetailStatus) {
self.message = message
self.date = date
self.location = location
self.status = status
}
}
NSManagedObject sub class I created with Xcode after I create the data model.
class Job: NSManagedObject {
#NSManaged var name: String
#NSManaged var count: NSNumber
#NSManaged var id: String
#NSManaged var startDate: NSDate
#NSManaged var finishDate: NSDate
#NSManaged var expected: NSDate
#NSManaged var isFinished: NSNumber
#NSManaged var sender: String
#NSManaged var receiver: String
#NSManaged var details: NSSet
}
class JobDetail: NSManagedObject {
#NSManaged var message: String
#NSManaged var date: NSDate
#NSManaged var location: String
#NSManaged var status: NSNumber
#NSManaged var parent: Job
}
Here are the screenshots of my data model.
Basically I want to CRUD Job in my application so that I can show them in my tableview. I have everything setup, but because I couldn’t setup Core Data I don’t have persistence. I will appreciate if you can help me to setup Core Data.
Refer this. May be it's useful to you...
http://www.raywenderlich.com/85578/first-core-data-app-using-swift
It seems from the screenshots that your setup is correct. Link details with jobs like this.
detail1.parent = job
detail2.parent = job
context.save(nil)
Get all details for a job like this
job.details
This is unordered, but you can sort them using sortedArrayUsingDescriptors.
let sortedDetails = job.details.sortedArrayUsingDescriptors(
[NSSortDescriptor(key:"date" ascending: false)])
Related
I'm working with web app. I have UITableViewController which deals with NSFetchedResultsController. I store tableView's objects through CoreData. When a user refreshes UI I perform server request and then call batch update for each new entity, my CoreData class looks like:
extension DBOrder {
#NSManaged var comment: String
#NSManaged var date: NSNumber
#NSManaged var id: NSNumber
#NSManaged var maturity_date: NSNumber
#NSManaged var number_of_tasks: NSNumber
#NSManaged var price: NSNumber
#NSManaged var status: String
#NSManaged var subject: String
#NSManaged var taskImages: [String]
#NSManaged var theme: String
}
"id" is unique for each object. "propertiesToUpdate" consists of some fields like "maturity_date": 1470427641000, "status": "some status" and etc. "entityName" is "DBOrder". And privateContext is NSManagedObjectContext type to update entities in background
func updateCoreData(id: NSNumber, entityName: String, propertiesToUpdate: [String: AnyObject], privateContext: NSManagedObjectContext) -> Bool {
let batchRequest = NSBatchUpdateRequest(entityName: entityName)
batchRequest.predicate = NSPredicate(format: "id == %#", id)
if !doesOrderExists(entityName, id: id, context: privateContext) {
return false
}
batchRequest.propertiesToUpdate = propertiesToUpdate
batchRequest.resultType = .UpdatedObjectIDsResultType
do {
let res = try privateContext.executeRequest(batchRequest) as! NSBatchUpdateResult
let orderIDs = res.result as! [NSManagedObjectID]
return (orderIDs.count != 0) ? true : false
} catch {
print(error)
}
return false
}
This function is called for each object that has been loaded from server. If object is already existed then I update it else create the new one.
Finally, the problem: when I use batch update it works incorrect with NSNumber. It always puts NSNumber fields to nil and works as it should with String fields. So, what I'm doing wrong?
I'm using Parse and I had a PFObject I was using to represent a "Job". It worked fined, but it was tedious always using setObject:forKey: and objectForKey: rather than accessing properties.
So, I decided to make a "proper" PFObject subclass. Now, every call made to "objectId" gives the above unrecognized selector error -- even calls that have nothing to do with my subclass.
I created my subclass "by the book", as far as I can tell (below), and I do call Job.registerSubclass() before Parse.setApplicationId: in my AppDelegate. Anybody seen this problem?
import Foundation
import Parse
class Job: PFObject, PFSubclassing {
#NSManaged var categoryName: String
#NSManaged var categoryId: String
#NSManaged var state: String
#NSManaged var details: String?
#NSManaged var jobDescription: String
#NSManaged var location: String
#NSManaged var dates: [String]
#NSManaged var images: PFFile?
#NSManaged var questionSequence: [String]?
#NSManaged var consumerResponseIndices: [Int]?
#NSManaged var isPosted: Bool
#NSManaged var bids: [AnyObject]?
override class func initialize() {
struct Static {
static var onceToken : dispatch_once_t = 0;
}
dispatch_once(&Static.onceToken) {
self.registerSubclass()
}
}
class func parseClassName() -> String {
return "Job"
}
}
I got the same issue before.
You may have this error when trying to convert NSArray/NSDictionary to String type, so it turns to NSContiguousString type.
You can check:
dates
questionSequence
consumerResponseIndices
bids
to see if this happened.
In my case the problem was :
if let countryLocale = (notification.userInfo![Constants.CountryLocale]!.firstObject as? String { code }
and solved with
if let countryLocale = (notification.userInfo![Constants.CountryLocale] as! [AnyObject]).first as? String { code }
In my calendarViewController I'd like to prepare an array containing dates. In my model i have to-may relationship where one medicine can have multiple dates of taking pill. How can i perform a loop through this set to append an array ?
My models:
extension Medicine {
#NSManaged var amount: String?
#NSManaged var endDate: String?
#NSManaged var name: String?
#NSManaged var time: String?
#NSManaged var notificationSet: NSNumber?
#NSManaged var taken: NSOrderedSet?
}
Model Dates
extension Dates {
#NSManaged var date: NSDate?
#NSManaged var takes: Medicine?
}
I'd like to perform loop like this ,but instead these dates i'd like those from CoreData:
var dates = [NSDate(timeIntervalSinceNow: 60*60*24*2), NSDate(timeIntervalSinceNow: 60*60*24*3), NSDate(timeIntervalSinceNow: 60*60*24*5), NSDate(timeIntervalSinceNow: 60*60*24*7)]
func calendar(calendar: CKCalendarView!, configureDateItem dateItem: CKDateItem!, forDate date: NSDate!) {
for dateTaken in dates {
if calendar.date(date, isSameDayAsDate: dateTaken) {
dateItem.backgroundColor = UIColor.redColor()
}
}
}
Fetch your Medicine entity and then create the array like this:
let dates = medicine.taken.map { $0.date }
Not sure about the NSOrderedSet which tends to be buggy so I generally avoid it, but you can try appending as! [NSDate] to make sure you have an proper array of dates.
I have a User model class (generated by XCode with Swift):
#objc(User)
class User: NSManagedObject { }
And it's extension:
extension User {
#NSManaged var id: NSNumber?
#NSManaged var firstName: String?
#NSManaged var lastName: String?
#NSManaged var birthYear: NSNumber?
}
I can save/fetch data from CoreData.
But can I use this class for object management without CoreData things? Or i need to create other class/struct for this?
For example, create User object (without ObjectContext), set his attributes and send it as property in some func? Maybe i can create some struct in class User (like struct {var firstNameData, secondNameData,...}) and use it in code?
I updated class:
struct User {
var id: Int!
var firstName: String!
var lastName: String!
var birthYear: UInt?
}
#objc(UserManagedObject)
class UserManagedObject: NSManagedObject {
func toStruct() -> User {
var userData = User()
userData.id = Int(self.id)
userData.firstName = self.firstName
userData.lastName = self.lastName
if let by = self.birthYear {
userData.birthYear = UInt(by)
}
return userData
}
}
Now for object management i use struct User and UserManagedObject for CoreData in/out
I have one to many relationship in my coredata model. For each News object I have many details object.
class Job: NSManagedObject {
#NSManaged var name: String
#NSManaged var count: NSNumber
#NSManaged var id: String
#NSManaged var startDate: NSDate
#NSManaged var finishDate: NSDate
#NSManaged var expected: NSDate
#NSManaged var isFinished: NSNumber
#NSManaged var sender: String
#NSManaged var receiver: String
#NSManaged var details: NSOrderedSet
}
class JobDetail: NSManagedObject {
#NSManaged var message: String
#NSManaged var date: NSDate
#NSManaged var location: String
#NSManaged var status: NSNumber
#NSManaged var parent: Job
}
So, how can I remove all details from Job? My current approach is to delete Job itself and create it again which is slower.
I have tried to delete with,
context?.deletedObjects(myJob.detail)
but it didn’t work. It says
'(#lvalue NSOrderedSet) -> _' is not identical to 'Set'
It seems that you mixed-up deleteObject() with deletedObjects().
deletedObjects() is a method to get a list of all managed objects which
have been marked for deletion in the managed object context. What you have to call is deleteObject()
for each object. Something like (not compiler-checked):
for detail in myJob.details {
context.deleteObject(detail)
}