I 'm learning about Objective - C by developing a contacts app. I'm not using Core data or the Address book API, as this is just for learning. So each contact is an object which is stored in a master NSArray. Users can create groups of contacts where each group stores the appropriate contact objects in an NSArray. The problem I'm facing is when a contact is deleted from the master array , I have to manually remove it from all the groups as NSArray retains its objects. Is there a better way around this?
As you are learning, i suggest:
Simple:
Have your application only contacts list, adding/editing/deleting a contact from a single master list. You can also save & retrieve list from plist in documents directory.
You will be learning: plist, tableView, navigation, viewControllers, maintaining data from & within array.
Realtime:
You can use a sqlite database, with 4-5 tables. Each having Contacts, Groups, Address, Website and many other if you like to have. All the tables with interlinked with a reference of row id's. Which definitely help you learn many things, apart from the above mentioned.
Dont copy objects into multiple arrays. Add the same object to multiple arrays using the same pointer to the original object. Maintain pointers to the arrays and remove the same object from all the arrays at once. If you want to implement isEqual make it use == pointer equality.
Copying the same object for the purposes of storing in collections only creates headaches for yourself. Immutability is a nice feature, but actual identity across the system is a better one especially in a pointer based language.
Related
I've created a model that has mainly a nested array of custom objects for use in a split-view (both UITableViews) "to-do" list type app. The left (master) is the lists of lists and the right (detail) is the lists :) Some other variables are kept in some of the classes like isSelected, isExpanded...
All of these classes implement NSCopying protocol. When I make a copy of a master list item and change the copy's name that works, but if I change anything in the detail list item belonging to that master list item, it changes in both the copy and the original. So I guess my question is how do I create a deep copy of a master list item. I thought by making them all implement NSCopying protocol it would automatically do this. I I really don't know what to put for code with so anything you need just ask.
Take a look at NSKeyedArchiver - you can archive your array of arrays, unarchive it, and you have a deep copied clone.
(Of course this only works if all your objects support archiving.)
how do I create a deep copy of a master list item
By implementing the deep copy logic in your own code. Deep copies are typically -- sometimes, but generally not -- more than just doing a copy of every object in the collection and everything it is connected to. Outside of property lists, anyway, which do support deep copies, but are limited to very simple, non-cyclic object graphs.
So, you would iterate the collection and copy each item in the collection, as needed. While implementing copyWithZone: may seem reasonable, a deep copy is often done by manually instantiating new instances and setting the various attributes based on the original as needed, copying where required.
-(MyClass)deepCopy {
MyClass* theCopy = [self mutableCopy];
for (MyElementType* element in self.dataContainer) {
MyElementType* theCopiedElement = [element deepCopy];
[theCopy somehowInsertThisElementInTheRightPlace:theCopiedElement]l
}
return theCopy;
}
Obviously, there's a bit of magic involved in that 5th line -- exactly how you do it depends on how the subsidiary data items are attached to your object. But there are really only 3-4 basic scenarios. Recursion naturally handles everything else.
(And note that you can be "smart" and not copy immutable objects, etc.)
(Also note that you can create "categories" for NSMutableArray and NSMutableDictionary.)
I am writing a small program for a data structures class that basically stores member objects. One of the things the user needs to be able to do is delete and add new users. That being said, I use an arraylist to hold my objects and then I clone it so that I can have two arraylists sorted in different ways. Changing object fields in one list DOES change them in the other but when I delete an object from one arraylist, it still stays in the other. What would be the best method to completely delete that member object from all arraylists?
A good way would be to write a helper method that would remove the element from each of the array lists, and use that method for the removal.
This is similar to a question I asked before, but now that I've come much further along I still have a question about "proper" subclassing of NSManagedObject as I was told last night that it's a "bad idea" to put lots of non-persisted properties and ivars inside one. Currently I have TONS of code inside my NSManagedObject, and Apple's docs don't really address the "rightness" of that. FYI: the code works, but I'm asking if there are pitfalls ahead, or if there are obvious improvements to doing it another way.
My "object" is a continuously growing array of incoming data, the properties/ivars that track the progress of the analysis of that data, and the processed data (output). All of this is stored in memory because it grows huge, very quickly, and would not be possible to re-generate/re-analyze continuously. The NSManagedObject properties that are actually persisted are just the raw data (regularly saved, as Core Data doesn't support NSMutableData), a few basic properties and 2 relationships to other NSManagedObjects (1 being a user, the other being a set of snapshots of the data). Only one object is being recorded to at any one time, although dozens can be opened for viewing (which may involve further processing at any time).
It's not possible to have the object that inserts the entity (data manager that manages Core Data) have all of the processing logic/variables inside it, as each object necessitates at least a handful of arrays/properties that are used as intermediaries and tracking values for the analysis. And I, personally, think that it sounds silly to create two objects for each object that is being used (the NSManagedObject that is the store, and another object that is the processing/temp store).
Basically, all of the examples I can find using NSManagedObjects have super simple objects that are things like coordinates, address book entries, pictures: stuff that is basically static. In that case I can see having all of the logic that creates/modifies them outside the object. However, my case is not that simple and I have yet to come up with an alternative that doesn't involve duplication.
Any suggestions would be appreciated.
You might use a 'wrapper', that is to say a class with a reference to one of your managed object instances, this wrapper would contain your algorithms and your non persisted algorithms.
I am having difficulty deciding which is the best method for saving my app data.
It is a recipe app.
I have an array of category class objects that contains an NSString variable for the category title and an NSMutable Array of Recipe class objects (which contains 3 NSString variables).
here is a semi-visual representation of my app model:
Array of Categories contains:
Category Object 1-->contains string title and mutable array of Recipe Objects
Category Object 2-->contains string title and mutable array of Recipe Objects
...
etc.
Users are able to create new recipes and the recipe object is stored within a selected category object.
On app load x amount of categories are created (depending on value of a numberOfCategories int). and of course upon relaunch I want to restore the recipes to their appropriate category objects.
Hopefully that wasn't too confusing--I was going the NSUserDefaults way and doing the NSCoding thing to encode/decode my custom objects but found it confusing because I have an array of custom objects that contains an array of custom objects.
I am open to the idea if it is the best route of converting my project to use Core Data--but that also seemed overly complicated for the simplicity of my app (pre-populating my SQLite database with categories, etc etc).
Let me know if you need further clarification.
Use CoreData. Sounds like you will need at least two separate entities and establish a relationship between them (Recipe and RecipeObject). NSUserdefaults is great for storing small amounts of data that needs to be persisted, but not really good for your use case.
Also, check out MagicalRecord and MOGenerator. Both of these open source libraries make working with CD much more fun and productive.
I would suggest you serialize your object as XML which is a good method to store hierarchical data.
context:
I have an entity Book. A book can have one or more Descriptions. Descriptions are value objects.
problem:
A description can be more specific than another description. Eg if a description contains the content of the book and how the cover looks it is more specific than a description that only discusses how the cover looks. I don't know how to model this and how to have the repository save it. It is not the responsibility of the book nor of the book description to know these relationships. Some other object can handle this and then ask the repository to save the relationships. But BookRepository.addMoreSpecificDescription(Description, MoreSpecificDescription) seems difficult for the repository to save.
How is such a thing handled in DDD?
The other two answers are one direction (+1 btw). I am coming in after your edit to the original question, so here are my two cents...
I define a Value Object as an object with two or more properties that can (and is) shared amongst other entities. They can be shared only within a single Aggregate Root, that's fine too. Just the fact that they can (and are) shared.
To use your example, you define a "Description" as a Value Object. That tells me that "Description" with multiple properties can be shared amongst several Books. In the real-world, that does not make sense as we all know each book has unique descriptions written by the master of who authored or published the book. Hehe. So, I would argue that Descriptions aren't really Value Objects, but themselves are additional Entity objects within your Book Aggregate Root Entity boundery (you can have multiple entities within a single aggregate root's entity). Even books that are re-released, a newer revision, etc have slightly different descriptions describing that slight change.
I believe that answers your question - make the descriptions entity objects and protect them behind your main Book Entity Aggregate Root (e.g. Book.GetDescriptions()...). The rest of this answer addresses how I handle Value Objects in Repositories, for others reading this post...
For storing Value Objects in a repository, and retrieving them, we start to encroach onto the same territory I wrestled with myself when I went switched from a "Database-first" modeling approach to a DDD approach. I myself wreslted with this one, on how to store a Value Object in the DB, and retrieve it without an Identity. Until I stepped back and realized what i was doing...
In Domain Driven Design, you are modeling the Value Objects in your domain - not your data store. That is the key phrase. It means you are not designing the Value Objects to be stored as independant objects in the data store, you can store them however you like!
Let's take the common DDD example of Value Objects, that being an Address(). DDD presents that an Mailing Address is the perfect Value Object example, as the definition of a Value Object is an object of who's properties sum up to create the uniqueness of the object. If a property changes, it will be a different Value Object. And the same Value Object 9teh sum of its properties) can be shared amongst other Entities.
A Mailing Address is a location, a long/lat of a specific location on the planet. Multiple people can live at the address, and when someone moves, the new people to occupy the same Mailing Address now use the same Value Object.
So, I have a Person() object with a MailingAddress() object that has the address information in it. It is protected behind my Person() aggregate root with get/update/create methods/services.
Now, how do we store that and share it amongst the people in the same household? Ah, there lies DDD - you aren't modeling your data store straight from your DDD (even though, that would be nice). With that said, you simple create a single Table that presents your Person object, and it has the columns for your mailing address within it. It is the job of your Repository to re-hydrate that information back into your Person() and MailingAddress() object from the data store, and to split it up during the Create/Update operations.
Yep, you'd have duplicate data now in your data store. Three Person() entities with the same mailing address all now have three seperate copies of that Value Object data - and that is ok! Value Objects are meant to be copied and destoyed quite easily. "Copy" is the optimum word there in the DDD playbook.
So to sum up, Domain Drive Design is about modeling your Domain to represent your actual business use of the objects. You model a Person() entity and a MailingAddress Value Object seperately, as they are represented differently in your application. You persist them a copied-data, that being additional columns in the same table as your Person table.
All of the above is strict-DDD. But, DDD is meant to be just "suggestions", not rules to live by. That's why you are free to do what myself and many others have done, kind of a loose-DDD style. If you don't like the copied data, your only option is that being you can create a seperate table for MailingAddress() and stick an Identity column on it, and update your MailingAddress() object to have now have that identity on it - knowing you only use that identity to link it to other Person() objects that share it (I personally like a 3rd many-to-many relationship table, to keep the speed of the queries up). You would mask that Idenity (i.e. internal modifier) from being exposed outside of your Aggregate Root/Domain, so other layers (such as the Application or UI) do not know of the Identity column of the MailingAddress, if possible. Also, I would create a dedicated Repository just for MailingAddress, and use your PersonService layer to combine them into the correct object, Person.MailingAddress().
Sorry for the rant... :)
First, I think that reviews should be entities.
Second, why are you trying to model relationships between reviews? I don't see a natural relationship between them. "More specific than" is too vague to be useful as a relationship.
If you're having difficulty modeling the situation, that suggests that maybe there is no relationship.
I agree with Jason. I don't know what your rationale is for making reviews value objects.
I would expect a BookReview to have BookReviewContentItems so that you could have a method on the BookReview to call to decide if it is specific enough, where the method decides based on querying its collection of content items.