How should I add items to a list in Core Data now that xcode 4 changed the generated code? - iphone

I have a core data model with a parent item and child items under it. In Xcode 3, when I generated the NSManagedObjects for this, I had methods called addChildsObject object method on Parent, but this has gone away in Xcode 4 (see Xcode4: Different code generated for custom core data managed objects). My question is this: how should I be adding the children to the parent now? I really don't want to mess with the generated code, revert to using Xcode3, or add a category to Parent to bring back the missing methods. Is there an approved way, or did Apple just muck up the whole process?

After discovering and reviewing the documentation on Dynamically-Generated Accessor Methods, it appears that Apple still recommends using the now non-existent methods, so it would appear that they have just screwed up by removing them. There is, however, another recommended way of doing this:
NSMutableSet *children = [parent mutableSetValueForKey:#"child"];
[children addObject: child1];
[children removeObject: child2];
This is not fabulous, because it relies on an unchecked string name, but it's the only remaining recommended way to do this without custom implementations. Thanks a lot Apple!

Related

Modifications on objects in NSUserDefaults-bound NSArrayController not saving

In my project, I have an NSArrayController bound to save to a the application's standard defaults (NSUserDefaults). This in itself works perfectly - objects added are saved and restored as expected.
However, if I programmatically modify one of the NSMutableDictionaries contained in the NSArrayController's array, none of the changes are saved. Only values set with the creation of the dictionary seem to stick.
I suspect this is because simply calling setObject:forValue: on the dictionaries in the array doesn't notify the controller of changes, but I'm not sure. Am I doing something wrong?
UPDATE: I have since switched from NSMutableDictionary to a custom object that conforms to KVC (to the best of my knowledge - I'm using properties so that should be taken care of) as well as NSCoding. It can and does save and restore fine - it's just not consistent. It kinda saves whenever it feels like it instead of when I update a property.
Well, I ended up just writing my own controller responsible for loading and saving downloads to their own plist file. It saves when it's told to without fail, so the problem is solved.

How to Extract the information about UI elements during runtime of an iOS application?

Is there any way that one could extract the information about UI elements (of the UIView) from the application’s memory during runtime of an iOS application (iPhone). Like getting a reference to the current UIView element and find a way to enumerate all UI elements contained in that view and create an abstract graph of the UIView calls of the app dynamically?
Since it looks like you may be interested n some general suggestions, I'll give you this one: look at DCIntrospect (available on github, with good documentation).
With this open source software, you can examine any item in your UI that subclasses UIView. You can see its many properties in your console.
It is very easy to use. I tried it, and it was a very simple add to my application delegate. To enable it, you press the space bar on your keyboard.
Since it is open source, you can examine the code and see for yourself what UI element properties are available and even make changes yourself.
UIView comes with an undocumented function to do that: -recursiveDescription. It's not as pretty as DCIntrospect, but you don't have to add anything to your project. Simply do:
NSLog(#"%#", [view recursiveDescription]);
or you can call it from the debugger:
p [view recursiveDescription]
See Apple's Technical Note 2239 (scroll to the bottom) for more details, and other interesting debugging commands.

CoreData Relationships in two different ManagedObjectContexts

Warning: This is my first IPhone Application and I'm new to Objective C, therefore my question might be very basic.
Actually I have a conceptual problem:
I have a one to many relationship between my NSObjects Project and WorkTime (Project<-->>WorkTime). WorkTime has attributes like startDate, endDate, … and a relationship named project to the Project object.
On the UITableViewController subclass that shows my list of WorkTimes, I fetch the CoreData Model with a FetchedResultsController. When I create a new WorkTime, I use a second context and merge it with the "default" once, once the user has clicked on "save" on the drill-down View, like in the CoreDataBooks example from the Apple Documentation. That works well.
The problem starts when I set the relationship. Since the projects are in the “default” context, I can’t assign any project object to the project key in WorkTime, since they are in two different contexts.
So, should I copy all the projects into the “saving” context? Or should I use just one context for everything?
One problem that arises when I use only one context is that the tableview that shows the WorkTimes gets actualized when the user clicks on the addbutton (insertNewObjectForEntityForName). So the list grows right before it presents the new view controller (addWorkTimeDetail) in modalviewcontroller. And if the user clicks cancel in that detail view and decides not to save the WorkTime, I’d have to delete the newly created entity from the context. I don’t think this sounds the way to do it.
Suggestions would be very appreciated!
UPDATE
I'm still having some issues:
When the AddWorkTimeViewController is created from the RootViewController, I create a new NSObject WorkTime. When the user clicks "cancel" I delete the newly created WorkTime and return to the RootViewController. The FetchedResultsController actualizes the tableView and I see a short animation that comes because the object has been deleted. That's doesn't look nice.
I know it would be better to create the object ONLY if the user clicks "save" and by "cancel" do nothing, but I need that object in order to populate the drilldown views with values. The drilldown views work with a NSManagedObject. I see two possible ways to solve this:
1) Have a temporary object TempWorkTime subclassed from NSObject with the same attributes from the WorkTime NSManagedObject. I would create the TempWorkTime in the AddWorkTimeViewController and use it for the drilldown views. I would of course have to subclass them to accept an NSObject instead of a NSManagedObject. I guess type casting wouldn't work. When the user clicks "save", I would create a WorkTime NSManagedObject and pass it the values from the TempWorkTime.
2) Is it possible to trick the FetchedResultsController so that it doesn't update itself while the tableView is not visible? In that case, it would not respond to the changes in the context until it's back in view, and so it would not do the delete animation.
Any suggestions?
SECOND UPDATE - maybe it's useful for people trying to do this same thing
I found this link which proved to be very helpful:
http://www.timisted.net/blog/archive/multiple-managed-object-contexts-with-core-data/
It's very well explained why it's sometimes a good idea to use two contexts. I had some problems with using one context explained in the UPDATE part of my question.
Now I'm using two contexts and it works perfectly, even with relationships. Important is to use the NSManagedObjects of the second context when creating the relationship. That was my mistake when I started to work with this approach.
I don't see why you use two different contexts.
The way to do it is to pass your tableView's context to addWorkTimeDetail, and add any new WorkTimes to that context. If the user cancels, i.e. doesn't create a new object, there will be nothing new in the list when you return. If the user creates the new WorkTime in the context it was passed, it will show up in the list when you return.
In your example, use only one context, and pass it along to your subviews.
I found this link which proved to be very helpful:
http://www.timisted.net/blog/archive/multiple-managed-object-contexts-with-core-data/
It's very well explained why it's sometimes a good idea to use two contexts. I had some problems with using one context explained in the UPDATE part of my question.
Now I'm using two contexts and it works perfectly, even with relationships. Important is to use the NSManagedObjects of the second context when creating the relationship. That was my mistake when I started to work with this approach.

What is the three20 method of passing objects between view controllers?

I have a basic RSS Reader I made from three20 tutorials using TTLauncherView as a menu to different feeds and TTTableViewController to show the feed list.
However, I am stuck at the point where from the feed list I click to view the feed item details. I use TTTableImageItem to display my feed items and I'm clueless as to how I am to use the URL variable in said TTTableImageItem to pass objects to the view controller showing the feed item.
I did some searching and I am lead to think that this cannot be done except via TTURLRequest, which leaves me even more confused.
Most of my code is adapted from IOSGuys tutorial, which uses a custom data source, data model and parser. I have tried making the data source and data model a singleton but to no avail and I'm unsure if that's even the best way to proceed for something as (presumably) simple as this.
Ideally I intend to pass the entire array of feed items with another argument for the index so that I can make use of UIPageControl to swipe between feeds when I'm at a more in-depth view.
Much help is appreciated! I have been spending too long looming around already!
The usual way of doing this is to have some sort of global singleton Data Manager class that manages the data models through Core Data, In-Memory Stores or other ways. Each model would have some sort of unique identifier. Doing it this way lends itself to a URL only stack needed to recover your navigation history without having to write state out to file in order to restore. You also can bring up any page in the app at any place with only a single URL. Using a URL scheme only then becomes trivial as you can do something like:
yourapp://blogs/jd82kd9
and have the blog view controller's init method contact the Data Manager for the blog with the unique identifier of jd82kd9
In your navigator's mappings, you would have something like this:
[map from:#"yourapp://blogs/(initWithBlogID:)") toViewController:[MyBlogViewController class]];
and then the initWithBlogID method would have the signature:
- (id)initWithBlogID:(NSString *)blogID;
see also Three20 : how to pass a class of objects between 2 views

Three20 + Core Data Simple Example

I've combed through SO, the Google group, and the blog-o-sphere trying to find an example of how to get the Three20 library to work with Core Data, and have not found much to speak of.
Does anyone here know where I could find a simple tutorial (or be willing to post one) on how to work with Core Data entities and Three20? Maybe something like:
I have an Core Data entity called Book which has the String attributes title and description. How would I create a simple app that would open with a table view showing a listing of all books, and when a row is touched push a view onto the nav controller that displays the selected book object's attributes? (just an idea -- anything that shows how to work with Core Data / Three20 would be much appreciated)
Thanks!
Core Data and Three20 won't have any specific implementation. They are tools that you can use to achieve the specific implementation yourself. You use Three20 to display the data you have in Core Data.
I suggest you dump Three20 and learn the basics of programming a standard table view controller first. You can see the very basics of a Core Data driven table view controller by simply creating a new iPhone app in Xcode and selecting "Use Core Data for storage".
The template code will point you in the right direction at least and should help you grok MVC a bit better which will help you with a Three20 implementation. Meanwhile, you should also look into using mogenerator+xmo'd. It's the only way to fly when it comes to creating custom managed objects.
When in doubt, consult the master and ask specific Core Data questions here on SO.
As far as I know (Three20 documentation is sparse), there is no automatic way for Three20 to work with Core Data.
What I typically do is:
get the set of entities from Core Data
load the relevant data (from the entities) onto a TTTableViewDataSource (e.g. TTSectionedDataSource) in a TTTableViewController
voila!
There is probably a more dynamic way to do this by implementing a TTTableViewDataSource subclass and letting it collect/manage the entities, but I don't think it's worth the effort.
(Prior to loading your entities onto your datasource in Three20, you need to convert them into table items, because a datasource is not exactly a datasource in Three20).
e.g.
[TTSectionedDataSource dataSourceWithObjects:
#"", // section header
[TTTableTextItem itemWithText:#"An item" URL:#"http://www.facebook.com"],
[TTTableSummaryItem itemWithText:#"Another item"],
nil];
Update: I don't think that you can pass your entities directly to a detail view through a Three20 URL scheme (though there is a generic object mechanism). You can pass your object as part of an NSDictionary through the query parameter.
e.g. You can have a mapping such as
[map from:#"example://bookDetails/(initWithName:)" toViewController:[BookDetailsController class]];
and a method definition like this
- (id) initWithName:(NSString *)theName query:(NSDictionary *)query
You can use this to push the detail view controller
// navigationURLString = #"example://bookDatails/Alice in WonderLand" (in URL encoding)
[self.navigationController pushViewController:[[TTNavigator navigator]
viewControllerForURL:navigationURLString query:dictionaryWithEntity] animated:YES];
Alternatively, you can pass the pertinent data through as arguments in the init call or just the entity's primary key and fetch the object again inside the detail view controller.
There is now a branch of three20 - CoreDataSupport - that supports using a NSFetchedResultsController. There you will find a NSFetchedResultsDataSource.