CoreData Relationships in two different ManagedObjectContexts - iphone

Warning: This is my first IPhone Application and I'm new to Objective C, therefore my question might be very basic.
Actually I have a conceptual problem:
I have a one to many relationship between my NSObjects Project and WorkTime (Project<-->>WorkTime). WorkTime has attributes like startDate, endDate, … and a relationship named project to the Project object.
On the UITableViewController subclass that shows my list of WorkTimes, I fetch the CoreData Model with a FetchedResultsController. When I create a new WorkTime, I use a second context and merge it with the "default" once, once the user has clicked on "save" on the drill-down View, like in the CoreDataBooks example from the Apple Documentation. That works well.
The problem starts when I set the relationship. Since the projects are in the “default” context, I can’t assign any project object to the project key in WorkTime, since they are in two different contexts.
So, should I copy all the projects into the “saving” context? Or should I use just one context for everything?
One problem that arises when I use only one context is that the tableview that shows the WorkTimes gets actualized when the user clicks on the addbutton (insertNewObjectForEntityForName). So the list grows right before it presents the new view controller (addWorkTimeDetail) in modalviewcontroller. And if the user clicks cancel in that detail view and decides not to save the WorkTime, I’d have to delete the newly created entity from the context. I don’t think this sounds the way to do it.
Suggestions would be very appreciated!
UPDATE
I'm still having some issues:
When the AddWorkTimeViewController is created from the RootViewController, I create a new NSObject WorkTime. When the user clicks "cancel" I delete the newly created WorkTime and return to the RootViewController. The FetchedResultsController actualizes the tableView and I see a short animation that comes because the object has been deleted. That's doesn't look nice.
I know it would be better to create the object ONLY if the user clicks "save" and by "cancel" do nothing, but I need that object in order to populate the drilldown views with values. The drilldown views work with a NSManagedObject. I see two possible ways to solve this:
1) Have a temporary object TempWorkTime subclassed from NSObject with the same attributes from the WorkTime NSManagedObject. I would create the TempWorkTime in the AddWorkTimeViewController and use it for the drilldown views. I would of course have to subclass them to accept an NSObject instead of a NSManagedObject. I guess type casting wouldn't work. When the user clicks "save", I would create a WorkTime NSManagedObject and pass it the values from the TempWorkTime.
2) Is it possible to trick the FetchedResultsController so that it doesn't update itself while the tableView is not visible? In that case, it would not respond to the changes in the context until it's back in view, and so it would not do the delete animation.
Any suggestions?
SECOND UPDATE - maybe it's useful for people trying to do this same thing
I found this link which proved to be very helpful:
http://www.timisted.net/blog/archive/multiple-managed-object-contexts-with-core-data/
It's very well explained why it's sometimes a good idea to use two contexts. I had some problems with using one context explained in the UPDATE part of my question.
Now I'm using two contexts and it works perfectly, even with relationships. Important is to use the NSManagedObjects of the second context when creating the relationship. That was my mistake when I started to work with this approach.

I don't see why you use two different contexts.
The way to do it is to pass your tableView's context to addWorkTimeDetail, and add any new WorkTimes to that context. If the user cancels, i.e. doesn't create a new object, there will be nothing new in the list when you return. If the user creates the new WorkTime in the context it was passed, it will show up in the list when you return.
In your example, use only one context, and pass it along to your subviews.

I found this link which proved to be very helpful:
http://www.timisted.net/blog/archive/multiple-managed-object-contexts-with-core-data/
It's very well explained why it's sometimes a good idea to use two contexts. I had some problems with using one context explained in the UPDATE part of my question.
Now I'm using two contexts and it works perfectly, even with relationships. Important is to use the NSManagedObjects of the second context when creating the relationship. That was my mistake when I started to work with this approach.

Related

What is the three20 method of passing objects between view controllers?

