Reputation: 2533
Note: although the question has a CoreData
example, it's not related to CoreData
, it's just an example
We are working on a Swift project with CoreData
as a caching layer.
We make use of Notification
s in our mainViewController
a lot to listen to the changes after our NSManagedObjectContext
has new changes.
This is working great until we added new entities with the following hierarchy:
Vehicle
is a base class with some attributes. Car
is a subclass of Vehicle
with specific attributes and a toMany relationship to Human
entity. Human
is a base class with specific attributes, and it has a relationship the Car
.The problem is in the following:
when a new Car
object is added, the notification fires, and in the mainViewController
, we need to check if it's of type Car
, like this:
if let insertedObjects = notification.userInfo?[NSInsertedObjectsKey] as? Set<Car> {
print("we have some cars") // this will never execute
}
The type downcast Set<Car>
will never evaluate to true because the Set
has elements of type Car
and also Human
.
What I want:
Check if the Set
has NSManagedObject subclass of type Car
or Human
as I downcast it.
What I tried to do:
downcast it to NSManagedObject
, and check if the Set
contains Car
by the adding the following where
condition:
insertedObjects.contains(Car)
, but it has a compile-time error:
Cannot convert value of type '(Car).Type' to expected argument type 'NSManagedObject'
Let me know if you have any question instead of just downvoting.
Upvotes: 3
Views: 131
Reputation: 19757
Not sure about the type casting (I think I remember doing it the same way and it worked, although it was with an array), but checking if there is a car in the set is different:
set.contains { (element) -> Bool in
return element is Car
}
Or shorter (more concise) version of the same call:
set.contains(where: { $0 is Car })
Upvotes: 1
Reputation: 540055
First downcast the inserted object to Set<NSManagedObject>
.
To check if any car has been inserted, use
if let insertedObjects = notification.userInfo?[NSInsertedObjectsKey] as? Set<NSManagedObject> {
if insertedObjects.contains(where: { $0 is Car }) {
print("we have some cars")
}
}
To get the inserted car objects as a (possibly empty) array,
use flatMap()
:
if let insertedObjects = notification.userInfo?[NSInsertedObjectsKey] as? Set<NSManagedObject> {
let insertedCars = insertedObjects.flatMap { $0 as? Car }
}
Your approach
if insertedObjects.contains(Car)
does not compile because
func contains(_ member: Set.Element) -> Bool
expects an instance of the element type as argument. As shown above, you can use the predicate-based variant
func contains(where predicate: (Element) throws -> Bool) rethrows -> Bool
instead.
Upvotes: 1