tableView and normal view (same data object) - ios

I don't know how I can share the same data between two tab bar items.
One tab uses nsfetchedresultscontroller and the other table is just a normal view that should use the same data as my fetchedresultscontroller.
If i had two normals views, I would just make my object a singleton, and let the tableview and normal view use the same data.
But now i have a fetchresultscontroller and a normal view. I was thinking about just using another fetchedresultscontroller for my normal view, so I have all the features such as fetch cache, notifications and such..
I know fetchresultscontroller should be used for tableview, but I guess I can use it for non tableviews as well.
Somebody knows what it is I should do? I couldn't find documentation from apple on this matter.

Your data should have noting to do with your viewControllers or views - that is, if you follow the MVC style. If your data is only available in one viewController and you don't want to extract it out into its own class, then provide methods in your viewController that can be called by the other viewController to get the data.
For example, have methods like this:
- (NSString) getNameOfSelectedUserAtIndex:(int) index;
- (int) getCountOfSelectedUsers;
- (NSSArray) getResults;
And then from within your other viewController, call:
string = [fetchedresultscontroller getNameOfSelectedUserAtIndex:i];
count = [fetchedresultscontroller getCountOfSelectedUsers];
array = [fetchedresultscontroller getResults];
You have to make sure you add fetchedresultscontroller as an instance variable to your other
viewController and set it probably in its viewDidLoad.

Related

iOS 8: Best approach: Multiple UICollectionView in master detail format & singleton data source

