How can I suspend the working of an NSFetchedResultsController? - core-data

I have a UITableViewController fed by an NSFetchedResultsController. From it, the user can call up a modal ViewController in which he or she can enter new data. As this begins, I create a temporary object as follows:
newPtr = [[Entry alloc] initWithEntity:[NSEntityDescription
entityForName:#"Entry" inManagedObjectContext:self.nmocontext]
insertIntoManagedObjectContext:self.nmocontext];
As the user makes choices, attributes of this 'provisional' object, newPtr, are set.
The problem is that the base UITableViewController remains active while the modal ViewController is visible. It seems to be freaking out (causing crashes) in some cases when it realizes a mandatory attribute of newPtr has not been set yet.
What can I do to stop the NSFetchedResultsController from looking at my managed object context until the modal ViewController is dismissed?

Core Data supports "nested" managed object contexts which allow for a flexible architecture that make it easy to support independent, cancellable, change sets. With a child context, you can allow the user to make a set of changes to managed objects that can then either be committed wholesale to the parent (and ultimately saved to the store) as a single transaction, or discarded. If all parts of the application simply retrieve the same context from, say, an application delegate, it makes this behavior difficult or impossible to support.

I haven't tested this myself but a possible approach would be to implement viewWillAppear and viewWillDisappear, and set the fetchedResultsController delegate to self on will appear and nil on will disappear.
OR
You could create an NSObject that mirrors the attributes of your NSManagedObject in your editing window. Once the user has finished editing the attributes (and you have run the appropriate validation rules) you can pass them back to your NSManagedObject instance and let the fetchedResultsController do its job.

Related

Passing an object from a tabbarController to its subviews

I am trying to pass a simple core data objects info from a tabBarController to its subviews so that they each reference a different attribute of that object. As a newbie, I'm not sure even where to start. It doesn't seem to be as simple as passing the data from one tableView to another...
Thank you for any help.
If you are sharing the same object between (most of the) the view controllers of your tab bar controller, maybe the best architecture for this would be to have one central data object.
A typical pattern is a singleton, some kind of data manager that provides the object, but maybe that is overkill. Another is to keep references to all view controllers and update them one by one when something changes - also not very elegant.
What you really want is something like a global variable. You could (ab)use your app delegate (just give it a property that points to the object) or if you prefer even your tab bar controller (make a subclass, give it a property). In the latter case, every view controller could then get the object like this:
NSManagedObject *object = [(MyCustomTabBarController*)self.tabBarController object];
For example, you can check for changes and refresh your views in viewWillAppear.
A UITabBarController should be handling other view controllers, not handling data objects. How does the tab bar controller get the object reference in the first place? And what is the object you're sharing?
Let each of your subordinate VC's keep a pointer to the object, and then they can each follow the appropriate keypath to get to the entities they're designed to handle.
Tim Roadley's book Learning Core Data for iOS, in chapters 5 and 6, shows how to pass an object from one view controller (a table view) to a detail view. It doesn't sound like that's what you're asking, but just in case...
In response to comment:
I'm looking at a tableview, tap a cell, and then a tab bar controller slides in? That's not the usual visual metaphor for a tab bar; it's meant for changing modes for the entire program. See the Music app for a typical example: songs, playlists, artists.
But if you really need to do it that way, try this (I'm assuming you're using storyboards):
In prepareForSegue: in your tableview controller, tell the destination (tab bar controller) what object it's working with.
In the tab bar controller's -viewWillAppear, tell each of its tabs about the attribute: self.frobisherViewController.frobisher = self.myWidget.frobisher.
You could instead tell each of the component tabs about the top level object: self.frobisherViewController.widget = self.myWidget. But I like the first approach better because there is less linkage. The frobisherViewController now would need to know about both widgets and frobishers.
This ended up being very simple. I was trying to call the object in the child views initWithNibName which doesn't work. I ended up creating a setObject function and calling the properties I wanted in viewWillAppear.
Hope this helps someone.

Bind NSArrayControllers ManagedObjectContext after loading from nib

Hello I am trying to bind the NSManagedObjectContext of my NSArrayController later by code.
The controller gets loaded in the nib without a bound context. But I have a NSTableView bound to the array controller. I want the table to remain empty until I loaded some data into the context (and not show the old data in the context on launch). When I launch the app i get this error:
Cannot perform operation without a managed object context
Is this just not possible? Do I have to work around that or am I doing it wrong?
I thought the controller would return nil without a context.
Perhaps you would be better served programmatically binding the NSArrayController to the NSTableView once the context is populated appropriately?
Here's Apple documentation of the NSKeyValueBindingCreation informal protocol.

MonoTouch.Dialog: Dismissing a Keyboard

Using the Reflection API to auto generate a UI.
How can I dismiss the keyboard when the user selects a new field, or if they choose a field which generates a new view to pick from. In the later case, when the user returns to the first screen, the old keyboard is still there.
UIView.EndEditing(bool force);
The above will hide the keyboard for you without needing to know who the first responder is. I haven't done much with the reflection API but you should be able to call that on the view when an element is selected.
Apple Docs -- endEditing:
Clarification for those initially struggling with the MonoDialog portion of the question:
The EndEditing method is not available on DialogViewControllers objects directly (who inherit from UITableViewControllers). You should be calling EndEditing(bool) on the View of a DialogViewController and not trying to call EndEditing(bool) on the actual DialogViewController itself.
For clarification:
DialogViewController dc;
dc.View.EndEditing(true);
Note:
UIView objects include the EndEditing(bool) method, but UITableViewControllers do not inherit from UIView so the EndEditing method is not available on the controller itself. UITableViewControllers contain a view object, call EndEditing on that view object.
Check the ResignFirstResponder method. This one should help you I guess.

Getting UITabBarController to work with Core Data

I've been reading this thread on Stackoverflow and have been trying to replicate the solution with no success in my own project.
My project has 4 tabs. In my app delegate I do this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
Page1 *page1 = (Page1 *)[navController topViewController];
Page2 *page2 = (Page2 *)[navController topViewController];
Page3 *page3 = (Page3 *)[navController topViewController];
Page4 *page4 = (Page4 *)[navController topViewController];
page1.managedObjectContext = self.managedObjectContext;
page2.managedObjectContext = self.managedObjectContext;
page3.managedObjectContext = self.managedObjectContext;
page4.managedObjectContext = self.managedObjectContext;
[self.window makeKeyAndVisible];
return YES;
}
In the originating thread it says I need to create a IBOutlet to each navController for each tab I want to use Core data on.
Whilst you can assign multiple delegates for the UINavigationController the same is not true for the outlets, you can only ever supply ONE outlet for the navController.
I can get Page1 to work, but the other pages simply crash; because of the lack of an IBOutlet.
Do I really need X IBOutlets for Y Tabs or can I do it another way?
Another issue is that the originating thread the accepted answer is:
Ideally you want to pass either the
NSManagedObjectContext,
NSFetchedResultsController or the
relevant NSManagedObject "down" into
the UIViewController.
But there is no code or example of how to do this.
Ideally, I do not want to use a singelton or use the app delegate all over the place.
Any confirmation and clarification would be great.
Thanks.
Your immediate problem has nothing to do with Core Data. You are assigning the same navigation controller to each tab when you need a separate navigation controller for each tab otherwise the navigation controller's hierarchy of views will get scrambled every time you change tabs.
The pattern recommended in the question you linked to is called "dependency injection" and it is the one that Apple recommends in most cases. However, in the case of tabbars or any other complex view/view-controller hierarchy, dependency injection can get to complicated. It's a particular issue with tabbars because you don't usually load all tab view/view-controllers when the app starts but wait until each tab is selected before loading its elements.
Instead, you can use an alternative pattern that exploits the UIApplication objects singleton status. Since there is only one application object, there is only one application delegate object. That means that anywhere in the app you can make a call like this:
(MyApplicationDelegate *) appDelegate=(MyApplicationDelegate *)[[UIApplication sharedApplication] delegate];
... and always get the same application object. Then, if you have the managed object context defined as a property of the app delegate you can get the context just by:
theManagedObjectContext=appDelegate.managedObjectContext
Add these two lines to every view controller and you can always be sure of getting the app delegate's managed object context.

