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

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

Related

iPhone MVC Question on table views and structuring custom class models

I have been reading a lot about MVC these days and I think I have my head around it but I would appreciate some advice and informed opinions on how to best approach my problem.
I have 3 questions really all related to the MVC design pattern.
In many of the examples I have encountered people have used the contoller (say of a Table view) to populate an array with objects of a custom class (say Student.h/m).
But shouldn't the Student class have methods that are called that would return an array of data for the variable in the controller? Isn't that how the MVC works? That the model holds the definition of the data and takes responsibility for reading and writing it?
In many table view examples, in the various books I have read, they all say, "for convenience we are going to make the controller our delegate and data source for the table". I have yet to see an example where table view does not use the controller as a data source. How would you hook up a table view to a different data source?
I have 2 model classes "mission" and "airfield". Each one of these needs data from a XML file in the cloud. Do I write the parser in the mission/airfield implementation files? Do I create a separate Parser object? Should these models retun data to the controller as an array?
Whilst I understand a lot of the theory a lot of the examples I find on the web seem to break a lot of the concepts I thought I understood.
Any explanations would be most welcome. The quality of responses on this site are amazing.
Thanks in advance
You seem to already have a pretty good understanding of how MVC works, so I'll just add a few comments.
The controller is responsible for feeding data to the view.
There could be a million different states and scenarios that would affect what data to use and how, and it's not the model's job to figure that out. The model holds the data, and the controller handles the logic.
If you need a different delegate or data source for your table view, you can instantiate them in the table view controller, and then tell the table view about them using the delegate and dataSource properties. They need to implement the required methods of the UITableViewDelegate and UITableViewDataSource protocols.
Sometimes models and controllers overlap in functionality, and this is a perfect example of such a case.
One solution could be to let the mission and airfield classes inherit from a custom class that knows how to download the required XML and set up a parser, so they just need to provide the URL and override the parser callbacks for their specific tags. Everything else related to downloading the XML could be handled in the super class.
Another way could be to create a separate class that takes a URL and returns some XML, and then the mission and airfield classes call that method and parse the XML independently.
The wrong way is to let both the mission and airfield classes know how to download and parse, because you'd have to maintain the code in both places.
It's OK to have a data loading controller, that hands over the data to the view controller, so the controller code can be very specific (and maintainable).

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.

Data driven UITableViewController implementations?

I have a UITableViewController which is starting to get a bit crazy with all the switch statements for each UITableView delegate.
Does anyone have any suggestions or examples of more of a data driven implementation for a UITableViewController? I'm thinking some type of data structure which would hold references of where to go to get cells for certain section/rows, where to get the section names, etc.
I think the More iPhone Development book describes something like this, just wanted to poll the community and see if anyone had some lessons learned on their own implementation.
I don't think there is a standard one that is generally suitable for everyone, but it's not too hard to whip up your own to suit the needs of your application. Basically, you want an array/list of sections, and for each section, an array/list of items. For each item, you'll want to allow specification of an image, text, detail text, and some sort of action to be fired upon selection.
If you want to get fancy, you can specify background colors, fonts, and other such things for each section heading, section footer, and item.
If your list items don't all look the same, then your tableView:cellForIndex: implementation needs to be smart enough to use different reuse identifiers for different-looking items.
A nice thing about this approach is that you can often use the same view and same controller for many "screens".
Consider using Core Data and NSFetchedResultsController.
Core Data's NSFetchedResultsController will do most of the data work for you. It might be overkill if your model is simple or not persisted though.

Question regarding iPhone core data and how to duplicate features for multiple users...that doesn't make sense, just read my question :)

