I was wondering if there is a way i could have a table view displayed on one view then when you hit the "add" button it would flip you to a second view where you would type in the name that you want the new cell's text label to say. Then you would hit a "done" button and it would flip you back to the first view where it would have the newest item. And you would be able to add however many cells you want.
Cocoa and Cocoa touch are based on an MVC pattern. What that means is there's separate layers each with responsibilities - the model, the view and the controller.
The model is the data and the operations on that data, the view is what you see and the controllers mediate between them.
So, in your example, you wouldn't add a cell from a different view. That violates the fundamental pattern. Instead, what would happen is the view where your adding the data would call to the model to add the item and the view would go away. Then, when it returns to the view that lists the items, it would query the model (which contains the new object) and the list would contain the object.
The two views are decoupled and they share the same model. It allows you to change interfaces and storage without breaking most of your app because they're decoupled.
For example, you could have a table view controller that gets it's list from querying your model class. Your model class could be a singleton ( [MyModel sharedInstance] ) that offers a method like:
NSArray* items = [model getItems];
That method could be backed by Sqlite (search for fmdb), CoreData storage, a simple file, or even in memory data like an NSMutableArray. Your UITableViewController implements the callback methods by calling into your model.
Then, you offer an Add button which calls this to modally show your AddItemController.
[self presentModalViewController:addItemController];
After the user supplies the data on the form and clicks the Done/Save button, you call your model to save the item which is a class with the data:
[[MyModel sharedInstance] saveItem:item];
That writes to your storage.
Then, upon return to your UITableViewController, in viewWillAppear, you re query the data and call for the table view to reloadData;
_items = [[MyModel sharedInstance] getItems];
[[self tableView] reloadData];
Now the table shows the data you just added.
There's other variations but that's a basic one with MVC separation.
I'd just like to add, putting this in plain words...
Whatever source that you use for your table to load cells from (an array, dictionary, class, you name it...) then you create the "add" button, make it push the new view controller, then when you press the "done" button on your navigation bar, add the object's property (the name text field info, or whatever you need) to the source you load your table view data from.
Related
I've got a user interface that looks pretty much like iTunes. For purposes of encapsulation, the top area and the main table view are in separate classes with separate nibs. I want to bind the search field from the top view controller to the tableview in the bottom view controller. I've arranged it so there are properties to store the NSArrayController in both classes. The array controller is an array of dictionaries, and the dictionaries have a "search_keywords" key that I want to use to filter the tableview.
Is it possible to set up the search stuff in Interface Builder even though it's in a separate nib? I can't figure out what to put in the various boxes.
If it's not possible with IB, I assume it's possible in code, since there is a view controller with references to both of the sub-view controllers and I can get at the search field, table view and array controller objects through properties on the two classes.
How do I set it up? IB would be best, if it's possible.
What I did was use the NSSearchField in the top view controller as a dummy/placeholder. I create the "real" search field in the tableview's nib, and wire up all the bindings stuff as per normal. Then in the main view controller I grab the search field out of the tableview's nib, and replace the dummy searchfield with the real one using replaceSubview:with:
Now I can continue to use IB to modify the bindings, and it doesn't really matter what's in what nib as it all gets placed properly in the view hierarchy at runtime.
In your concept you cannot bind the search field in IB in the desired way.
Do it like
1. Create an accessor-method (accessorMethodForTextInSearchField or what name you want to use) in the TopClass for the Text in the searchField
2. Import the TopClass.h in the MainClass
3. In MainClass you can use
NSString *searchString = [ NSString stringWithString:[ TopClass accessorMethodForTextInSearchField] ];
4. Now search for searchString in the array
Would it be possible (or advisable) to attempt to subclass a UITableView to have built-in search functionality?
There are two reasons I wanna do this:
Reuse: I could use the same subclass at multiple places in my project with different data-sources.
Cleaner code: It would de-clutter my view controller. All the plumbing for implementing search would be neatly incapsulated in the subclass implementation.
Any ideas how one would go about doing this?
Use UISearchDisplayController
From Apple doc,
A search display controller manages display of a search bar and a
table view that displays the results of a search of data managed by
another view controller.
You initialize a search display controller with a search bar and a
view controller responsible for managing the original content to be
searched. When the user starts a search, the search display controller
is responsible for superimposing the search interface over the
original view controller’s view and showing the search results. The
results are displayed in a table view that’s created by the search
display controller. In addition to the original view controller, there
are logically four other roles. These are typically all played by the
same object, often the original view controller itself.
It can be implemented as,
searchController = [[UISearchDisplayController alloc]
initWithSearchBar:searchBar contentsController:self];
searchController.delegate = self;
searchController.searchResultsDataSource = self;
searchController.searchResultsDelegate = self;
UISearchDisplayController itself encapsulate all the normal search features. If you want you can subclass it to achieve whatever you are planning to do. You can use this in any class.
I guess I should ask for clarification: do you want the user's search to simply scroll to a row in the table, or do you want it to filter the rows, displaying only rows that match the search term?
Assuming you want it to filter the rows...
It would be pretty complicated to make a UITableView subclass to do this, because you'd need to interpose your own private UITableViewDataSource and UITableViewDelegate in front of the “user” data source and delegate.
It also might be rather inefficient, depending on how you get the data for the table view. If the table view can have thousands of rows, and they come from (say) a SQLite database or Core Data, the data source can search more efficiently for matching rows. In the table view, you'd have no choice but to iterate through the rows one by one, checking each for a match. Or you'd have to extend the data source protocol to give the table view a way to pass the search string to the data source... which seems like it defeats the goal of putting the searching in the table view.
If you tell us more about where the data comes from for your various table views, we might be able to give you better advice.
I have two table views and a detail view being managed by a UINavigationController. When a row is selected on the second table, it pops to a detailed view allowing changes specific data represented by the row. I need to be able to switch between the UITableView and the UIViewController without losing any of the data that might have been changed in the UIViewControllers (button selections, text values entered in fields, etc).
Basically, once the UIViewController is presented, one should be able to switch back and forth between the table and detail view without losing any data.
The problem is, when a UIViewController is popped from the navigation controller, that memory is automatically released, and since I'm using ARC, I can't just keep a pointer to that with a retain command in the UITableView.
I know that I could manually rebuild the view each time its corresponding table row is selected, but I feel that might be a messy solution. Another option I've thought of is keeping an array of pushed UIViewControllers and checking if the selected table row corresponds with an existing value before a new one is created, but that might also get messy.
Any suggestions?
Your final wish in this back and forth of view is what you stated in your question: you want to switch between view controllers without losing any information of the actions performed in these controllers.
But if you think at how MVC pattern works, you should consider a view controller as the glue logic between the view and the model. The view is not persistent, that's why it is legitimate for ARC to get rid of the owning view controller when the view is no more needed. Instead what you should persist while your app is working is the model data only: the model data will be shared between the involved view controllers, the view controllers will be recreated each time and the corresponding views will be updated based on the model data. The only reason why the view controller should be kept alive is when its alloc-init-loadView takes too much (e.g.: the view is OpenGL backed) but in such case I would suggest you to keep a strong reference to it in the AppDelegate and ask it to refresh the content when the model data is replaced.
So basically what you should do is:
- select the table
- extract the model data associated to the table, including all information relevant for the view controller
- push the view controller; save all view modifications to the model
- when the view controller is popped, the model data will be returned only
- next time, when you push the view controller again, you will restore the model and re-init the view controller.
This approach is not complicated and gives you the possibility to structure the app in a clean way. Tomorrow you can change your view controller structure (that its view and the logic) without any impact in the communication with the other view controllers as this managed by the model passing only.
There are a couple of solutions to this, just like you suggested.
The array solution is highly inefficient because of memory issues.
The second solution you proposed is a lot more elegant. Just write your own init method in that view controller and init the view controller with data from a plist file
If I'm reading the question correctly, you've got a tableView and a detailView that are driven by the same model data. When changes to the model data are made in the detail view, you want those changes to persist.
If you update the model based on the state of the controls when the detail view is popped, then those changes will persist and the changes will be visible the next time you drill back down into the detail view.
You don't mention what form the table data takes, but let's assume it's an NSArray of NSMutableDictionaries. When you tap the row, the didSelectRowAtIndexPath: method will need to hand the dictionary from that array index to the detail view controller through a property on the detail controller. The detail view controller will update the dictionary values in the method that dismisses it.
The way to think of this is using the model-view-controller pattern. The table and detail view data is stored in the model; the views present the data; and the controllers are responsible for updating the model and navigating between views.
I've created a window that contains an NSSplitView in which case the right custom view has a view that I swap into at runtime. The custom view swapped in contains a NSTableView with data inside it. I have a search box in the main window of the application that I want to be able to constrain the rows of the table view with.
I have the code to do this and I know it works, but the code I have was tested with a search text box and table view that were on the same window scope. With the text search box now being in the main window and the table view being in a different custom view, I'm not sure how to get the text search box to call the relevant methods from the custom view's controller class, because I don't have direct access to these method anymore.
I'm sure this is a very beginner question, but any help would be appreciated. Thanks.
Have your main window controller pass the search query or filter predicate to a property of the content view controller.
You can give the main window controller a weak-referencing (assign) property that holds the current content view controller. Implement a custom setter that not only assigns to the backing instance variable, but also does the swap. That, any time it's time to do a swap, you simply say self.currentContentViewController = viewControllerToSwapIn, and when it's time to change the query/predicate, you pass it to self.currentContentViewController.searchQuery (having implemented the searchQuery property in the MainContentViewController class and made all your actual content-view controllers inherit from that class).
I am trying to re-call core-data in UITable using model view. I am in UITable in - (void)viewDidLoad method using getting some data from internet and setting them entities and showing them on UITable.It works normal ,but Now I am trying to use new addModel view and in this model view I can type user name in textfield and save it in person entity.But when model view disappears my table not updates,after re-lunching it updates but because of not running vievDidLoad again it doesn`t gets value form internet.
i thought that am I have to use some recursive function? But where must I put it?in UITable which function calls every time?
NSFetchedResultsController, the iPhone equivalent of NSArrayController, is probably what you need. As the docs say NSFetchedResultsController
optionally monitors changes to objects
in its associated managed object
context, and reports changes in the
results set to its delegate (see “The
Controller’s Delegate”).
so it should respond when you update an entity.