I have two UICollectionViews C1 & C2 in a master detail layout on an iPad app. C1 is master collection view and displays primary data. When one taps on a cell in C1 then C2 will be updated and shows all objects information including the primary object information already being shown on C1.
Is it possible to have a single data source for both the collection views?
I thought out below given design for the data source
#protocol MyDataSourceDelegate <NSObject>
#optional
//Below method is called to notify collection view that a new object is added to the data source and so it must update its UI
- (void)didInsertItemAtIndexPath:(NSIndexPath*)indexPath;
//Below method is called to notify collection view that an existing object is removed from the data source and so it must update its UI
- (void)didRemoveItemAtIndexPath:(NSIndexPath*)indexPath;
#end
#interface MyDataSource : NSObject
#property(nonatomic,strong)NSArray *fetchedObjects;//main objects array
#property(nonatomic,strong)NSArray *masterObjects;//array of objects displayed in master collectionview
#property(nonatomic,strong)NSArray *detailObjects;//array of objects displayed in detail collection view in multiple sections.
//called from within collection view when a cell is tapped
- (void)selectItemAtIndexPath:(NSIndexPath*)indexPath isMasterData:(BOOL)isMaster;
//call when a collectionview cell needs information for a particular cell's contents
- (id)itemAtIndexPath:(NSIndexPath*)indexPath isMasterData:(BOOL)isMaster;
- (id)itemAtSection:(NSInteger)section isMasterData:(BOOL)isMaster;
#end
The problem with above implementation is that I want to keep data manipulation related work completely out of view controller hosting above two collection views so as to avoid bloating and same data source for both collection views. In above scenario how delegation will work between collectionviews and MyDataSourceDelegate protocol? As per my understanding delegation is a 1-1 relationships so how a single data source can be managed between two collection view?
A data source is a very handy way to pass information around your application and can handle pretty much every class you choose to implement within your project. I use a data source mainly to handle a core data model, but I also use it for other things (passing around custom methods,etc).
I recently was using a data source for two tableview controllers, and this did cause some problems. However, if you keep your data separate in your data source for each collection view you should be okay. It WILL get harry when you start passing around properties (especially your arrays) between the controllers and the data source. You can run the risk of mutating your data.
A teacher of mine once said that the best programmers write the least amount of code. But if you find your data getting mutated, or you aren't getting the results back that you need, you may just need to implement it within your controller temporarily. Get it working and then decide the best way to move it to your data source. You might also consider creating similar properties for your arrays in each controller to store the information from your data source. You might be okay with immutable arrays, but if you're going to be manipulating the data you'll want to store it in a new property.
Consider the scenario below. I'm going to use the *fetchedObject array for my example.
DataSource.h
#interface DataSource : NSObject
+(instancetype) sharedInstance;
#property (nonatomic, strong) NSArray *fetchedObjectsC1;
#property (nonatomic, strong) NSArray *fetchedObjectsC2;
#property(nonatomic,strong)NSArray *masterObjects;
#property(nonatomic,strong)NSArray *detailObjects;
Consider creating separate instances that are designated for each collection view.
DataSource.m
+(instancetype) sharedInstance{
static dispatch_once_t once;
static id sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (void) fetchCoreData{
//set up fetch
self.fetchedObjectsC1 = [NSArray arrayWithArray:[self.fetchedResultsController fetchedObjects]];
self.fetchedObjectsC2 = [NSArray arrayWithArray:[self.fetchedResultsController fetchedObjects]];
}
Now you have two separate instances populated with the same data. One for C1 and one for C2. This is how you would call them in a different class.
[DataSource sharedInstance].fetchedObjectsC1;
[DataSource sharedInstance].fetchedObjectsC2;
Consider a scenario where you're trying to populate two separate tableviews/collection views with the same instance of NSArray from your data source. When you start to implement canEditRowAtIndexPath: and other methods that manipulate your table view's data, you're also going to effect the functionality of the other collection view. Especially if you're saving/fetching from core data throughout this process. This will often result in a crash.
Based on the info that I have this is the best I could do, let me know if this doesn't work for you, and we'll work something else out. Don't forget to add your singleton to the data source and make sure its public.

How to have 2 tableview in one view controller with 1 tableview being dependent to the other

I'm in the process of creating an app that needs to have 2 TableViews that is linked to core data. The first table View is the Parent tableview wherein the user needs to select it before the 2nd table view populates with the associated data. I've been looking at examples and solutions but I came upon an issue with the FetchRequest Controller. how will it know which table to query?
I saw an example here but its not that complete. or at least, It did not gave a complete detail as to how to set the 2nd tableview's Delegate and Datasource. well, the delegate is the ViewController but what about the Datasource? how would it know which data to pull from?
I hope you guys can assist with this dilemma or at least, point me to an example.
I would use a UIViewController rather than a UITableViewController. Add two UITableViews, either in code or in a storyboard, and create two properties for them - let's say parentTableView and childTableView. Make your view controller both the delegate and dataSource for both tableViews. When you implement the relevant methods, begin by checking the tableView parameter that is passed in the method call, and provide the relevant data:
if (tableView == self.parentTableView) {
// provide data relevant to the parent...
} else { // provide data relevant to the child...
}
To provide the data for the tables, you could use one fetched result controller for the parent, and then use the parent - child relationship to derive the data for the child table view (eg. for numberOfRowsInSection for the child, you might use [self.selectedParent.children count], and so on). This will work fine, but you lose the benefits of using a fetched results controller for the child objects: automatic table sections, and automatic updates when new child objects are inserted/updated/deleted.
If you would prefer, you can use two separate fetched result controllers - one for the parent objects, and another for the child objects. Create a property for each, say parentFRC and childFRC, and then use the relevant one to provide the data in the tableView delegate methods as above. For the childFRC, you should set a predicate which limits the fetched child objects to those whose parent is the selected parent in the parentTableView. (You will need to reperform the fetch for the childFRC when the selected parent changes).
If you use the NSFetchedResultController delegate methods to keep track of changes to the data, you should again set your view controller as the delegate for both FRCs, and in your implementation of the relevant methods, check the fetchedResultController parameter that is passed in the method call to determine which object has been changed - parent or child - and update the appropriate table.

Why should I use NSFetchedResultsController in a hierarchical ViewController structure?

I searched a bit but couldn't find the answer I was actually looking for. Simple scenario:
TableViewController with an NSArray of beers. If I select the cell, a detail-view with beer details should be displayed. Now the beers are stored using CoreData.
In the RootViewController I use NSFetchedResultsController to fetch all the beers.
Now my question is: Should I just set the beer property of the destination to the selected beer, or should I create a new NSFetchedResultsController and perform a whole new fetch with a set up NSPredicate?
Where is the difference?
Hmm...
For me I think the biggest factor would be whether the data changes or not.
NSFetchedResultsController is good for performing fetches etc... but it comes into its own when dealing with CoreData entities that change.
The NSFetchedResultsControllerDelegate methods are there to update the table/collection view when the CoreData model is updated on a background thread (i.e. from a network request etc...).
If your model doesn't change at all then I'd go with just passing the beer object in and using the properties of that object.
If the model does change then use the NSFRC and its delegate methods to perform a new fetch.
If you already hold the selected object in your RootViewController and it has all attributes that you will present in the detailViewController, then I see no point setting up the NSFetchedResultController for the detailVC. You can just pass the object to detail in prepareForSegue or so.
The point of using NSFetchedController is that you don't have to update your tableview datasource array and reload rows/table with each change in your list provided you use Apple's CoreDataTableViewController template.

Core data - How to reload NSSet (child objects) on second tableview controller

Hi I am new to Core data. I am having difficulties in reloading my child objects or the NSSet objects which is located on a second tableview.
So I have two tableview controllers, the first one is Budget where I can add or delete a budget. Within that budget object it has a one to many relationship with Expense object (So the Expense is the NSSet).
After when I tap into one of the budget cells, it takes me to the NSSet of Expenses, I then converted the Expenses NSSet into NSArray by using the allObjects method like below:
_expenses = [[_currentBudget expenses]allObjects];
I then populated the table view controller and it shows me all of the individual expense available within that budget. I then have an add (+) bar button to add an expense into the current budget (or call the predefined method that core data gave me: -(void)addExpensesObject(NSManagedObject*)object
Everything is great and it can be saved. However.... once I saved I am not sure how to reload the NSArray of expenses as it is not like the fetchedResultsController. (I am able to reload data on the first tablview once a budget was added because i used the NSFetchedResultsControllerDelegate and implemented the changes/update/insert etc methods).
So my question is, how do I reload those set of NSArray objects? I tried to add in viewdidappear [[self tableview]reloadData] but that didn't work for some reason.. But when I tap back to the first tableview (budgets) and tap back into the expense... it reloads.
Many thanks!
The simplest solution would probably be to use a fetched results controller in the
second table view controller as well. Instead of passing
[[_currentBudget expenses]allObjects]
to the second view controller, just pass _currentBudget. In the second view
controller, create a fetched results controller with a
fetch request on the "Expense" entity and using a predicate like
[NSPredicate predicateWithFormat:#"budget = %#", self.currentBudget]

How to set properties for more than one UITableView?

I have two UITableViews that I want to put into my app and obviously would need to set the properties of each of them (cellforRowAtIndexPath, numberOfRowsInSection).
How would I do this with two UITableViews?
Would I put an if statement (please explain) in these methods, or are there separate ways to do this?
If you are creating by IBOutlet set tag for each UITableview in properties window then if you want to set datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(tableView.tag == 1)
{
return 1;
}
else
{
return 2;
}
}
same way set for cellforRowAtIndexpath.hope will help
Those are not "properties". They are methods; in particular, they are messages to the data source and delegate of the table view. Each table view gets to designate what object should be its delegate and data source. (Even those need not be the same object, but they usually are.)
So. If the tables are different, then why not have the data source and delegate of Table 1 be one object, and the data source and delegate of Table 2 be another object?
But if that is impossible, and both tables must have the same object as their data source and delegate, then yes, you will obviously need to distinguish one table from the other. That, after all, is what you typically do when you have a table and a search results table based on it.
To display two tables simultaneously you may be beter off creating two view controllers rather than distinguishing tableviews in a single controller. Do you really want to take small iPhone screen space displaying both the folder list and actual mail content at once? UI where controllers are pushed/popped has lots of advantages.
But if you want something different you may want to have a look at implementations of slide menu interface. That will show you how to implement two controllers visible simultaneously.
On iPad it is different and API provides a split view or master-detail interface.

Resources