I am working on a simple core data app that uses a tableview and a detail view. I am getting the error message stating that the property managedObjectContext is not found in the object type ChildrenTVC. The problem is that it really is there. I have cleaned the project and deleted the derived data. There must be something else going on.
Here is the code for the object header:
#interface ChildrenTVC : CoreDataTableViewController <AddChildTVCDelegate>
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#end
and the code for the implementation file:
#import "ChildrenTVC.h"
#implementation ChildrenTVC
#synthesize managedObjectContext = _managedObjectContext;
#synthesize fetchedResultsController = _fetchedResultsController;
Here is the app delegate file where the error registers:
#import "AppDelegate.h"
#import "ChildrenTVC.h"
#implementation AppDelegate
#synthesize window = _window;
#synthesize managedObjectContext = __managedObjectContext;
#synthesize managedObjectModel = __managedObjectModel;
#synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: ( NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
ChildrenTVC *controller = (ChildrenTVC *)navigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
The error is at the controller.managedObjectContext. A lot of this is boilerplate code so there is not much to it. I just can't figure out why it is not seeing the property for the managed object context. The property is in the code.
UPdate:
I ended up recreating the file entirely. I am not sure what references are still in place when a file is changed, but something was pointing to the wrong file. I had to empty the trash to get the new file work properly. It seems to work now, though. All the research I did ended up revealing that there are some things that are unexplained in Xcode.
I had solved this issue by entirely recreating the header file, but I never really understood why it happened. What I did not understand then were the effects of the changes that I had made to the app. The real problem was an issue in the sequence that the header files were imported. I had changed the #import in two implementation files and that caused the compiler to not read one of the header files. I could see that the code was there, but the compiler could not read the code because it was not importing it. That gave way to the error I was receiving. My solution simply reversed the change that I had made. It would more easily have been solved by simply removing the #import of the view controller header file on the app delegate. I recently tested this and it was the correct solution.
You are type casting the navigationController.topViewController but i assume it isn't one in reality. Try this
ChildrenTVC *controller = [[ChildrenTVC alloc] init];
NSArray *vcArray = NSArray *vcArray = [NSArray arrayWithObject:controller]:
[self.window.rootViewController setViewControllers:vcArray animated:NO];
What happens if you make following changes to ChildrenTVC.h
#interface ChildrenTVC : CoreDataTableViewController <AddChildTVCDelegate>
{
NSManagedObjectContext *managedObjectContext;
NSFetchedResultsController *fetchedResultsController;
}
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
#end
Related
Ok. I have a big problem. I recently downloaded FRLayeredNavigationController using Cocoapods. Before using it and simply using the UINavigationController, everything was working fine. Now its just a big mess. This is what I have after running the application:
This is my code:
AppDelegate.h
#import <UIKit/UIKit.h>
#import "FRLayeredNavigationController/FRLayeredNavigation.h"
#interface TasksAppDelegate : UIResponder <UIApplicationDelegate>
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#property (strong, nonatomic) UINavigationController *navigationController;
#property (strong, nonatomic) FRLayeredNavigationController *layeredNavigationController;
#property (strong, nonatomic) UIWindow *window;
#end
AppDelegate.m
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
ToDoTableViewController *tableViewController = [[ToDoTableViewController alloc]init];
self.layeredNavigationController = [[FRLayeredNavigationController alloc]initWithRootViewController:tableViewController];
tableViewController.managedObjectContext = self.managedObjectContext;
self.window.rootViewController = self.layeredNavigationController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
In my console I am getting the following:
DEBUG: self: 'ToDoTableViewController: 0x9537600', self.parentViewController: '(null)'
So basically what I can tell is that either for some reason FRLayeredNavigationController is not being created, or that the managed object context is not being created. I have no idea why. Literally if I change the FRLayeredNavigationController to UINavigationController, everything works fine >.>
If it makes any difference, TableViewController is not a UITableViewController, but rather a UIViewController with a tableView inside of it.
The ToDoTableViewController is not getting generated here. ManagedContext does not seem to be causing this. In your ToDoTableViewController do you have a property named 'parentViewController' which you are trying to access ?
Because of your breakpoint: Maybe check for random breakpoints in Xcode: Press ⌘+6 in Xcode to see all breakpoints. The log message however comes from a known limitation in FRLayeredNavigationController: You cannot use self.layeredNavigationItem (or someViewController.layeredNavigationItem) until the view controller (self or someViewController) is actually pushed onto the screen.
FRLayeredNavigationController's documentation on layeredNavigationItem mentions that:
Warning: This property is nil until the view controller is shown on the screen. To configure the FRLayeredNavigationItem before appearing on the screen use the following methods:
[FRLayeredNavigationController initWithRootViewController:configuration:]
[FRLayeredNavigationController pushViewController:inFrontOf:maximumWidth:animated:configuration:]
The reason for that (I'm the developer of FRLayeredNavigationController) is that layeredNavigationItem is implemented by walking the view controller hierarchy and before the view controller is pushed, it's not in the hierarchy at all. Therefore, parentViewController is nil.
I'm hoping someone can shed some light on my question below.
I'm getting a property delegate not found on object of type viewcontroller error on when I declare the delegate in the parent view:
Here's the relevant code in the parent .h file:
#protocol ModalViewDelegate
- (void)didReceiveFrequencyMessage:(NSString *)message;
#end
#interface jhsManageRemindersViewController : UIViewController<UIAlertViewDelegate, UINavigationControllerDelegate, ModalViewDelegate>
and here's where I call the child view:
jhsScheduleViewController *jhsScheduleController = [[jhsScheduleViewController alloc]
initWithNibName:#"jhsScheduleViewControllerr" bundle:nil];
jhsScheduleController.delegate = self;
// Create the navigation controller and present it modally.
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:jhsScheduleController];
navigationController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:navigationController animated:YES];
and here's part of my child .h file
#protocol ModalViewDelegate ;
#interface jhsScheduleViewController : UIViewController {
//id<ModalViewDelegate> delegate;
// __unsafe_unretained id <ModalViewDelegate> _delegate;
__weak id <ModalViewDelegate> delegate;
NSMutableString *message;
}
#property ( weak) id<ModalViewDelegate> delegate;
//#property (nonatomic, weak) id<ModalViewDelegate> delegate;
#property (nonatomic, retain) NSMutableString *message;
and finally, here's my .m usage
#synthesize delegate;
//#synthesize delegate = _delegate;
I've viewed and tried various solutions based upon Stackoverflow questions and this recommended blogpost. I've included some of my attempted solutions in commented out code, just as an FYI.
I started with the code I had in an iOS4 app but that generates the error. As a footnote, this is an app with a TabBarController and a NavigationController
Can someone tell me how to fix this so the delegate error can be resolved?
Thank you for your help!
Well, I'm not sure what the problem was. But as a last resort, I saved every file, then tried to build it, with Xcode still reporting the error, which worked.
Actually, there was an error in the initWithNibName but it ran fine until it got to that point, and correcting the typo fixed that. Again, I'm not sure what the problem was but I seem to be on my way.
I have my ViewController.h/m and another class Keyboard.h/m.
In my ViewController.h I have an UILabel:
#interface ViewController : UIViewController{
UILabel *label;
}
#property (nonatomic, retain) IBOutlet UILabel *label;
and my ViewController.m looks so
#import "ViewController.h"
#synthesize label;
...
Now I want to change the label from Keyboard.m.
I have tried something like this:
#import "ViewController.h"
...
ViewController *vc;
vc.label.text = #"text";
it compiles without any errors but the label doesn't change
It's very error prone that you're doing here.
ViewController *vc;
declares a pointer, but this won't be initialized; so when you're accessing its property vc.label.text, objc_messageSend() will be passed a bogus pointer, so it can potentially crash! (you're lucky if id didn't do so.)
Anyways: if you have done it well, like ViewController *vc = [[ViewController alloc] init]; creating a new instance wouldn't have affected the other instance. You have to store the pointer to your instance somewhere, e. g. set a #property (retain) ViewContrller *vc; to your application's app delegate object, and access it through that property like this:
[(MyAppDelegate *)[[UIApplication sharedApplication] delegate] vc].label.text = #"new text";
that way it should work.
Hope it helps.
How are you initiating your vc variable? I am guessing that is where the error is coming from. Try doing:
vc = [[ViewController alloc] initWithNibName:# ViewController"];
If you are already doing that, make sure your IBOutlet is hooked up correctly. You are setting the variable correctly so the error must be coming from somewhere else.
I´m completely new to core data programming. i just try to find out where the best place for implementing the core data code would be. i´ve done the apple tutorial Locations and it worked well. now i try to transfer that to my current project what is a bit more complex.
the Locations tutorial shows one RootViewController including a programmatically generated tableView. my project is based on a tabView template. it owns a MainWindow.xib including the TabBarController including three ViewController (MapView, ListView, SettingsView) where each view has it´s own navigationController and xib-file.
The first stumbling block was changing the code that it will run with a xib for the tableView instead of creating it programmatically. I´ve managed that but there is still one error. I can´t connect the managedObjectContext from the appDelegate to the listViewController. I´ve tried the examples and suggestions for that issue from this forum here. but it still doesn´t work.
after looking at the CoreDataBooks sample project i´ve seen that the core data code was implemented in the RootViewController as well. Seems that it would be the wrong way to implement it in the ListViewController. But i don´t have a RootViewController in my project. In the AppDelegate i directly pass the tabBarController as the rootViewController. therefore i don´t know how to reach the listViewController to set the context like it was done in the Locations sample.
As the MapView is the first view i can´t set the context in the appDelegate. And after struggling a long time with the managedObjectContext i wonder if it would be better to invent a RootViewController to be able to place additional code there. the model should be accessible by all three views and it seems that the RootViewController is the right place.
But how do i combine that with a tabBarController which includes three more viewControllers based on xib-files? Could somebody recommend me examples or tutrials including core data based on a tab bar app?
Please read the following article by Marcus Zarra: Passing around a NSManagedObjectContext on iOS. That should give you an idea how to solve your problem.
In general you should add a NSManagedObjectContext property to all of your ViewControllers and pass the context before adding them to the view stack via pushViewController:animated:. You should not take the context from your app delegate.
If you pass a single NSManagedObject to a ViewController, e.g. to present a kind of detail view, you can access the context from that object, as every NSManagedObject knows about the NSManagedObjectContext it is "living" in.
If you are a registered iOS developer, I'd also recommend the WWDC 2010 and 2011 videos. There are some sessions about mastering Core Data.
ok, now i have the correct solution. it took a while to understand but now it works with dependency injection from application delegate into the view controllers (listViewController).
my problem was that i didn´t know how to reference my view controllers as they are nested into dedicated navControllers and one tabBarController.
after reading a lot of postings here i understood i have to declare my view controllers in the appDelegate.h and synthesize them in appDelegate.m and after that connect them to the appropirate item in IB. that was done fast & easy after understanding :-)
there is no rootViewController needed.
MyAppDelegate.h:
#import <UIKit/UIKit.h>
#import "ListViewController.h"
#interface MyAppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
IBOutlet ListViewController *listViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#property (nonatomic, retain) IBOutlet ListViewController *listViewController;
#property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
#end
MyAppDelegate.m:
#import "MyAppDelegate.h"
#import "ListViewController.h"
#implementation MyAppDelegate
#synthesize window=_window;
#synthesize tabBarController=_tabBarController;
#synthesize managedObjectContext=__managedObjectContext;
#synthesize managedObjectModel=__managedObjectModel;
#synthesize persistentStoreCoordinator=__persistentStoreCoordinator;
#synthesize listViewController;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// Handle the error.
}
// Pass the managed object context to the view controller.
listViewController.managedObjectContext = context;
// Override point for customization after application launch.
// Add the tab bar controller's current view as a subview of the window
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:NO];
return YES;
}
...
ListViewController.h
#import <CoreLocation/CoreLocation.h>
#interface ListViewController : UITableViewController <CLLocationManagerDelegate> {
UINavigationController *navController;
NSManagedObjectContext *managedObjectContext;
}
#property (nonatomic, retain) IBOutlet UINavigationController *navController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
-(NSManagedObjectContext *)managedObjectContext;
#end
ListViewController.m
#import "MyAppDelegate.h"
#import "ListViewController.h"
#implementation ListViewController
#synthesize navController;
#synthesize managedObjectContext;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"managedObjectContext: %#",[self managedObjectContext]);
NSError *error = nil;
if (![managedObjectContext save:&error]) {
NSLog(#"error: %#",[self managedObjectContext]);
return;
}
...
I've coded an app like that some time ago. The way I've solved it is I made a singleton which had a persistentStoreCoordinator property like the one in Apple documentation to hold the access to the database (so I don't have to write it every time). Then in every tab bar view controller I've initiated its own NSManagedObjectContext.
NSPersistentStoreCoordinator *coordinator = [[Singleton sharedSingleton] persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator: coordinator];
}
That way every controller approaches the database with it's own context, if you understand what I mean.
Please note that if any of your view controllers has a detail view controller, take the standard approach of passing the managed object context to it like in sample code (Books, Locations, Recipes).
i just fixed the bug. i missed out some methods necessary in the appDelegate. it works now if i put following code into viewDidLoad of my ListViewController
if (managedObjectContext == nil) {
NSLog(#"managedObjectContext is nil");
managedObjectContext = [(IntraAppAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
is that OK concerning proper MVC pattern rules? in my case the ViewController takes the context from the appDelegate now.
trying to set the context in the appDelegate with something like that throws an error:
NSManagedObjectContext *context = [self managedObjectContext];
if (!context) {
// Handle the error.
}
// Pass the managed object context to the view controller.
self.tabBarController.listViewController.navController.managedObjectContext = context;
self.window.rootViewController = self.tabBarController;
how can i gather the reference of other viewControllers which are controlled by the tabBarController and are not the topView/superView after app start? the first view is the MapView. do i have to instantiate or declare the listViewController in appDelegate? how must it be coded that it referes to the listViewController controlled by the tabBarController?
Im new to using core data and having really basic problems. Im trying to have the user enter a string and then be able to save that string and allow it to be returned to them at some point. But i cannot seem to get it to save. In fact the program quits when I attempt to run the following method. I can post the rest of my project, but i thought maybe that would be annoying so let me know if seeing it in greater detail would help. Thanks so much.
James
.h: file
#import <UIKit/UIKit.h>
#import "People.h"
#class rootViewController;
#interface data : UIView <UITextFieldDelegate>{
rootViewController *viewController;
UITextField *firstName;
UITextField *lastName;
UITextField *phone;
UIButton *saveButton;
NSMutableDictionary *savedData;
//Used for Core Data.
NSManagedObjectContext *managedObjectContext;
NSMutableArray *peopleArray;
}
#property (nonatomic, assign) rootViewController *viewController;
#property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, retain) NSMutableArray *eventArray;
- (id)initWithFrame:(CGRect)frame viewController:(rootViewController *)aController;
- (void)setUpTextFields;
- (void)saveAndReturn:(id)sender;
- (void)fetchRecords;
#end
.m file:
-(void)saveAndReturn:(id)sender{
People *userEnteredName = (People *)[NSEntityDescription insertNewObjectForEntityForName:#"People" inManagedObjectContext:managedObjectContext];
[userEnteredName setName:firstName.text];
//NSError *error;
//if (![managedObjectContext save:&error]) {
// This is a serious error saying the record could not be saved.
// Advise the user to restart the application
//}
[peopleArray insertObject:userEnteredName atIndex:0];
}
From the error you gave you must have named the People object differently - in the model are you using "People" for both class and entity name (those can be the same)?
Edit:
After reviewing your code, you had multiple problems:
1) In the app delegate you did "[data alloc]" but no init. That was where you set the managed object context, but it was never used... not just because of the lack of an init but because...
2) The place where the data controller was really built and used from was the rootViewController. That's the one that is actually doing all the work, the one in the app delegate is just discarded.
3) So where to get the context then? Honestly the best spot is in the data controller, one fix I know worked was putting this line before every time the context was accessed:
#import "UserProfileAppDelegate.h"
// Then in the method before the use of context........
self.managedObjectContext = [((UserProfileAppDelegate *)[[UIApplication sharedApplication] delegate]) managedObjectContext];
When that was in place, the project ran. I think though you should put that into something like a viewDidLoad on the data controller (if it has a view that is ever used).