MVC basics: Should I add a UIViewController, a Delegate or a Source to my custom view?

my question is about view controllers, delegates and all that in general. I feel perfectly comfortable with UIView, UIViewController, Delegates and Sources, like UITableView does for instance. It all makes sense.
Now I have implemented my first real custom view. No XIBs involved. It is an autocomplete address picker very much like in the Mail application. It creates those blue buttons whenever a recipient is added and has all the keyboard support like the original.
It subclasses UIView. There is no controller, no delegate, no source. I wonder if I should have either one of those? Or all, to make it a clean implementation.
I just cannot put my finger on the sense a view controller would make in my case. My custom view acts much like a control and a UIButton doesn't have a controller either.
What would it control in my view's case?
Some of my thoughts:
For the source: currently the view has a property "PossibleAutocompleteRecipients" which contains the addresses it autocompletes. I guess this would be a candidate for a "source" implementation. But is that really worth it? I would rather pass the controller to the view and put the property into the controller.
The selected recipients can be retrieved using a "SelectedRecipients" property. But views should not store values, I learned. Where would that go? Into the controller?
What about all the properties like "AllowSelectionFromAddressBook"? Again, if I compare with UIButton, these properties are similar to the button's "Secure" property. So they are allowed to be in the view.
The delegate could have methods like "WillAddRecipient", "WillRemoveRecipient" and so on and the user could return TRUE/FALSE to prevent the action from happening. Correct?
Should I maybe inherit from UIControl in the first place and not from UIView?
And last but not least: my custom view rotates perfectly if the device is rotated. Why don't all views? Why do some need a controller which implements ShouldAutoRotateToDeviceOrientation()?
Does it make sense what I wrote above? In the end I will provide the source on my website because it took me some time to implement it and I would like to share it as I have not found a similar implementaion of the Mail-App-like autocomplete control in MonoTouch.
I just want to learn and understand as much as possible and include it in the source.
René
I can answer part of your question.
I just cannot put my finger on the
sense a view controller would make in
my case
The ViewController is responsible for handling the View's state transitions (load, appear, rotate, etc) These transitions are used mainly when you use a navigation component (UINavigationViewController, UITabBarController). These components needs to received a ViewController that will handles the view's transitions.
For exemple, when you push a ViewController on a UINavigationViewController, it will cause the ViewDidLoad, ViewWillAppear, ViewDidAppear. It will also cause the ViewWillDisappear, ViewDidDisappear of the current ViewController.
So, if your application has only one portrait view, you don't need a ViewController. You can add your custom view as a subview of the main window.

Resources