I have a basic RSS Reader I made from three20 tutorials using TTLauncherView as a menu to different feeds and TTTableViewController to show the feed list.
However, I am stuck at the point where from the feed list I click to view the feed item details. I use TTTableImageItem to display my feed items and I'm clueless as to how I am to use the URL variable in said TTTableImageItem to pass objects to the view controller showing the feed item.
I did some searching and I am lead to think that this cannot be done except via TTURLRequest, which leaves me even more confused.
Most of my code is adapted from IOSGuys tutorial, which uses a custom data source, data model and parser. I have tried making the data source and data model a singleton but to no avail and I'm unsure if that's even the best way to proceed for something as (presumably) simple as this.
Ideally I intend to pass the entire array of feed items with another argument for the index so that I can make use of UIPageControl to swipe between feeds when I'm at a more in-depth view.
Much help is appreciated! I have been spending too long looming around already!
The usual way of doing this is to have some sort of global singleton Data Manager class that manages the data models through Core Data, In-Memory Stores or other ways. Each model would have some sort of unique identifier. Doing it this way lends itself to a URL only stack needed to recover your navigation history without having to write state out to file in order to restore. You also can bring up any page in the app at any place with only a single URL. Using a URL scheme only then becomes trivial as you can do something like:
yourapp://blogs/jd82kd9
and have the blog view controller's init method contact the Data Manager for the blog with the unique identifier of jd82kd9
In your navigator's mappings, you would have something like this:
[map from:#"yourapp://blogs/(initWithBlogID:)") toViewController:[MyBlogViewController class]];
and then the initWithBlogID method would have the signature:
- (id)initWithBlogID:(NSString *)blogID;
see also Three20 : how to pass a class of objects between 2 views

is it good practice to share the ADD and EDIT screen to use the same UIViewController?

is it good practice to share the ADD and EDIT screen to use the same UIViewController?
That is in the case where the only real difference would be in one the values would be populated with existing (EDIT).
PS. Some clarification. So perhaps take the simple case where there is just one or two NSString fields (e.g. title & description) - so is there anything wrong (e.g any gottchas) associated with using the same controller/NIB(view) for both EDIT and ADD?
Not sure about "good practise", but...
Populating a Label with one or another string is easy, also easy is hiding buttons or fields on depending if the ADD or EDIT view is displayed.
The problems tend to come when your view has received the user input and then needs to decide whether to modify an existing object or to create a new object.
So before exiting, the view has to decide how to treat user input. If the differentiation is mind boggling complex you are better off with two viewsControllers. If it is a matter of a simple if-the-else in or near the viewWillDisapper method then one view can do.
I would use inheritance in this case. Some base UIViewController and two additional UIViewControllers - one for add, second for editing. You can use one UIViewController too, but it depends on how difficult your task is or isn't. It's too general question.

Which pattern should be used for editing properties with modal view controller on iPhone?

I am looking for a good pattern for performing basic property editing via a modal view on the iPhone.
Assume I am putting together an application that works like the Contacts application. The "detail" view controller displays all of the contact's properties in a UITableView. When the UITableView goes into edit mode a disclosure icon is displayed in the cells. Clicking a cell causes a modal "editor" view controller to display a view that allows the user to modify the selected property. This view will often contain only a single text box or picker. The user clicks Cancel/Save and the "editor" view is dismissed and the "detail" view is updated.
In this scenario, which view is responsible for updating the model?
The "editor" view could update the property directly using Key-Value Coding. This appears in the CoreDataBooks example. This makes sense to me on some level because it treats the property as the model for the editor view controller.
However, this is not the pattern suggested by the View Controller Programming Guide. It suggests that the "editor" view controller should define a protocol that the "detail" controller adopts. When the user indicates they are done with the edit, the "detail" view controller is called back with the entered value and it dismisses the "editor" view. Using this approach the "detail" controller updates the model. This approach seems problematic if you are using the same "editor" view for multiple properties since there is only a single call-back method.
Would love to get some feedback on what approach works best.
I don't think any of the Apple examples (or anyone else's) actually show you how to structure an entire real world application. Instead, each example is just a test harness which shows you how to use one particular feature of the API but pays no attention to how that feature really integrates with anything else. Data models are given particularly short shift.
I prefer a design in which the data model is the spine of the application upon which hands all the view-controller/view pairs. The view controllers do not communicate with each other directly but instead communicate through the data model. The data model tracks what information the app is currently working on and therefore what data each particular view controller needs at any given time.
Let's use a contact manager type apps as an example. The basic of the data model would be a list of contact objects each of which in turn would hold attributes of a contact. The data model would completely control access to the data and monitors which data was currently being used. The UI is hierarchal such that the user first sees a list of all contacts in a masterView, then the details of each contact in a contactDetailView and then can edit each contact attribute in a custom attribute edit view for each type of data so there is a nameEditView, a phoneDetailView, an emailEditView etc. Each has a paired view controller masterVC, contactDetailVC, nameEditVC etc.
The to build it's tableview, the masterVC ask the data model for the number of contacts, their divisions into sections and then request each particular contact object at each particular index path so it can display a table. When the user selects a table row, the masterVC tells the data model which contact object was selected by sending it the index. Then the masterVC pushes the contactDetailVC. It does nothing else.
When the contactDetailVC activates, it ask the data model for the currently active Contact object. It doesn't know or care how the current contact was selected nor even which view/VC preceded it. The data model returns the currently active contact. When the user selects a field, the contactDetailVC tells the data model which attribute of the contact was selected and then pushes the proper editorVC onto the stack.
When the editorVC loads it ask for the data model for the current contact and the current attribute being edited. It doesn't know or care how the current contact attribute was selected nor even which view/VC preceded it. When the user makes a change, it ask the data model to save the change (the data model can refuse if verification fails for some reason) and then pops itself.
Internally, I like to implement the data model in two parts each managed by separate object. One is the abstracted data manager itself in this case a Core Data stack. The second is an user defaults manager that tracks the actual state of operations in the data model and saves them to user defaults. A master object holds these objects as attributes and serves as the interface of the data model.
This type of model makes it easy to suspend, resume or restart the application back to its previous state. Since each view/VC is self contained, when you restart the app, you just push all the views on the stack without animation and the last one pushed pops up fully populated with data even though the user chose nothing in the previous views and indeed did not even see them.
It also protects the user from data loss in the event of a crash since each VC saves its data and the app state every time it pushes or pops. It's easy to add additional view/VC because each VC only has to know about and communicate with the data model instead of bunch of other VC. It makes the components of the app easy to use in different versions of the app or in different apps altogether.
Edit:
Do you just hard code some if
statements to pair up the attributes
with the correct editor, or are you
doing something more dynamic based on
the entity/attribute metadata?
In most the most common design, the Contact entity could have a variable number of phone#s, emails or other data fields so each attribute would actually be a separate entity and the Contact would have a relationships pointing to those entities. When the user selected that contact to edit in the ContactDetailView, the data-model would simply mark the NSManagedObject representing the desired attribute of the contact. It could do so by setting an attribute like "lastChosenAttribute" or storing the URI for the object. When the editor view loaded it would be hard coded to ask the data-model for the "lastChosenAttribute" and would receive an NSManagedObject for a phone#, email etc. The editor would make changes to that object and they would be automatically saved back into the contact.
For data that is singular, such as a name or name components, the data-model would provide the editorVC with the contact entity and the editorVC would be hard coded to ask the contact object for that specific attribute.
It's a tough call--the View Controller Guide recommendation seems cleaner conceptually, but the other method can be easier, especially if you're using Core Data. To give a blanket generalized opinion, I would say use your first method if you're using Core Data, since managed objects inherently have their own context and can update themselves (and classes such as NSFetchedResultsController can automatically respond to updates).
If you're not using Core Data, I would go with the "official" recommendation, since it makes it easier to manage updated properties manually. As to the concern about multiple properties, it's certainly possible to have multiple delegate methods and call the appropriate one. For instance:
//if property is an address
if ([self.delegate respondsToSelector:#selector(editorView:didUpdateAddress:)])
[self.delegate editorView:self didUpdateAddress:theAddress];
//if property is a name
if ([self.delegate respondsToSelector:#selector(editorView:didUpdateName:)])
[self.delegate editorView:self didUpdateName:theName];
This could get hard to manage, though--you'd probably want to have an abstract superclass for properties, or something along those lines.

Question regarding iPhone core data and how to duplicate features for multiple users...that doesn't make sense, just read my question :)

So I am working on a simple iPhone app, that uses core data to manage objects. My code is similar in function to Apple's CoreDataBooks app, found here. There is a blank UITableViewCell, and you have the ability to add objects to this blank list. If you hit the add button, a DetailViewController pops up that manages the attribute of each object. In the coredatabooks example, the app is like a library, and you can add book objects. My question is about how I might go about making it so that multiple users can have their own separate list of these objects. Again, relating back to coredatabooks, you would be able to make different library objects whose attributes are the book objects themselves. So using the convenient and easy to use coredata ui, would it be very hard to set it up so that in the UITableView, there was Library-A and Library-B and then selecting one of the libraries would move me to a screen that has the list of different books unique to that specific library? If you then select a book, you would then be able to view that book's attributes as before. So I guess my question is regarding how to put another RootViewController-esque view in front of the native one. As you may gather from this post I am in the learning stage of iPhone development, so I don't even know if logically this is even feasible or the correct way to do it. Any help/insight on this matter would be greatly appreciated! Thanks for your patience!
Create another UITableViewController (.h, .m, .xib files). And you can put some functionality into that view controller for adding library.
You can set that viewcontroller as startup object from MainWindow=.xib file. OPen that xib file -> expand navigation controller -> click on root view controller.
then in attributes window you can select your new controller as startup. you have to also set startup class from identity window.
Ruchir is correct, you can add another table view and controller. You will have to make some adjustments so that it is loaded and displayed first.
Also, it sounds like you will want to create a new entity in your data model for a Library which should have a to-many relationship with the Book entity.
Library <-->> Book
The new table view controller can use a fetched results controller that fetches Library entities. When the user chooses a row, you can set a property on the books table view controller before you push it on the navigation stack. Then use a predicate on the books fetched results controller to only fetch books in that library.

Where to store "global" data in Eclipse RCP Application?

I'm a beginner with Eclipse RCP and I'm trying to build an application for myself to give it a go. I'm confused about how one actually goes about handling model objects. None of the examples I can find deal with the problem I'm having, so I suspect I'm going about it the wrong way.
Say I need to initialise the application with a class that holds authenticated user info. I used my WorkbenchWindowAdvisor (wrong place?) to perform some initialisation (e.g. authentication) to decide what view to show. Once that's done, a view is shown. Now, that view also needs access to the user info I had earlier retrieved/produced.
The question is, how is that view supposed to get that data? The view is wired up in the plugin.xml. I don't see any way I can give the data to the view. So I assume the view has to retrieve it somehow. But what's the proper place for it to retrieve it from? I thought of putting static variables in the IApplication implementation, but that felt wrong. Any advice or pointers much appreciated. Thanks.
The problem you are facing here is in my opinion not RCP related. Its more an architectural problem. Your view is wired with business logicand!
The solution can be done by two (common) design-patterns:
Model-View-Controler (MVC)
Model-View-Presenter (MVP)
You can find plenty information about this in the web. I am going to point a possible solution for your particular problem using MVP.
You will need to create several projects. One is of course an RCP plugin, lets call it rcp.view. Now you create another one, which doesnt make UI contributions (only org.eclipse.core.runtime to start with) and call it rcp.presenter. To simplify things, this plugin will also be the model for now.
Next steps:
Add the rcp.presenter to the
dependencies of rcp.view (its
important that the presenter has no
reference to the view)
Export all packages that you are
going to create in the rcp.presenter
so they are visible
In rcp.presenter create an interface
IPerspective that has some methods
like (showLogiDialog(), showAdministratorViews(User user), showStandardViews(User user))
Create a class PerspectivePresenter that takes IPerspective in the constructor and saves it in an attribute
In rcp.view go to your Perspective, implement your interface IPerspective, and in the constructor create a new reference presenter = new PerspectivePresenter(this)
call presenter.load() and implenent
this in the presenter maybe like this
code:
public void load()
{
User user = view.showLoginDialog(); // returns a user with the provided name/pw
user.login(); // login to system/database
if(user.isAdministrator())
view.showAdministratorViews(user);
else
view.showStandardViews(user);
}
As you can see, the view just creates a reference to the presenter, which is responsible for all the business logic, and the presenter tells the view what to display. So in your Perspective you implement those interface functions and in each one you can set up your Perspective in a different way.
For each View it goes in the same way, you will need a presenter for the view which performs operations and tells the view (using the interface) what to display and passing down the final data. The view doesnt care about the logic. This is also very usefull when using JFace-Databindings (then only bound data is passed to the view).
For example, the WorkbenchWindowAdisor will just create everything that is needed in the application. Other views, perspectives, then can enable/disable menus and so on depending on the data they got (like when isAdministrator you might want to enable an special adminMenu).
I know this is quite a heavy approach, but the Eclipse RCP is designed for big (as the name says rich) applications. So you should spend some time in the right architecture. My first RCP app was like you described...I never knew where to store things and how to handle all the references. At my work I learned about MVP (and I am still learning). It takes a while to understand the concept but its worth it.
You might want to look at my second post at this question to get another idea on how you could structure your plugins.