I have a model which references all object with a reference to itself. I thought I could use this property, LinkingObjects(fromType: Outfit.self, property: "clothes") as a List<Outfit> and just patch it right into my existing code.
Specifically I need to use the observe function of List. Is there any way to treat LinkingObjects equally as List?
Let me give this a shot with an example - you may be approaching it backwards or I may not fully understand the question.
Suppose you have an Outfit class that has a List property of clothing objects
OutfitClass: Object {
let clothingObjects = List<ClothingClass>
}
and then a class that holds each clothing type with a Link back to a particular OutfitClass. Now we have an inverse relationship.
ClothingClass: Object {
#objc dynamic var description = ""
let outfits = LinkingObjects(fromType: OutfitClass.self, property: "clothingObjects")
}
So each outfit has a list of clothes, jacket, button up shirt, tie etc and each of those items would know what outfit or outfits it belongs to.
That should satisfy the requirements where a model (the ClothingClass)
which references all objects (the OutfitClass) with reference to itself
I understand the objective is that you want to add an observer to all Outfit objects where a certain clothing item is referenced. So for example: the Red Tie Clothing Class object wants to observe all Outfits that reference that Red Tie.
So the approach is like this
First, we need to load in the Clothing Class object we are interested in
let redTieResults = realm.objects(ClothingClass.self).filter("descripton == 'Red Tie'")
no error checking here but let's assume that Red Tie is guaranteed to exist
let thisRedTie = redTieResults.first!
Now lets get the results, to which we can add an observer, for any Outfit class objects that have this specific Red Tie object in their List
let outfitResults = realm.objects(OutfitClass.self).filter("ANY clothingObjects == %#", thisRedTie)
then you add an observer to the outfitResults
Related
For example, there are a Dog and a Cat Object, and they all have the same property "owner", how can I delete all the dog and cat which have the same owner in the database? Do I have to delete them individually? It bothers me because I need to delete so many objects at a time based on a property they all have.
At the moment there is no way to achieve this. None of Realm's Collection types support having elements from different types, so you cannot create a Realm List or Results instance that could hold all your objects that share the same property, but have different types.
In the future once Realm outgrows this limitation, you should be able to define a superclass, called Animal, which have an owner property, make both Dog and Cat inherit from the Animal class, then delete all objects from Realm that inherit from Animal.
However, at the moment even if you make an abstract Animal class and make both Dog and Cat inherit from Animal, if you try to delete all objects of type Animal from Realm, it will only delete the objects whose type is actually Animal, but it won't delete any objects whose type inherits from Animal.
See this GitHub issue for details about the problem around inheritance in Realm and some workarounds.
Try this
let samsPets = realm.objects(Pet.self).filter("owner.name = 'Sam'")
do {
try realm.write {
realm.delete(samsPets)
}
} catch {
print(error)
}
Here we're querying for all pets, who's owners name is sam and deleting them. This could be all done in one statement too.
This assumes that each pet has a property reference to their owner.
(i.e. dynamic var owner: Person?)
We are a looking for a value type design pattern in swift that will allow us to create a shopping cart to hold Products. We are currently using a class but that is a reference type and when we try to add two different version of the same product (i.e. with a different colors or sizes), the first item we added gets changed to the second item we added because it points to the same object in memory.
The design pattern needs to be “global” so we can access it from any page in the app. Right now this is our Cart class that stores all the items in the cart. What do we need to do to make this a value type or how does it need to be reengineered to use a struct without a class?
class Cart : NSObject {
var allProductsInCart = [MainProduct]()
override init() {
super.init()
}
class var sharedCart: Cart {
struct Static {
static let instance = Cart()
}
return Static.instance
}
}
The problem we are getting is that we need the products in the cart to be of custom class “MainProduct.” Right now as you can see, they are stored as “MainProduct.” Do we need to switch the products to a struct or other design pattern as well? How would we do that?
Yes, given the desired behavior between a value type vs. reference type you should use a Struct.
A commonly used "pattern" for doing this is called "Redux".
The idea is that you have one, immutable version of the "state" of your app.
It can be accessed from anywhere and the only way to update it is through "actions". These will reconstruct the entire state with the required updates.
ViewControllers and views, etc... subscribe to updates of various parts of the state.
So you could have an AppState that contains a ShoppingCartState. When a product is added to it your CartViewController will be informed of this update and can update its view etc...
There are many different frameworks that are built to use Redux so I won't recommend one as you should find the one that is right for you. But I believe this pattern best suits the usage you are after.
I have a NSManagedObject subclass defined like this:
extension Item {
#NSManaged var name: String
#NSManaged var parent: Item
#NSManaged var children: [Item]
}
In order to set the 'parent' attribute, I use this:
anItem.parent = aParent
And I know it will automatically append anItem to aParent.children too.
However, I would like the child item to be added at a specific position.
This idea is to have a sorted array of children.
I know I could simply do this:
aParent.childen.insert(anItem, atIndex: specificPosition)
But is there any method to override or operator to overload in order to automatically achieve that ?
Inserting the child at a particular position will not ensure the same sort order later when you fetch.
You will need an additional attribute to define the sort order during the fetch.
Have a look at this answer
A couple misconceptions here:
CoreData to-many relationships are not of type Array, they are Set or NSSet. This can be verified by having your subclass generated by Xcode.
It is possible to to have an ordered relationship - just take a look at the relationship inspector in your Core Data Model. This will change it to a NSOrderedSet
MAJOR CAVEAT to (2) - The order is determined exclusively by the order that you add them - see this link for more info.
It is much more memory intensive to store these as ordered, if you can, have an attribute you can use to order them after fetching.
I'm using CoreData and I have a Book entity and a ReadingSession entity. Each Book has many ReadingSessions.
If I add this computed property to the Book class, it works:
var sessions: [ReadingSession] {
let request = NSFetchRequest(entityName: "ReadingSession")
let predicate = NSPredicate(format: "book = %#", self)
request.predicate = predicate
return try! DataController.sharedInstance.managedObjectContext.executeFetchRequest(request) as! [ReadingSession]
}
But if I add this one, it doesn't:
var sessions: [ReadingSession] {
return readingSession?.allObjects as! [ReadingSession]
}
This last example sometimes returns the correct array and sometimes just returns an empty array.
I tried the same thing with other relationships inside computed properties and the results are the same.
Why is that? Is there a reason why I shouldn't try doing this? Is my first example a valid workaround, or will it cause me problems later on? Should I give up using computed properties for this and just repeat the code when I need it?
Thanks in advance!
Daniel
Answering my own question, as Wain pointed out in the comments I should be able to use relationships inside computed properties, and my problem was actually somewhere else.
If you're interested in the details read the next paragraph, but, long story short, if you're having the same problem you should look into your relationships and make sure they're set properly as To One or To Many. Also check if you're setting all your properties in the right places and only when necessary.
I edited my question to remove lots of unnecessary details and make it more readable, but in the end the problem was that I had a User entity with a selectedBook property which was set when a user selected a row. I had set it up as a To Many relationship, but a user can have only one selectedBook at a time, so it should have been a To One relationship there. Also when I created a book I set user.selectedBook to it, but the selectedBook property should only be set when a user selected a book from a row. So I was setting and trying to access some of my relationships at all the right times. I tried to access a user.selectedBook before a user had even selected a row, for instance, and then it obviously returned nil, which messed up many other computed properties. Now I fixed all that and I'm able to access all my relationships from within computed properties without any issues.
I don't even know how to title this one:
Lets say I have a manufacturer entity and a model entity, with a one-to-many relationship.
Each manufacturer can have multiple models (just using these as an example).
manufacturer has a tableview and its independent fetchedResultsController, then when you press on a manufacturer cell you go to models viewcontroller that also has its own tableview and fetchedResultsController, ofc showing the relevant added models.
Let's say I would like to take one of the models and copy them or cut them into another manufacturer, I was thinking of a method styled like:
-(void)copyThis:(Model*)model toThat:(Manufacturer*)manufacturer
I am grabbing the right manufacturer object and the right model object but how can I implement the insertion of one to another?
To copy
Model *newModel = [NSEntityDescription insertNewObjectForEntityForName:#"Model" inManagedObjectContext:self.context];
newModel.property = model.property; //For every property
model.relationShipName = manufacturer;
[self.context insertObject:copyModel];
To cut
model.relationShipName = manufacturer;
(I assume that you have an xcdatamodeld and have generated an NSManagedObjectSubclass of your Model and Manufacturer entities)
What do you want to achieve with copying? Do you want a 'new' model with the exact parameters added to the other manufacturer, or do you want the relationship to be with the same model object?
Assuming you want to keep a single instance of the Model object:
Manufacturer *fromManufacturer = ...
Model *model = [[fromManufacturer models] objectAtIndex:...];
Manufacturer *toManufacturer = ...
[toManufacturer insertModelObject:model];
if (isCut) [fromManufacturer removeModelObject:model];
To get the insertModelObject and removeModelObject methods automatically, you can use Xcode to generate NSManagedObject subclasses for you automatically. It's under the Editor menu when you're looking at the CoreData Model file. Note that the names of the methods and objects may be different depending on the CoredData model structure and relationship names you've created.