So I am working on a simple iPhone app, that uses core data to manage objects. My code is similar in function to Apple's CoreDataBooks app, found here. There is a blank UITableViewCell, and you have the ability to add objects to this blank list. If you hit the add button, a DetailViewController pops up that manages the attribute of each object. In the coredatabooks example, the app is like a library, and you can add book objects. My question is about how I might go about making it so that multiple users can have their own separate list of these objects. Again, relating back to coredatabooks, you would be able to make different library objects whose attributes are the book objects themselves. So using the convenient and easy to use coredata ui, would it be very hard to set it up so that in the UITableView, there was Library-A and Library-B and then selecting one of the libraries would move me to a screen that has the list of different books unique to that specific library? If you then select a book, you would then be able to view that book's attributes as before. So I guess my question is regarding how to put another RootViewController-esque view in front of the native one. As you may gather from this post I am in the learning stage of iPhone development, so I don't even know if logically this is even feasible or the correct way to do it. Any help/insight on this matter would be greatly appreciated! Thanks for your patience!
Create another UITableViewController (.h, .m, .xib files). And you can put some functionality into that view controller for adding library.
You can set that viewcontroller as startup object from MainWindow=.xib file. OPen that xib file -> expand navigation controller -> click on root view controller.
then in attributes window you can select your new controller as startup. you have to also set startup class from identity window.
Ruchir is correct, you can add another table view and controller. You will have to make some adjustments so that it is loaded and displayed first.
Also, it sounds like you will want to create a new entity in your data model for a Library which should have a to-many relationship with the Book entity.
Library <-->> Book
The new table view controller can use a fetched results controller that fetches Library entities. When the user chooses a row, you can set a property on the books table view controller before you push it on the navigation stack. Then use a predicate on the books fetched results controller to only fetch books in that library.

Where to store "global" data in Eclipse RCP Application?

I'm a beginner with Eclipse RCP and I'm trying to build an application for myself to give it a go. I'm confused about how one actually goes about handling model objects. None of the examples I can find deal with the problem I'm having, so I suspect I'm going about it the wrong way.
Say I need to initialise the application with a class that holds authenticated user info. I used my WorkbenchWindowAdvisor (wrong place?) to perform some initialisation (e.g. authentication) to decide what view to show. Once that's done, a view is shown. Now, that view also needs access to the user info I had earlier retrieved/produced.
The question is, how is that view supposed to get that data? The view is wired up in the plugin.xml. I don't see any way I can give the data to the view. So I assume the view has to retrieve it somehow. But what's the proper place for it to retrieve it from? I thought of putting static variables in the IApplication implementation, but that felt wrong. Any advice or pointers much appreciated. Thanks.
The problem you are facing here is in my opinion not RCP related. Its more an architectural problem. Your view is wired with business logicand!
The solution can be done by two (common) design-patterns:
Model-View-Controler (MVC)
Model-View-Presenter (MVP)
You can find plenty information about this in the web. I am going to point a possible solution for your particular problem using MVP.
You will need to create several projects. One is of course an RCP plugin, lets call it rcp.view. Now you create another one, which doesnt make UI contributions (only org.eclipse.core.runtime to start with) and call it rcp.presenter. To simplify things, this plugin will also be the model for now.
Next steps:
Add the rcp.presenter to the
dependencies of rcp.view (its
important that the presenter has no
reference to the view)
Export all packages that you are
going to create in the rcp.presenter
so they are visible
In rcp.presenter create an interface
IPerspective that has some methods
like (showLogiDialog(), showAdministratorViews(User user), showStandardViews(User user))
Create a class PerspectivePresenter that takes IPerspective in the constructor and saves it in an attribute
In rcp.view go to your Perspective, implement your interface IPerspective, and in the constructor create a new reference presenter = new PerspectivePresenter(this)
call presenter.load() and implenent
this in the presenter maybe like this
code:
public void load()
{
User user = view.showLoginDialog(); // returns a user with the provided name/pw
user.login(); // login to system/database
if(user.isAdministrator())
view.showAdministratorViews(user);
else
view.showStandardViews(user);
}
As you can see, the view just creates a reference to the presenter, which is responsible for all the business logic, and the presenter tells the view what to display. So in your Perspective you implement those interface functions and in each one you can set up your Perspective in a different way.
For each View it goes in the same way, you will need a presenter for the view which performs operations and tells the view (using the interface) what to display and passing down the final data. The view doesnt care about the logic. This is also very usefull when using JFace-Databindings (then only bound data is passed to the view).
For example, the WorkbenchWindowAdisor will just create everything that is needed in the application. Other views, perspectives, then can enable/disable menus and so on depending on the data they got (like when isAdministrator you might want to enable an special adminMenu).
I know this is quite a heavy approach, but the Eclipse RCP is designed for big (as the name says rich) applications. So you should spend some time in the right architecture. My first RCP app was like you described...I never knew where to store things and how to handle all the references. At my work I learned about MVP (and I am still learning). It takes a while to understand the concept but its worth it.
You might want to look at my second post at this question to get another idea on how you could structure your plugins.