How to get NSString variable value from NSObject to ViewController - iphone

I am trying to set up an object to control all of my data so it can set things up in the background to it appears my tableviews load faster than they do now etc.
This is what I am trying to achieve.
I am setting a variable in the NSObject from the secondVC when the tableviewcell is selected like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//Access selected cells content (cell.textLabel.text)
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//Parent view logic (sends info back to the correct cell in parent view)
if (parentViewSelectedIndexPath.section == 0)
{
if (parentViewSelectedIndexPath.row == 0)
{
//Predicates restrict the values that will be returned from the query
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#",#"MANUFACTURER",cell.textLabel.text];
NSArray *filterArray = [myDataArray filteredArrayUsingPredicate:predicate];
//[[self delegate] setManufactureSearchFields:filterArray withIndexPath:indexPath]; //This is where I pass the value back to the mainview
//Using Object
VehicleControllerNSObject *vehicleControllerNSObject = [[VehicleControllerNSObject alloc] init];
[vehicleControllerNSObject setFirstCell:filterArray];
}
//etc
At the end there you can see the method that is getting set up in the VechicleControllerNSObject which looks like this.
-(void)setFirstCell:(NSArray *)array{
manufactureSearchObjectStringFVC = [[array valueForKey:#"MANUFACTURER"] objectAtIndex:0];
NSLog(#"%#", manufactureSearchObjectStringFVC); // this prints the correct value to the console
}
As you can see this prints the correct output fine.
however I have no idea how to call manufactureSearchObjectStringFVC and pass the value it holds into the uitableviewcell that I would like to pass it in on my firstviewcontroller.
This is what I have for testing atm.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
VehicleControllerNSObject *vehicleControllerNSObject = [[VehicleControllerNSObject alloc] init];
manufactureSearchObjectString = vehicleControllerNSObject.manufactureSearchObjectStringFVC;
NSLog(#"%#", vehicleControllerNSObject.manufactureSearchObjectStringFVC);
}
That nslog prints null..
I have three questions
1, how do I get the correct value into the first valuecontroller.
2, should I be using viewDidAppear like this?.. I think not.. how can I do this better
3, Do you think this is a good way of doing this type of thing, as in the future i would like to use the NSObjectClass to parse info, cache etc all behind the senses leaving the views to just display when the data is ready hopefully helping performance..
Any help would be hugely appreciated as I really want to learn this stuff as i know its important for me to know.

Your question is so beautifully and clearly formatted and diagrammed that it seems a shame to ask you to do a search. But here it is:
Search for Sharing Data between View Controllers
You'll find many good discussions about sharing data between view controllers.
Briefly, though, I can tell you why your code isn't working. In your tableView:didSelectRowAtIndexPath: method, you are creating (alloc/init) a new instance of your VehicleControllerNSObject class each time. Then back in your first view controller on viewDidAppear:, again you are creating (alloc/init) a whole new instance each time.
So you have multiple objects coming and going and they have nothing to do with each other. It's a bit like giving some important information to one person at a bus station and then later randomly picking some other person out and trying to retrieve that same information from her.
So one quick idea would be to create just once instance of your VehicleControllerNSObject (just an aside, that's a bit of a strange name for a class since generally all objective-c objects are descendants of NSObject anyway. I'm just going to call that VehicleController for now)
So let's say you wanted a 'sharedInstance' of VehicleController. You could add a class method to VehicleController to give you a way to easily get that one sharedInstance:
+(VehicleController*)sharedInstance {
static VehicleController *sharedInstance_ = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance_ = [[VehicleController alloc] init];
});
return sharedInstance_;
}
So to get that instance in methods in other classes you can just do something like :
VehicleController *sharedController = [VehicleController sharedInstance];
sharedController.someProperty = someValue;
// and then back in your first view controller, similarly:
VehicleController *sharedController = [VehicleController sharedInstance];
id someValue = sharedController.someProperty;
Again, check the search, many people have had good discussions on this. This is just one approach. I hope it at least makes sense why your code wasn't working.
Hope that helps.

To answer question 3. No.
I think that the best way to do something like this would be to use Core Data and it's NSManagedObject.
A combination of UITableViewController and NSFetchedResultsController that is feed from a Core Data sqlite backing store, if well set would feed and keep your UITableView updated.
It would be to long to describe all in here. So I will stop there.
If you don't want to go with that there is always the possibility to use a shared pointers to a mutable object or to use a singleton object to communicate information between UIViewController.

Related

Two variables with the same name in different objects altering each others' values

I have two UITableView objects that both have an array named sectionHeaders that is used as a reference object to provide, no surprise, the header names for a given section in the table. The first table view has it as an NSMutableArray and adds the headers dynamically as they are needed. The second view uses an NSArray and creates the array using the #[item1, item2, ...] shorthand. Both objects are declared as global instance variables.
The first table view creates the second and pushes it onto the navigation controller stack. The headers appear correctly the first time the former view is displayed, and they always display correctly whenever the latter view is displayed, but when I hit back to return to the first view, the section headers match those of the second view. This problem is immediately resolved by changing one of the two variable names, but I would much rather understand why the problem is happening in the first place.
Please let me know if any more information would be helpful. I have no concept of what might be causing this, so I'm not entirely sure what information could be useful.
Edit: Here's a simplified version of the way the two objects are set up and interact.
CalendarViewController.m:
NSMutableArray *sectionHeaders;
#implementation CalendarViewController
-(id) initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
sectionHeaders = [[NSMutableArray alloc] init];
}
//this is the method that adds items to the sectionHeaders object with irrelevant information excluded
-(void) distributeEvents {
[self.tableView beginUpdates];
if(condition1) {
if(![sectionHeaders containsObject:#"Today"]) {
[headers addObject:#"Today"];
}
}
else if(condition2) {
if(![sectionHeaders containsObject:#"Next week"]) {
[headers addObject:#"Next week"];
}
}
//et cetera...
}
//the only other time the sectionHeaders object comes up is in
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return sectionHeaders[section];
}
The second object, an EventViewController, is initialized when a cell is tapped. It is not created with any variables associated with the sectionHeaders object.
EventViewController.m:
NSArray *sectionHeaders;
#implementation EventViewController
//within the init method
sectionHeaders = #[#"What", #"When", #"Where"];
//later...
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return sectionHeaders[section];
}
That's all the references I make to those objects. I apologize for not having the simplified code in the question to begin with. Hopefully having more context will help.
From your code it appears that both sectionHeaders arrays are defined outside the scope of the corresponding classes and basically are two global variables with same name - in which case linker should have given you a warning.
I suggest you move them inside the class they belong to.

How to save nsdictionary of a subview to a mainview based off tableviewcell selection

I am currently parsing some xml that looks like this
<Rows>
<Row MANUFACTURERID="76" MANUFACTURERNAME="Fondont" ISMANU="F" ISAUTO="F"/>
<Row MANUFACTURERID="18" MANUFACTURERNAME="Anti" ISMANU="T" ISAUTO="T"/>
</Rows>
I parse it so that there is an array of dictionaries (each dictionary has the four values of the Row in it).
I then pass ManufacturerName to my startSortingTheArray method like this
if (dataSetToParse == #"ICMfg") // ICMfg is a string passed to this view from the parent view cell selection enabling me to pass different data sets to this view
{
//Filter results (ISAUTO = T)
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K like %#",#"ISAUTO",#"T"];
NSArray *filteredArray = [myDataArray filteredArrayUsingPredicate:predicate];
//Passes Manufacturer strigs over to startSortingtheArray method
[self startSortingTheArray:[filteredArray valueForKey:#"MANUFACTURER"]];
}
So from here all of the ManufacturerNames are sent to my method as an array of strings. I then use this array to set up all of my sections / index-scroller. The method below shows how I am doing this.
//method to sort array and split for use with uitableview Index
- (IBAction)startSortingTheArray:(NSArray *)arrayData
{
//If you need to sort incoming array alphabetically use this line of code
//TODO: Check values coming in for capital letters and spaces etc
sortedArray = [arrayData sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
//If you want the standard array use this code
//sortedArray = arrayData;
self.letterDictionary = [NSMutableDictionary dictionary];
sectionLetterArray = [[NSMutableArray alloc] init];
//Index scrolling Iterate over values for future use
for (NSString *value in sortedArray)
{
// Get the first letter and its associated array from the dictionary.
// If the dictionary does not exist create one and associate it with the letter.
NSString *firstLetter = [[value substringWithRange:NSMakeRange(0, 1)] uppercaseString]; //uppercaseString puts lowercase values with uppercase
NSMutableArray *arrayForLetter = [letterDictionary objectForKey:firstLetter];
if (arrayForLetter == nil)
{
arrayForLetter = [NSMutableArray array];
[letterDictionary setObject:arrayForLetter forKey:firstLetter];
[sectionLetterArray addObject:firstLetter]; // This will be used to set index scroller and section titles
}
// Add the value to the array for this letter
[arrayForLetter addObject:value];
}
//Reload data in table
[self.tableView reloadData];
}
from here I do several things to do with setting up the tableview after [self.tableView reloadData]; is called, The main thing being is that I set the cell up with the string values of the array.
//Display cells with data
NSArray *keys = [self.letterDictionary objectForKey:[self.sectionLetterArray objectAtIndex:indexPath.section]];
NSString *key = [keys objectAtIndex:indexPath.row];
cell.textLabel.text = key;
when the cell is then selected the string value inside the cell is then sent back to the main view and used later as a search parameter... The thing being is that I am setting up several parameters that will be used as one search string.
Looking back at the XML I parsed
<Rows>
<Row MANUFACTURERID="76" MANUFACTURERNAME="Fondont" ISMANU="F" ISAUTO="F"/>
<Row MANUFACTURERID="18" MANUFACTURERNAME="Anti" ISMANU="T" ISAUTO="T"/>
</Rows>
These are the values of columns inside an SQl table that has a keyvalue MANUFACTURERID that is also found in other tables that I parse. I would like to use these key values to restrict/refine other queries but I just cannot figure out how to pass them to my parentview where I set up all of the search parameters, that is my question how can I save the dictionary of values that is related to the users tableview selection from the subview. So that I can then pass one or some of those values back to the subview of a different dataset to restrict the information that is displayed dependent on the users previous selections.
This has taken me about an hour to type up. Hopefully it makes sense, I am still fairly new to iOS development and Objective C, and this concept is really pushing my capabilities and before I move on and end up hasing some crap together that I will have to fix later on I am hoping that one or some of you will be able to lend your experience in this type of this to me so I can get this right first time :)
If you need me to clarify anything or provide you more information that will help you help me just let me know.
Thanks in advance!
The common pattern for passing information backwards in your view controller hierarchy is to use delegation. You can achieve this in your scenario by implementing the following:
1) Define a protocol in the SearchParametersViewController, which represents your the parent view controller you mentioned.
#protocol SearchParametersViewControllerDelegate <NSObject>
#optional
- (void)searchOptionsSelected:(NSArray *)selectedSearchOptions;
#end
2) Conform to that protocol in your SearchOptionsSelectionViewController, which represents the table view controller that has a list of selections to choose from. Make sure to import or forward-declare the class the protocol is defined in (e.g. SearchParametersViewController) .
#import "SearchParametersViewController.h"
#interface SearchOptionsSelectionViewController <SearchParametersViewControllerDelegate>
3) Define a delegate property in your SearchOptionsSelectionViewController (assumes you are using ARC on iOS 5.0, 4.x use unsafe_unretained instead of weak. Use assign if the project is using manual memory management). This delegate object will contain a reference to your parent view controller (e.g. SearchParametersViewController). You do not want this property to be retained as to avoid retain cycles/circular references where one object references another, which in turn has a reference back to the first and neither object is ever deallocated.
#property (nonatomic, weak) id<SearchParametersViewControllerDelegate> delegate;
4) When instantiating the SearchOptionsSelectionViewController instance inside your parent view controller (SearchParametersViewController), set the delegate property to the parent view controller instance as represented by the self keyword. This ensures you can send the message (and corresponding data) backward in your view controller hierarchy, yet the object relationships remain loosely coupled. This delegate protocol could be conformed to in any other view controller, there are no tight relationships in the selection view controller back to the parent view controller, the only thing linking them is the flexible delegate protocol adoption by the selection view controller.
SearchOptionsSelectionViewController *selectionViewController = [[SearchOptionsSelectionViewController alloc] init];
selectionViewController.delegate = self;
5) Finally, in your SearchOptionsSelectionViewController table view's -tableView:didSelectRowAtIndexPath: delegate method, pass the data corresponding to the selected row back to your parent view controller (SearchParametersViewController) via the delegate method you defined in the SearchParametersViewControllerDelegate protocol. You must use the -respondsToSelector: method to ensure that the delegate object actually implements the -searchOptionsSelected: delegate method. To force this implementation, change #optional to #required above the method prototype in the protocol definition in step #1. self.someDataArray represents a the data source you are using with the selection table view controller. The specifics of the delegate protocol method and data object(s) sent back to the parent view controller can be changed, the important thing here is the delegation pattern and not having any tightly coupled relationships between the instances of either class, but especially backwards in the view controller hierarchy.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self.delegate respondsToSelector:#selector(searchOptionsSelected:)])
{
NSArray *selectedObjs = [NSArray arrayWithObject:[self.someDataArray objectAtIndex:indexPath.row]];
[self.delegate searchOptionsSelected:selectedObjs]
}
}
6) Implement the delegate method inside SearchOptionsSelectionViewController.m
- (void)searchOptionsSelected:(NSArray *)selectedSearchOptions
{
// do what you need to with selectedSearchOptions array
}
Further reading:
Cocoa Fundamentals Guide - Delegates and Data Sources
Cocoa Core Competencies - Protocol
You could use the application delegate to achieve your goals here.
I'm going to assume your app has a structure a bit like this. Please excuse the crudity of this model.
Application delegate (A) --> Search Options View (B) --> Table where you do selections (C)
|
|
--> Some other view where you need the selection (D)
Your problem is that you need information to flow from C to D.
Your application delegate has the merit of being universally accessible via [[UIApplication sharedApplication] delegate]. So you can get a pointer to it from anywhere. From C, you can send your selection information back to A. A can either send this on automatically to D, or D can request it from A whenever it wants it.
A couple of points:
I won't expand any further on my answer at the moment because it's beer o' clock here now, plus I might have misunderstood your requirement. If you do need anything else, I will be up at baby o' clock in the morning UK time so there might be some delay.
Some people frown on using the application delegate as a "data dump" in the way I have suggested. Some of those people would rather set up a whole singleton class and treat that as a data dump instead. It seems to be one of those neverending arguments so I try not to get involved.
You have a few options, one is to use user defaults. It might be the easiest.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html
Another is to post a notification with the information.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsnotificationcenter_Class/Reference/Reference.html

