Reputation: 37
I have entities Application
and Process
, one application can have many processes, but one process can only have one application. I get one specific application entity:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let appfetchRequest = NSFetchRequest(entityName: "Application")
//appfetchRequest.returnsObjectsAsFaults = false
do{
let results = try managedContext.executeFetchRequest(appfetchRequest)
applications.addObjectsFromArray(results as! [NSMutableArray])
}catch let error as NSError{
print("Jakis blad z applications entity: \(error)")
}
let predicate:NSPredicate = NSPredicate(format: "name == %@", appTitle)
let application:NSArray = applications.filteredArrayUsingPredicate(predicate)
and in this I have relationship (named applicationprocesses
).
I try to get an array with these entities in many ways, but no one work.
Actually, I have:
let processes = application.valueForKey("applicationprocesses").allObjects.first
print(processes?.valueForKey("applicationprocesses"))
And this give me:
Optional({(
<NSManagedObject: 0x7f945871b7a0> (entity: Application; id: 0xd000000000080002 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Application/p2> ; data: {
appcolor = "#3F3F3F";
appicon = bed;
applabel = Proces;
applabelplural = Procesy;
applicationprocesses = (
"0xd000000000140004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p5>",
"0xd000000000100004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p4>",
"0xd000000000180004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p6>",
"0xd0000000001c0004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p7>",
"0xd0000000000c0004 <x-coredata://00C2FE4A-143B-436E-B39B-A0A32C300B68/Process/p3>"
);
companyid = 392;
id = 1261;
name = "aplikacja 1";
processescount = 5;
})
)})
I need to display these processes in a UITablewView
, so I need an array.
I will be grateful for any help.
Upvotes: 1
Views: 950
Reputation: 8411
The problem you are having is not the result of a bad line of code somewhere. It is actually working as it is supposed to. But you can make it a lot easier to work with NSManagedObject
Any fetch from your database results in [AnyObject]
. If you leave it like it is, you are forced to use key-value coding which is a pain and very easy to mess up.
However it is very simple to create Classes from CD Entities and downcast the fetch result. This is an awesome feature of CoreData that unfortunately is not stressed enough.
Your related entities might look like this:
Go to Menu -> Editor -> Create....
Select the entities you want to create a subclass for.
New files will show up in your project :
Now you can use code like this :
Insert objects
Notice the .... as? Company
this is the downcast.
It allows you to access the attributes from the CD Entity like you would access any attributes from a Struct or Class.
func createACompany() {
// no appDel here. appDel and managedContext are best declared in the class scope. See gist for entire ViewController
guard let moc = managedContext else { return }
guard let company = NSEntityDescription.insertNewObjectForEntityForName("Company", inManagedObjectContext: moc) as? Company else {
return // guard is handy to "abort"
}
company.name = "Apple"
guard let bob = NSEntityDescription.insertNewObjectForEntityForName("Employee", inManagedObjectContext: moc) as? Employee else {
return
}
bob.name = "Bob"
bob.company = company
do {
try moc.save()
} catch {
print("core data save error : \(error)")
}
moc.refreshAllObjects()
}
Fetch objects
func fetchCompanies() -> [Company] {
guard let moc = managedContext else { return [] }
let request = NSFetchRequest(entityName: "Company")
request.returnsObjectsAsFaults = true
do {
let results = try moc.executeFetchRequest(request)
guard let companies = results as? [Company] else {
return []
}
return companies
}catch let error as NSError{
print("core data fetch error: \(error)")
return []
}
}
Get related objects
Look closely at the guard
statement.
let employeeSet = company.employees
-> unwrap of optional NSSet
let employees = employeeSet.allObjects
-> get all objects in the NSSet
as? [Employee]
-> downcast the result of allObjects
to an Array
of Employee
func getEmployees(forCompany company : Company) -> [Employee] {
guard let employeeSet = company.employees, let employees = employeeSet.allObjects as? [Employee] else {
return []
}
return employees
}
Side note:
If you change your mind about the naming of the class and you change it everywhere. Don't forget the update it here too :
The class field has to be updated.
Similar to the InterfaceBuilder. If you change the class name it will not find it anymore.
Upvotes: 2
Reputation: 33
I believe that you want to get all the managed objects (process) relate to the application object you already got. We usually use the "entity" word for same things as table in database.
I'm sorry I didn't have swift version for this line of code. I'm not sure about my swift skill
NSArray *processes = [[application fristObject] objectIDsForRelationshipNamed:@"applicationprocesses"]
Then use API to convert objectID to ManagedObject
- (__kindof NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;
The only problem is this API, (NSArray *)objectIDsForRelationshipNamed:(NSString *)key , only supported from version 8.3
Upvotes: 0