Using a single view for multiple NSManagedObjects - iphone

So I have a couple properties that are common across several of my Core Data entities. Notes, URL, etc.
I have a single view controller for editing this information, and I pass the Entity to it as a NSManagedObject
#property (nonatomic, retain) NSManagedObject *editedObject;
#property (nonatomic, retain) Thing *thing;
#property (nonatomic, assign, getter=isEditingThing) BOOL editingThing;
And to actually get the object in a state I could make changes I would
if([editedObject isKindOfClass:[Thing class]]) {
thing = (Thing *)editedObject;
editingThing = YES;
}
That way I can set the values on thing and save the managedObjectContext like normal.
However, this is crashing my application, but only if I enter and exit the View Controller for editing the field over and over again.
Which brings me to my question: What's the best way to handle using a single view controller to edit a common field on more than one Core Data Entity? Should I just set the Boolean and populate the correct entity property when I call the View Controller?

I imagine your thing property is not getting retained because you're not using your accessor to set it. Change:
thing = (Thing *)editedObject;
to:
[self setThing:editedObject];
As to your bigger question, I think you need to provide more context. What do you mean by "edit a common field on more than one Core Data Entity"?

If both entities have a property called notes then change your property:
#property (nonatomic, retain) id managedObject;
Then when you go to set it, you can just set it without caring what the object is:
[[self managedObject] setNotes:...];
As long as whatever you set managedObject to responds to the property notes it will work just fine. If not, it will error out and you can test that easily.
You could go a more paranoid route and test if it responds first:
if ([[self managedObject] respondsToSelector:#selector(notes)]) {
but that is over protective since the only thing you would want to do that point is crash anyway.

Related

How to add an object to a NSMutableArray that is stored in a CoreData iOS database?

I have an NSManagedObject subclass where absences is an NSMutableArray
#interface Record : NSManagedObject
#property (nonatomic, retain) id absences;
#end
I want to be able to add items to the absences array; however, if I do [myRecord.absences addObject:SomeObj the record does not save properly. It almost appears that the NSManagedObject does not know that I updated the absences array.
Nevertheless, if I add SomeObj to some localAray, then set myRecord.absences = localArray, the NSManagedObject saves correctly.
Can someone explain this behaviour and how I might avoid it...thanks
You're exactly right, in the first case you're changing an object outside of NSManagedObject field of view. To solve this, Apple doc says the following
For mutable values, you should either transfer ownership of the value to Core Data, or implement custom accessor methods to always perform a copy.
So declaring your property with (copy) should suffice.

Programmatically add attributes to Core Data

I am developing a application that uses core data. In my application i would like every user to have the same database. So i want all of the devices to share the same core data objects.
In order to do that 'synchronization' I found a presentation on this answer that discussed this matter. In the presentation, it is suggested that I add attributes such as 'creationDate' and 'modificationDate' to every object in Core Data.
So to do that, i tried to subclass NSManagedObject (MyManagedObject) in order to add those properties to every object in core data. I also made every NSManagedObject subclass I had (generated automatically by the model) subclass MyManagedObject.
The problem is that the properties I added to the NSManagedObject subclass do not persist in the database. So when I close and reopen the application, 'creationDate' becomes (null).
Here's some of my code (header):
#interface MyManagedObject : NSManagedObject
#property (nonatomic, retain) NSDate * modificationDate;
#property (nonatomic, retain) NSDate * creationDate;
#end
And here's the .m file:
#implementation MyManagedObject
#synthesize modificationDate, creationDate;
-(void)willSave {
[super willSave];
self.modificationDate = [NSDate date];
}
-(void)awakeFromInsert {
[super awakeFromInsert];
[self setCreationDate:[NSDate date]];
[self setModificationDate:[NSDate date]];
}
Any help, directions or reading would be greatly appreciated. I have been struggling with this for a while now. I need a better way than adding these attributes to EVERY single entity in the model. Thanks in advance
PS: i intend to have a 'truth database' (a .sqlite file) in a server. The synchronization will be between the server and the iPhone. Such as suggested in the presentation
If you create MyManagedObject in the data model design tool and also register it as the parent of other entities inside that tool, this should almost work. (I suspect you didn't do that because of the #synthesize statement...those would usually be #dynamic.)
The one other problem to fix is that you have to test whether you've already changed an object's property (self.modificationDate in your case) before changing it again or else willSave continues to get called. A BOOL value that gets set after the first change and cleared in didSave is a simple thing to test.

releasing object created in getter and setter

I have some doubt regarding retain in .h file. I know that if we alloc/copy/retain than we need to release it, but in following case
#property (nonatomic, retain) IBOutlet UITableView *myTable;
Do I need to release this table view object in my dealloc. I have created this tableview using xib.
Thanks.
So sayeth the docs:
Objects in the nib file are created with a retain count of 1 and then
autoreleased. As it rebuilds the object hierarchy, however, UIKit
reestablishes connections between the objects using the
setValue:forKey: method, which uses the available setter method or
retains the object by default if no setter method is available. If you
define outlets for nib-file objects, you should always define a setter
method (or declared property) for accessing that outlet. Setter
methods for outlets should retain their values, and setter methods for
outlets containing top-level objects must retain their values to
prevent them from being deallocated.
And:
When a low-memory warning occurs, the UIViewController class purges
its views if it knows it can reload or recreate them again later. If
this happens, it also calls the viewDidUnload method to give your code
a chance to relinquish ownership of any objects that are associated
with your view hierarchy, including objects loaded with the nib file,
objects created in your viewDidLoad method, and objects created lazily
at runtime and added to the view hierarchy. Typically, if your view
controller contains outlets (properties or raw variables that contain
the IBOutlet keyword), you should use the viewDidUnload method to
relinquish ownership of those outlets or any other view-related data
that you no longer need.
So basically, when being loaded from a NIB/XIB, the property is used. Meaning, if you specify retain properties on your IBOutlets (which you should), you need to release them. The preferred way to do this is in viewDidUnload, using the property.
#property (nonatomic, retain) IBOutlet UITableView *myTable;
...
- (void) viewDidUnload
{
self.myTable = nil;
}
Yes you will have to as you would be creating an object in the .h file and allocating it memory.. The only thing you are doing in XIB is creating a link between the two (XIB just acts as an outlet for the inner tableview) , but if you posted a button using the xib and did not link it via the code then you don't have to release it...
First of all you are not retaining anything in .h file.
The purpose of #property declaration in the .h file (it can also be don in .m file) is to tell the compiler how to handle the getters and setters for this property when you use (dot syntax).
Example:
Declaring property in the following way:
#property (nonatomic, retain) IBOutlet UITableView *myTable;
Tells the compiler that when you create a UITableView in your .m file like so:
- (id)initWithTable:(UITableView *)table
{
self = [super init];
if (self) {
self.myTable = table;
}
return self;
}
Compiler will automatically know to retain it, and so you would also need to release it.
But if you would declare your property in the following way:
#property (nonatomic, assign) IBOutlet UITableView *myTable;
and created the tableView as in the previous example
- (id)initWithTable:(UITableView *)table
{
self = [super init];
if (self) {
self.myTable = table;
}
return self;
}
The compiler would only assing the value of myTable to point to table. You would not own it and should not release it.
No u dont need to
u only need to release object which you have allocated.
since the table view is allocate in the xib it's release should be none of your concern
hope this helps
it should be release. if you want to see difference then run your application in instruments and check it.

Three20: How to access the model in the next ViewController?

The Situation
I populate my TTTableViewController with a TTListDatasource(with TTModel).
My didSelectObject methods opens a TTViewController.
The Question
I d like to show more informationen in the TTViewController.
1.Question: Should i hand over the datasource (and run a new query) or should i hand over a specific VO (with all information)?
2.Question: How do I acces the datasour in the new TTViewController?
thanks,
In your TTTableViewController's didSelectRowAtIndexPath: definition, use your TTListDatasource to grab a reference to the corresponding object. Then pass it to your TTViewController. This is best accomplished by using a property of the TTViewController so that you don't have to worry about retain/releasing'ing.
#property (nonatomic, retain) TTModel *model;
and then in the didSelectRowAtIndexPath:
TTModel *model = //get the correct model
TTViewController *vc = [[TTViewController alloc] initHoweverYouWant];
vc.model = mode;
A few tips: TTViewController doesn't sound terribly descriptive, since you're (correctly) prefixing your classes. Maybe TTPhotoViewController or something may be more descriptive. Always err on the side of verbosity :)
Additionally, I find it pretty useful to just have my UITableViewController subclass implement the UITableViewDataSource protocol instead of creating a separate object, unless the exact same datasource is going to be used elsewhere for the exact same reason. This works more nicely with NSFetchedResultsController if you're using core data, as well.

How to share an array between two classes?

I want an array that gets data from one class to be avaliable to me in another class with the same data.
If we declare an array on the applicationDelegate class.
Then declare an object of applicationDelegate in both classes.
And assign the array into appDelegate.array from one class, will i be able get the array across the classes?
I'm with Mike. Leave the App Delegate out of it.
You're in control of when and how your objects are instantiated. If it's important for more than one class to have access to the same data, hand off the data, or a means of getting at your data, as you create instances of the dependent class.
An example, given classes WVParent and WVChild.
WVParent has a property, someArray, which is the array your other objects need:
#interface WVParent : NSObject {
NSArray *someArray
}
#property (nonatomic, retain) NSArray *someArray;
#end
Then you have WVChild, which itself has a property called parentObject:
#class WVParent;
#interface WVChild : NSObject {
WVParent *parentObject;
}
#property (nonatomic, assign) WVParent *parentObject;
#end
Assuming the parent is creating the child instance, you'd allocate it and assign the parent:
WVChild *child = [[WVChild alloc] init];
child.parentObject = self;
Then the child instance can access someArray by:
self.parentObject.someArray
This is just one option. You could also just pass the array itself to the child, assuming the data is static and unlikely to change over the course of the application session.
This way, instead of having a source of data living somewhere in the App Delegate, it lives within a class more appropriately responsible for its creation, maintenance and vending. If you've got a class that pops into existence and can only reach the rest of your app by getting the app delegate, you might want to put a little more thought into your architecture.
More on dependency injection here:
http://en.wikipedia.org/wiki/Dependency_injection
Yes, you could declare a member/property on your applicationDelegate class, although you should try to follow the Single Responsibility Principle and make sure you don't end up stuffing lots of miscellaneous shared stuff in your app delegate (which happens a lot with iPhone code).
Another alternative would be to inject the array into the objects' constructors when you create them.
It's hard to know the best solution in terms of design without knowing what this data is and where it really belongs.