I'm having issues inputing a name if applicable

I have a function here that upon completing a single round, if your score is higher than either a default score entry or a newly placed high score then it will swap its data with your data and push everything else down. removing the last entry from the list. currently this is just one exchange and for functions sake I'm going to hard code it and then refactor it later.
My main problem is that when I set up a text input view to capture the players name execution continues immediately without the players input and crashes the game. I commented out the line that sets the text because I have a default value in place just in case any attempt that I try to make fails. How can I get Execution to wait for a moment while input is taken? Would I have to set up a delegate method? If so I'm still a bit confused by delegates. I could set it up to work but I don't understand it, so I wouldn't be able to do any other special custom tasks with it. I've worked on it for a while and got no further...
-(void)saveData:(ScoreKeep *)stats{
NSMutableDictionary *swap = [[NSMutableDictionary alloc]init];//used for swaping entries
NSString *filePath = [self pathOfFile];
NSLog(#"Writing to %#", filePath);
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSLog(#"Loading previous dictionary to save...");
dataDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
if ([dataDictionary objectForKey:#"1"]) {
NSMutableDictionary *highScore = [dataDictionary objectForKey:#"1"];
if ([stats.score intValue] > [[highScore objectForKey:#"SCORE"] intValue]) {
NSLog(#"You Win! score: %# highscore: %#", stats.score,[NSNumber numberWithInt:[[highScore objectForKey:#"SCORE"] intValue]] );
stats = [[ScoreKeep alloc] initWithNibName:#"Scorekeep" bundle:nil];
NSLog(#"Setting up name entry");
[self.view addSubview:stats.view]; //New view is added so that the player can input data(Assume it is complete);
//stats.nameTag = setName.nameTag;//This line is executed before the new view is dismissed causing an error to occur
[stats setupDictionary]; // It just goes down hill from here if the previous line is uncommented
[dataDictionary setObject:stats.sComponents forKey:#"1"];
}else {
NSLog(#"You Lose: %# highscore: %#", stats.score,[NSNumber numberWithInt:[[highScore objectForKey:#"SCORE"] intValue]] );
}
NSLog(#"Got first place entry");
}else {
NSLog(#"Initilizing Score");
}
}else{
NSLog(#"Creating new dictionary to save...");
dataDictionary = [[NSMutableDictionary alloc]init];
}
[dataDictionary writeToFile:filePath atomically:YES];
}
Help would greatly be appreciated. If more information is needed I'd be happy to provide.
by the way ScoreKeep is an object that contains a dictionary and a function to create a dictionary such that it can set any values I need and package them into sComponents(the dictionary to be entered into the main savefile)
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#class omphalosUtility;
#pragma mark -
#pragma mark Saving data
#pragma mark -
static inline void poop(){
NSLog(#"POOP");
}
I'm going to try making a utility file that works independently of the app so that I Can update files and perform other universal operations such as saving when needed. Its a step in a direction that i'd like to take.
If i get it right, (The code is really nasty, man...) your problem is that you are trying to present a View Controller with the wrong way.
Correct me if i'm wrong, is ScoreKeep is a ViewController? if so, you have to name it properly. that's for a start.
Second, you cant present another view controller only by adding its "view" property to the current view controller's View Hierarchy. that way the view will not respond properly to the events.
the correct way to to what you'r trying to do is by presenting the ScoreKeep ViewController modally.
there is no other right way to do this without using delegation. you will have to acquire this technique.
Your view controller that responsible for getting the name from the user need to have a way to tell it's master view controller that the user entered a name. and that is achieved through delegation.
What you should do:
Basically you create a protocol called something like "NamePrompterViewControllerDelegate"
that will have at least one method that will be called when the user will done entering his name.
Your ScoreKeepViewController should have an instance variable that implemented the protocol (Look at the apple documentation on protocols for assistance)
Your main view controller (the one that contains the method you added) then should implement the protocol you created, and set itself as the delegate of ScoreKeep like that:
stats = [[ScoreKeep alloc] initWithNibName:#"Scorekeep" bundle:nil];
stats.delegate = self;
For more info on presenting and dismissing ViewControllers modally you should read the documentation at Apple Documentation
I hope i helped you, there is just a lot to cover and it hardly can be done by writing an answer.
Feel free to ask more for clearance.

NSInvalidArgumentException: Illegal attempt to establish a relationship between objects in different contexts

I have an app based on the CoreDataBooks example that uses an addingManagedObjectContext to add an Ingredient to a Cocktail in order to undo the entire add. The CocktailsDetailViewController in turn calls a BrandPickerViewController to (optionally) set a brand name for a given ingredient. Cocktail, Ingredient and Brand are all NSManagedObjects. Cocktail requires at least one Ingredient (baseLiquor) to be set, so I create it when the Cocktail is created.
If I add the Cocktail in CocktailsAddViewController : CocktailsDetailViewController (merging into the Cocktail managed object context on save) without setting baseLiquor.brand, then it works to set the Brand from a picker (also stored in the Cocktails managed context) later from the CocktailsDetailViewController.
However, if I try to set baseLiquor.brand in CocktailsAddViewController, I get:
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason:
'Illegal attempt to establish a
relationship 'brand' between objects
in different contexts'
From this question I understand that the issue is that Brand is stored in the app's managedObjectContext and the newly added Ingredient and Cocktail are stored in addingManagedObjectContext, and that passing the ObjectID instead would avoid the crash.
What I don't get is how to implement the picker generically so that all of the Ingredients (baseLiquor, mixer, garnish, etc.) can be set during the add, as well as one-by-one from the CocktailsDetailViewController after the Cocktail has been created. In other words, following the CoreDataBooks example, where and when would the ObjectID be turned into the NSManagedObject from the parent MOC in both add and edit cases? -IPD
UPDATE - Here's the add method:
- (IBAction)addCocktail:(id)sender {
CocktailsAddViewController *addViewController = [[CocktailsAddViewController alloc] init];
addViewController.title = #"Add Cocktail";
addViewController.delegate = self;
// Create a new managed object context for the new book -- set its persistent store coordinator to the same as that from the fetched results controller's context.
NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] init];
self.addingManagedObjectContext = addingContext;
[addingContext release];
[addingManagedObjectContext setPersistentStoreCoordinator:[[fetchedResultsController managedObjectContext] persistentStoreCoordinator]];
Cocktail *newCocktail = (Cocktail *)[NSEntityDescription insertNewObjectForEntityForName:#"Cocktail" inManagedObjectContext:self.addingManagedObjectContext];
newCocktail.baseLiquor = (Ingredient *)[NSEntityDescription insertNewObjectForEntityForName:#"Ingredient" inManagedObjectContext:self.addingManagedObjectContext];
newCocktail.mixer = (Ingredient *)[NSEntityDescription insertNewObjectForEntityForName:#"Ingredient" inManagedObjectContext:self.addingManagedObjectContext];
newCocktail.volume = [NSNumber numberWithInt:0];
addViewController.cocktail = newCocktail;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addViewController];
[self.navigationController presentModalViewController:navController animated:YES];
[addViewController release];
[navController release];
}
and here's the site of the crash in the Brand picker (this NSFetchedResultsController is backed by the app delegate's managed object context:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
if ([delegate respondsToSelector:#selector(pickerViewController:didFinishWithBrand:forKeyPath:)])
{
[delegate pickerViewController:self
didFinishWithBrand:(Brand *)[fetchedResultsController objectAtIndexPath:indexPath]
forKeyPath:keyPath]; // 'keyPath' is #"baseLiquor.brand" in the crash
}
}
and finally the delegate implementation:
- (void)pickerViewController:(IngredientsPickerViewController *)pickerViewController
didFinishWithBrand:(Brand *)baseEntity
forKeyPath:(NSString *)keyPath
{
// set entity
[cocktail setValue:ingredient forKeyPath:keyPath];
// Save the changes.
NSError *error;
if (![cocktail.managedObjectContext save:&error]) {
// Update to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
exit(-1); // Fail
}
// dismiss picker
[self.navigationController popViewControllerAnimated:YES]
}
EVEN MORE
I'm making progess based on Marcus' suggestions -- I mapped the addingManagedObjectContexts to the parent managedObjectContext and wrapped everything in begin/endUndoGrouping to handle cancel vs. save.
However, the object to be created is in an NSFetchedResultsController, so when the user hits the "+" button to add the Cocktail, the (possibly-to-be-undone) entity briefly appears in the table view as the modal add view controller is presented. The MDN example is Mac-based so it doesn't touch on this UI behavior. What can I do to avoid this?
Sounds like you are creating two different Core Data stacks (NSManagedObjectContext, NSManagedObjectModel, and NSPersistentStoreCoordinator). What you want to do from the example is just create two NSManagedObjectContext instances pointing at the same NSPersistentStoreCoordinator. That will resolve this issue.
Think of the NSManagedObjectContext as a scratch pad. You can have as many as you want and if you throw it away before saving it, the data contained within it is gone. But they all save to the same place.
update
The CoreDataBooks is unfortunately a really terrible example. However, for your issue, I would suggest removing the creation of the additional context and see if the error occurs. Based on the code you posted and I assume the code you copied directly from Apple's example, the double context, while virtually useless, should work fine. Therefore I suspect there is something else at play.
Try using a single context and see if the issue persists. You may have some other interesting but subtle error that is giving you this error; perhaps a overrelease somewhere or something along those lines. But the first step is to remove the double context and see what happens.
update 2
If it is crashing even with a single MOC then your issue has nothing to do with the contexts. What is the error you are getting with a single MOC? When we solve that, then we will solve your entire issue.
As for a better solution, use NSUndoManager instead. That is what it is designed for. Apple REALLY should not be recommending multiple MOCs in their example.
I answered a question on here recently about using the NSUndoManager with Core Data but you can also look at some of my articles on the MDN for an example.
Yeah, you definitely don't want to cross context boundaries when setting relationships between objects; they both need to be in the same NSManagedObjectContext. In the old EOF, there were APIs for faulting objects into different contexts, but doesn't look like CoreData has an equivalent.

Three20: Make a TTTableItem link to a TTViewController

I want my table items to show the disclosure arrow and link to another "details" screen. Pretty standard. Three20 is supposed to help with this.
In my TTListDataSource, I'm currently doing:
- (void)tableViewDidLoadModel:(UITableView *)tableView
{
[super tableViewDidLoadModel:tableView];
// Construct an object that is suitable for the table view system
// from each domain object that we retrieve from the TTModel.
for (Listing *result in [(id<SearchResultsModel>)self.model results]) {
NSString *url = [NSString stringWithFormat:#"myapp://listing", result.theID];
TTTableSubtitleItem *item = [TTTableSubtitleItem itemWithText:result.title subtitle:result.desc imageURL:result.imageURL defaultImage:nil URL:url accessoryURL:nil];
[self.items addObject: item];
}
}
But I need to pass an object (not just a string) to the TTViewController when the TTTableItem is clicked. I know that you can pass an NSDictionary object to a
TTViewController using: TTNavigator's [[TTNavigator navigator] openURL: query: animated:] method.
However, since I'm trying to open this URL from a TTTableItem, I don't know how to use openURL method with it where I can pass a query NSDictionary object, since all it takes as an NSString "URL" parameter.
I read the discussion here however I'd really, really like to avoid having to modify the original Three20 code. If it can properly be extended, that would be fine.
What's the simplest way I can make my table item's open up a TTViewController and pass an object (such as an NSDictionary)?
If you look at http://three20.info/core/navigation they show you how to do this without overriding the didSelectObject method.
In a nutshell, you can assign a URL to an object (via a category for NSObject) which is mapped to a URL for the controller that is hosting the table. The handler can then open another URL passing the appropriate objects in the query dictionary.
From the Google Group...
http://groups.google.com/group/three20/msg/5cdbbaf753dc52a1