Pass core data entity variable between views - ios

I´m having trouble understanding how to use a core data entity variable between views, and for better understanding of what my issue is, my code is below:
View A:
At some point i´m doing this when a save button is pressed:
- (void)guardarOrcamento
{
newBudget=[NSEntityDescription insertNewObjectForEntityForName:#"Budget" inManagedObjectContext:context];
newBudget.relationshipBetweenEntityBudgetAndClient = myEntityClientVariable;
UIAlertView *saved = [[UIAlertView alloc]initWithTitle:#"Budget Saved" message:#"" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[saved show];
NSError *error;
[context save:&error])
}
View B:
My problem is in this view, i need to connect another relationship and for that, my "newBudget" variable most not be empty!:
- (void) setSelectedRowInTableview:(int)line
{
rowEntity=[NSEntityDescription insertNewObjectForEntityForName:#"rowEntity" inManagedObjectContext:context];
rowEntity.relationshipBetweenEntityRowEntityAndBudget = newBudget;
....
This RowEntity can only exist if Budget entity already exists...and at this point it does!...in the other view i have inserted a new object and saved it...and i understand why the variable "newBudget"(in view B) is empty, but how can i persist it?
Thanks for you time

Basically you have to pass either the full budget entity or the ID of the relevant budget entity from view "A" to view "B". Not knowing your app's view hierarchy and logic I assume you select a budget then add entities related to that budget.
Independently from the variable passing solution you have the choice whether you store the selected/inserted budget object in an NSManagedObject variable or store the ID of the budget object in NSManagedObjectID and then retrieve the object using -(NSManagedObject *)existingObjectWithID:(NSManagedObjectID *)objectID error:(NSError **)error.
1) using global variable
Setup in your AppDelegate a NSManagedObject/NSManagedObjectID, and make it accesable:
NSManagedObject *selectedBudgetReference; // OR
NSManagedObjectID *selectedBudgetReferenceID;
...
#property (strong, nonatomic) NSManagedObject *selectedBudgetReference;
#property (strong, nonatomic) NSManagedObjectID *selectedBudgetReferenceID;
Then store into the inserted/selected reference at view A:
AppDelegate *app = (AppDelegate*) [[UIApplication sharedApplication] delegate];
app.selectedBudgetReference = newBudget;
app.selectedBudgetReferenceID = [newBudget objectID];
Finally access it in view B:
AppDelegate *app = (AppDelegate*) [[UIApplication sharedApplication] delegate];
NSManagedObject *localBudgetToRelate = app.selectedBudgetReference;
NSManagedObject *localBudgetToRelate2 = [context existingObjectWithID:app.selectedBudgetReferenceID];
2) passing variable when user switches from view A to B
Similarly as above but you setup the object variable in form B (formBViewController) and when on form A and creating form B to switch to that view you basically access the form B's newly created view controller and pass the budget info to formBViewController's object variable.

Related

Custom TableViewCell with Core Data

I have a Destination View Controller that allows you to edit information displayed in the TableViewController..I am attempting to set this up in a custom cell..I have my UITableViewCell file with the custom property class and I also have my Model Class for the Core Data with the attributes. I managed to get my root table view controller to show the custom label when I add a NEW player but once I click on the cell and edit it in the new view controller it goes back to the default on the table view. I believe it has something to do with this code but I can not figure it out.
my NsManagedObject Subclass
#property (nonatomic, retain) NSString *playerFirstName;
I have a pointer to my Player Class of currentPlayer in my viewcontroller.h file and the firstnameTextfield is my UITextField
-(IBAction)doneEditing:(id)sender {
_currentPlayer.playerFirstName = firstnameTextField.text;
AppDelegate *myApp = (AppDelegate *) [[UIApplication sharedApplication]delegate]'
[myApp saveContext];
}
Update
I believe this is my line of code that is the problem after messing with it
_currentPlayer.playerFirstName = firstnameTextField.text;
how do I get the currentPlayer pointer to go to my playerNameCell property in my customcell class
You should do something like:
- (IBAction)newPlayer {
_currentPlayer = (Player*) [NSEntityDescription insertNewObjectForEntityForName:#"Player" inManagedObjectContext:_managedObjectContext];
}
The _managedObjectContext should be passed to the view controller from the app delegate or some other view controller.

A UIlabel issue: Keep the string value after app is closed?

So one of the users in here managed to show me how to pass data from a child view controller to a parent view controller via a string.
So now the string is passed, BUT, i want that value to stay displayed on the firstViewController after the app is closed and re-opened.
The value is saved in with NSUserDefaults by the way and with an NSLog i am seeing on the conosole it is saved in the apps folder but that value isnt saved onto the UILabel display.
It only displays it when i put save but then i close and reopen, it dissappears but in an NsLog it is still inside the app but not on display UILabel.
How can i address this ?
On my appDelegate.h i have a
#property (strong, nonatomic) NSString *sharedString;
To pass the secondViewController data to the firstViewController.
In the save method on my secondViewController i have a function related to the
AppDelegate.h declaration which is:
AppDelegate *apiDelegate = [[UIApplication sharedApplication] delegate]
apiDelegate.sharedString = self.textFieldData.text;
And in my firstViewController i have a method which display the data from the second
viewController:
-(void) viewDidAppear:(BOOL)animated {
AppDelegate *apiDelegate = [[UIApplication sharedApplication] delegate]
self.DisplayData.text = appDelegate.sharedString;
[super viewDidAppear: NO];
Is there something wrong which isnt keeping the data intact after app closes or am
I missing something here ?
So one of the users in here managed to show me how to pass data from a
child view controller to a parent view controller via a string.
First you need to establish some hierarchy as to how you get a childViewController from a parentViewController. One way to pass data from childViewController to parentViewController is using a delegate. The other could be using the KVC/KVO protocol. https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html
In this you can simply register an observer for the property defined in the childViewController and observe it's changes wherever you want (well, given the hierarchy is satisfied).
To save the value. You can simply save it using NSUserDefaults. I don't see any code in your post but you can simply define a key and save the value with NSUserDefaults using:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:sharedString forKey:#"sharedString"];
NSString *sharedStringFromDefaults = [defaults objectForKey:#"sharedString"];
Also,
AppDelegate *apiDelegate = [[UIApplication sharedApplication]
delegate]
Apple requires you to avoid such references in the application. It only constrains the app. Further, the sharedString is not required to be in the AppDelegate. Otherwise the AppDelegate will be filled with almost every other data structure you have shared in the app.
//add this code when you want to store string
[[NSUserDefaults standardUserDefaults] setObject:self.textFieldData.text forKey:#"sharedString"];
[[NSUserDefaults standardUserDefaults] synchronize];
//and when you want string than
self.DisplayData.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"sharedString"];

How do I access a Model Object from different viewControllers

I'm not sure if I'm taking the right approach to this, but I want to access my model for a Shopping Cart Class from different viewControllers. My first approach was to init a Cart * object in each viewController, but I think I just ended up with multiple cart objects when all I want is one that can be accessed globally. After searching I came up with a different approach that seems better, but no luck yet.
I have a button that is supposed to add a deal to a shopping cart. but when I try to add it, the method is not getting called. Here is how I have it set up.
In my Cart class I have a NSMutableArray to hold my deals.
In my viewController I set up a property of type Cart *cart and initialized like this
#property (strong, nonatomic) Cart *cart;
...
-(id)initWithModel:(Cart *)cart {
self = [super init];
if(self){
self.cart = cart;
}
return self;
}
Then my button method is this
-(IBAction)addDealToCart {
NSLog(#"The Cart has %i items", [self.cart qtyOfItemsInCart]);
NSLog(#"Added the Deal to the Cart");
[self.cart addDealsToCart:self.deal];
NSLog(#"The Cart now has %i items", [self.cart qtyOfItemsInCart]);
self.deal.qtyInCart = self.deal.qtyInCart + 1;
NSLog(#"the deal has %i items in the Cart", self.deal.qtyInCart);
}
In this line addDealsToCart:deal never gets called.
here is my addDealsToCart:deal method in my Cart Class
-(void)addDealsToCart:(Deals *)deal {
[self.cartContents addObject:deal];
NSLog(#"the deal was added to the cart %#",deal);
}
any help would be great. thanks
Without going for a whole re-architecturing, why don't you pass your cart object to each view controller? I personally wouldn't go the singleton route that your description hints of.
Update (example):
UIViewController *yourNextVC = [[YourNextVC alloc] init];
yourNextVC.cart = self.cart //The current cart in your current vc, passing it along.
[self presentViewController:yourNextVC animated:YES completion:nil];
I you just want one Cart variable througout the app you can have it in appDelegate if you want
#property (strong, nonatomic) Cart *cart;
And taking out is simple
AppDelegate *appDelegateObject=(AppDelegate*)[[UIApplication shareApplication] delegate];
appDelegateObject.cart.qtyOfItemsInCart= 1; //initialize where you want.
Take out in another view controller like this:
AppDelegate *appDelegateObject=(AppDelegate*)[[UIApplication shareApplication] delegate];
NSLog(#"cart value: %d,appDelegateObject.cart.qtyOfItemsInCart);

CoreData: Accessing the instance of NSManagedObject

I have 3 Scenes each collecting User's input. Each Scene has 5 UITextFields. The 4th Scene shows all the 15 Text Field in a UITableView.
I'm not sure if this is the best way to do do this, but I have the following code for scene 1:
//Meetings is NSManagedObject class. Meetings.h and .m was created from the Meetings entity from Core Data
//I have this code once in the file right before I start saving the data
Meetings *meetings = (Meetings *) [NSEntityDescription insertNewObjectForEntityForName:#"Meetings" inManagedObjectContext:self.managedObjectContext];
// I have similar code below for each user's input.
NSString *date = [[NSString alloc] initWithFormat:#"%#", [dateFormatter stringFromDate:selectedDate]];
DateLabel.text = date;
[meetings setDateLabel:date];
...
[meetings setTimeLabel:time];
..
//Code below is to save. I have this once at the end of the file to save the data
NSError *error = nil;
if (![managedObjectContext save:&error]) {
// Handle the error.
}
//The log below shows the saved data fine. Thus, the data is being saved in managnedObjectContext.
NSLog (#"This is the DateLabel %#", meetings.DateLabel);
Question: How do I access the pointer *meetings from Scene 2 and 3 to save rest of the fields in managedObjectContext? I did a NSLog from Scene 2 and it shows as Null:
//In Scene 2 viewDidLoad method I did the following to check:
self.managedObjectContext = [(STAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
Meetings *meetings = (Meetings *) [NSEntityDescription insertNewObjectForEntityForName:#"Meetings" inManagedObjectContext:self.managedObjectContext];
NSLog (#"This is the DateLabel from Scene 2 %#", meetings.DateLabel);
The log shows:
2013-02-11 18:04:05.447 MyApp[3505:c07] This is the DateLabel from Scene 2 (null)
You either need to pass a pointer to the Meetings object from the previous screens forward to the next by storing them in a property, or you can pass the object's id's and fetch them as needed for the final screen.
Assume the following is a reflection of your code. The class names may not be identical, but I think you will be able follow and change them as needed.
Scene 1 Header File:
//
// Scene1ViewController.h
// ... etc.
#import <UIKit/UIKit.h>
#import "Meetings.h"
#interface Scene1ViewController : UIViewController
#property (nonatomic, strong) Meetings *meetingsForScene1;
// ... etc.
#end
Scene 2 Header File:
//
// Scene2ViewController.h
// ... etc.
#import <UIKit/UIKit.h>
#import "Meetings.h"
#interface Scene2ViewController : UIViewController
#property (nonatomic, strong) Meetings *meetingsFromScene1;
#property (nonatomic, strong) Meetings *meetingsForScene2;
// ... etc.
#end
meetingsForScene2 may or may not be appropriate depending on your requirements. You might just add data from Scene2 to the meetingsFromScene1 and pass that instance on to the next scene.
Scene 1 Implementation's -prepareForSegue:sender::
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destinationViewController = segue.destinationViewController;
if ([segue.identifier isEqualToString:#"YourSegueIdentifierForTransistionFromScene1ToScene2"]) {
Scene2ViewController *scene2 = [destinationViewController isKindOfClass:[Scene2ViewController class]] ? (Scene2ViewController *)destinationViewController : nil;
NSAssert(scene2, #"scene2 should not be nil");
NSAssert(self.meetingsForScene1, #"self.meetingsForSecen1 should not be nil");
scene2.meetingsFromScene1 = self.meetingsForScene1;
}
}
Note you might have two properties on Scene2. One for the current scene's data and one for the previous scene's data. The important property is the one that holds the data from the previous scene. The -prepareForSegue:sender: method in Scene1 is an appropriate time to set Scene1's data to the property on Scene2.
I've included some NSAssert calls to do some checking. Consider removing those in your production code. Also, note the check when assigning *scene2. If your destination controller is not the right "kind", you'll find out right away.
I am not necessarily advocating this approach as the "best" for your problem, but this approach will at least provide a path to a solution, if not address the issue entirely.
Well, what you do in your viewDidLoad method is creating a new object in your NSManagedObjectContext instance.
What you should do is to make a fetch request for your previously created Meetings object.
Maybe you should read a tutorial about Core Data. The following is very easy to understand: http://www.raywenderlich.com/934/core-data-on-ios-5-tutorial-getting-started

Accessing properties of an object inside array of objects

I have a list of items showing up on a table view.
Every item has its properties such as name, pic, rank etc'.
My goal is, every time the user selects a row the item with its properties will be added to a new list.
I've created a new list called listOfBugs and because i want it to be global i've allocated and initialized it inside viewDidLoad. (Is that a proper thing to do?)
Here is my code:
MasterViewController.h
#interface MasterViewController : UITableViewController
{
NSMutableArray *listOfBugs;
}
#property (strong) NSMutableArray *bugs;
MasterViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
listOfBugs = [[NSMutableArray alloc]init];
self.title = #"Scary Bugs";
}
...
...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ScaryBugDoc *bug = [self.bugs objectAtIndex:indexPath.row];
UIAlertView *messageAlert = [[UIAlertView alloc]
initWithTitle:#"Row Selected" message:bug.data.title delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[messageAlert show];
[listOfBugs addObject:bug];
NSLog(#"this is %#",listOfBugs);
}
Using NSLog I can see that the objects are added:
ScaryBugs[1195:11303] this is <ScaryBugDoc: 0x75546e0>
2012-12-05 17:45:13.100
ScaryBugs[1195:11303] this is <ScaryBugDoc: 0x75546e0>
I have a few questions.
1.How can I access the properties of the objects inside of the array listOfBugs ?
Update: This worked for me:
NSLog(#"this is %#",((ScaryBugDoc *)[listOfBugs objectAtIndex:0]).data.title);
But I can't access the listOfBugs from another class.
I turned it into a property as suggested to make my life easier but still can't access it from another class.
For example in listOfBugsViewController.m return [_listOfBugs count]; will give me the error Use of undeclared identifier '_listOfBugs'
2.I want to be abale to populate a table view with the customized list, how can i do that?
After accomplishing that I would like to save the list as a plist and also add and remove objects from it at ease so I need to take that under consideration.
This is the code that I'm based on, I only made a few adjustments to create the new list
This is really two questions:
1) How do I make my property a public property which can be accessed by other classes?
You do this just like you did with your bugs property. Add this to your .h file:
#property (strong) NSMutableArray *newList;
Note that if you aren't using different threads, you can make it a little more efficient by using the nonatomic property as well (#property (nonatomic, strong)).
Once you do that, you don't need your iVar declaration because it will automatically be generated for you. (i.e. you can remove NSMutableArray *newList;.)
2) How do I access an object in an array?
Objects in an array are stored as an id object, meaning that it is a "generic" object. If you know what type of object is stored, then you need to tell the compiler what it is so that it knows what properties and methods are appropriate for that class. You do this by casting the variable to the proper type:
ScaryBugDoc *bug = (ScaryBugDoc *)[self.newList objectAtIndex:0];
Then, you can access the properties of the object, assuming that they are public (as covered in point 1 above) like this:
NSLog(#"this is %s", bug.data.tile);
Okay, so based from the comments, this should work:
Album* tempAlbum = [albumList objectAtIndex:i];
//now you can access album's properties
Song* tempSong = [album.songs objectAtIndex:j];
//now you can access song's properties
This can be simplified down to:
Song* someSong = [((Album)[albumList objectAtIndex:i]).songs objectAtIndex:j];
When returning an object from an NSArray, or a collection object like that it will return a generic id object. This will need to be typecasted to the expected object so you can access the right properties.

Resources