Accessing the next object in managedObjectContext from my detailView - ios

I have a simple application that uses Core Data / ManageObjectContext. It works very similar to Apple's sample app. The fetchedResultsController grabs the objects and builds out a table view. When I click it sends the Object at that index to the detail view. Simple.
What I want to do is access the next Object from my current detail view so that I need not return to the table view to move through to the next detail view.
I've seen some similar questions but the answers suggest creating a mutable array which seems to defeat the purpose of core data and managed objects.
Thanks!

Use NSFetchedResultsController
/* Returns the fetched object at a given indexPath.
*/
- (id)objectAtIndexPath:(NSIndexPath *)indexPath;
Note:
Creating a mutable array does not necessarily defeat Core Data nor NSManagedObjectContext, but it definitely would defeat the caching mechanism provided by NSFetchedResultsController.

What you're trying to achieve is to present the same data in a bit different way, so you can use same data source based on NSFetchedResultsController. You can easily get index of passed object so you'll be able to navigate between next/prev objects.

Set up a property that refers to the master view controller on the detail view controller, or make the master view controller a delegate of the detail and make it follow a protocol with a suitable method.
Either way, the master view controller will receive a message from the detail view controller and when an action you specify takes place, you could just set the detailItem again on the detail view controller to the next item in your model.
This is assuming you maintain a reference to the index of the current detail item, and a reference to your detail view controller.

Related

Use data in multiple view controllers under a tabbarcontroller

I have a songs = [Song]() array of song objects being generated in the first view controller of my tab bar.
How can i use this array in the other view controllers of the UITabBarController?
I need to show this in my initial view controller, a table containing all songs, but also need to use this data in a second view controller, a table containing only favourite songs.
I think a good solution would be to create another class for managing the songs data. Basically, you want to add a model for your view controller to look at. In this new class, you may decide you want to use a singleton to provide the exact same data to every object viewing the data. This is similar to what core data does, and is something I think you should consider using (core data works with xml). But, by having a class other than your view controller manage your data, any view controller (or any other object) that needs access to the data need only ask the data class for it.

How to edit a UICollectionView item in another UIViewController?

I'm using a Master Detail View Controller with Swift.
When I click on a master cell, I see a collection view containing a list of pictures.
Each picture represent data stored inside Core Data.
Each picture data has also a timestamp and all picture taken the same day are stored in the same Master cell.
[Date of the day 1]
[pic1]
[pic2]
[Date of the day 2]
[pic3]
[pic4]
What I want to achieve is:
When I click on a picture, another ViewController is displayed (through a segue) and this new VC allows me to edit the picture and change its date.
The thing is I have multiple things happening here when I change the day or a picture:
if the pic was alone in the collection, then I also have to remove the Master Day cell too.
if the pic was not alone, I just need to update the detail collection view
In any cases, if I have to create a new Day, I need to create a new Master Cell and update the view and if I need to delete a Day, I have to also update the Master view.
If you edit the collection items, you can simply do a:
self.collectionView performBatchUpdates:
and then update the model, and notify the collection view of your action...
but I don't see how I can do that from another UIViewController.
Currently, in the Edit View Controller, I update the model and then dismiss the View controller. And I get a crash because the collectionView tries to display an Item that is not part of the current collection anymore...
To solve this issue, maybe I can use a protocol in order to inform the detail view from the edit view but If I do that, I need to give the IndexPath of the Edit Cell to the edit view and then give it back to the detail view through the protocol... Why not. but not that clean in my opinion.
Another problem is, the app seems to also crash in the master view when I delete a Day. Because, the master view doesn't know that I deleted a day from the edit view.
My main problem is that I don't see how to tell my Master View Controller that I made some model changes... especially when I don't have any IndexPath information from within the edit view.
Technically, I could use the notificationCenter to notify both Views, I guess... but still, I would need to pass both IndexPath from the Master view to the Detail view and then to the Edit view.
Ugly.
Several ways by which this can be achieved:
1) Delegation: The view controller containing collection view will act as a delegate of Edit View Controller and when editing is done it will callback a method to 'The view controller containing collection view'
2) Notification: EditingFinished
3) blocks
Using protocol is good solution but can be painful since you have to manage edited items using their indexPaths. A simpler solution, since you are using CoreData, is to fetch entries using a computed property and just call collectionView.reloadData() on viewWillAppear method from the controller that contains collectionView. This way calling reload data will recompute Core Data entries and will place each item in correct position. Also viewWillAppear will get called after dismissing controller that stands on top of collection view controller
I found an interesting article addressing my problem.
It was not indeed a trivial problem...
http://www.objc.io/issues/4-core-data/full-core-data-application/#using-a-collection-view

Data source for PageViewController - usage of arrays/dictionaries to store view controllers in data source

I am implementing a scroll style page view controller for my app, based on the page based application template.
In the data source class, I am storing the list of view controllers in a dictionary (could also use array I guess) so that I can reuse them if the user swipes back to a view controller they already viewed. There are about 15 total view controllers in the page view controller.
I wonder if this is a good idea compared to calling the story board instantiateViewControllerWithIdentifier each time. (I understand the pageviewcontroller itself stores its own array of view controllers anyway.)
I could instead just store the model object in the dictionary or array and instantiate the view controller and pass in the model object after calling instantiateViewControllerWithIdentifier.
I am interested in what is likely to be the better approach.

TableView index from rootcontroller to detailcontroller (UINavigationController)

My root view is a grouped tableview. When the user selects a row, i want to be able to retain which row was selected to give to the detailcontroller for loading the correct data.
All the navigation is working fine, I just don't want to have to create a global variable to just retain the index. Is there a built in method for the navcontroller or something?
You can either set a property in you detail view controller before it is pushed giving info about the row selected so it can influence the behaviour of the detail view controller, or it is possible to access the parent view controller directly from the detail view controller with:
#property(nonatomic, readonly) UIViewController *parentViewController
I prefer the first option - you can write a custom init... method, to supply the data for the detail view controller when it's created.
There isn't a builtin way as such, you should try and make the view controllers de-coupled as possible so they can be re-used and are resistent to changes elsewhere in the app.
This is a useful quote from the View Controller Programming Guide for iOS:
With the exception of view controllers managing leaf data, each custom view controller must provide a way for the user to navigate to the next level of the data hierarchy. A view controller that displays a list of items can use taps in a given table cell to display the next level of data. For example, when a user selects a photo album from the top-level list, the Photos application creates a new photo album view controller. The new view controller is initialized with enough information about the album for it to present the relevant photos.
I wanted to follow up with how I ended up coding this. I'm still somewhat new to Obj-C, so some concepts I haven't dealt with or come across, so if this is old hat, sorry.
You can create your data element in the child controller and pass the data 1 for 1 directly to that element by accessing its property.
ParentController.h
NSDictionary *myData;
ChildController.h
NSDictionary *childData;
// This would get called in the parent controller where appropriate
// but before the child controller is presented
ChildController.childData = myData;
This is obviously very stripped down, but the idea works. Just take your data and pass it to the property before calling it and it will be there once the child view is presented. Hope this helps.

Should my app use just one managed object context?

Is it appropriate for my app to have several managed object contexts? I was going this route, (passing along my MOC from one instance of a UIViewController subclass to the next,) but I'm starting to run into EXC_BAD_ACCESS errors and I'm wondering if it could be related.
So, when do I want to use multiple ManagedObjectContexts, and (when) should I only use one?
Edit:
In my UISplitViewController based app, when deleting a row on my Master view, only after presenting a second view inside the main detail view, my detail view controller crashes on respondsToSelector, which I don't call ever.
Edit 2:
Basically, I have a master view and a detail view. In the detail view, the user presses a button. The button brings up a "new transaction" view. Instead of presenting the view modally, I manually add it to the detail view. If the user makes a change to the managed object context in this new view and then tries to delete the row in the master view, it causes a crash. If I present the same view modally, everything works just fine.
Furthermore, NSZombieEnabled says that a respondsToSelector method is being called on the (parent) detail view. I don't call that anywhere in my app. Could this be a memory issue? A threading issue? I don't explicitly create any new threads, but I don't know if there are any threads being created behind the scenes.
What might be the problem?
EDIT3:
This problem seems to get better. In my detail view, I also have a table, which, like the master view, uses an NSFetchedResults controller. When I delete the cell, I also hide the detail view, which causes it to be released. Releasing the detail view causes the app to crash. If I don't delete the detail view, the transactions in the detail view's table are deleted. (This is because I have Core Data set to cascade when an account is deleted.)
So, perhaps I have too many NSFetchResultsController objects? I believe that what is happening is follows:
When I delete a row, the NSFetchResultsController value changes and so it tries to fire the delegate method. However, the detail view has been removed and it's view controller deallocated. So, the delegate system fires a controllerDidChange method and crashes when trying to deliver the notification to the detail view.
How can I fix this?
Generally speaking you should use just one, unless you need to access data from multiple threads, in which case you'll need one per thread.
You certainly shouldn't need to create one per UIViewController.
You might also want to re-think whether you should pass the whole managed object context to a UIViewController anyway - how about just passing it the model objects it needs to do it's job?

Resources