I'm new to xcode and I'm struggling with this for 5 days now, my head is almost blowing away because I know this must be pretty simple!
I have a tab bar based iphone app with 2 tabs.
On the first one I want to create new Items and store them in a NSMutableArray inside a "Repository" NSObject Class that I've already created.
This Repository class has methods like add, remove, update and fetchAll Items. The last one is the method that returns all the items stored in the NSMUtable Array.
There's also a NSObject "Item" Class that represents what is an Item.
On the second tab I have a table view controller that I want to fill up with the items created on the first tab and that have been stored in the "Repository" Class.
My question is:
I have to alloc init my repository somewhere in the process so that I can call the "Repository" class methods. The thing is, if I alloc init the repository on the first tab controller, everytime that the first tab is loaded it will alloc init the repository again and the items that where there just disappear. The same goes for the second tab.
So where should I alloc init my repository so that I can call the "add" method in the first tab view and call the "delete" and "fetchAll" methods in the second tab view (that is a table view) and guarantee that I'm acting on the same repository data?
Thanks in advance
I have to alloc init my repository somewhere in the process so that I can call the "Repository" class methods. The thing is, if I alloc init the repository on the first tab controller, everytime that the first tab is loaded it will alloc init the repository again and the items that where there just disappear. The same goes for the second tab.
It seems that you might need a singleton.
A singleton is a unique global object that you can access from anywhere in your app. On the first access, it will be also created. On any subsequent access, the existing object will be returned.
Have a look at this post for a good tutorial.
It sounds like you can have a property for your 'Repository' class in your app delegate and initialise it there as soon as the app has finished launching. Then you would be able to access it from any part of your code.
Or, you can subclass UITabBarViewController and initialise the 'Repository' object in the controller's viewDidLoad method.
Seems you are facing problems with passing data. Well as #sergio suggested you can use a Singleton.
Also it will be a good idea to use a Utility class for all your global methods.
Thus you can update your variables in another tab and values will be reflected when you switch among them.
Related
I am making an app with swift and xcode. In it I have a model class with user's information in it. I want to display some of that information with one view controller, update/change that information in another, and keep all of the views up-to-date with whatever is in the model class.
I was told using a singleton could work but is not recommended. Is there a better, more accepted way of accessing the model class from multiple view controllers without a segue between them (I am using a tabBarViewController)?
If you want to go "pure" that is follow Apple Best practices where a View Controller is never hard-coded to a global model (more of a pain than is worth, practically, in my opinion):
Subclass UITabBarController to contain the model instance as a stored property (perhaps private(set) is the best access level here, but however you want to expose it safely to other classes -- PUBLICLY EXPOSED AS A PROTOCOL TYPE ONLY OF COURSE.)
Don't forget to set the identity class of your Storyboard Tab VC to this new subclass otherwise your sexy code will not run.
In your (hopefully base class to all child tab VCs) View Controller class, hook into didMoveToParentViewController(parent: UIViewController). Gently downcast (as?) to the UITabBar subclass above, and extract the model, and copy the reference into your local stored property. It will happen exactly at the right time, just as you land into the soft arms of your parent VC.
Happiness!
You can try KVO mechanism. By which if you change a model variable's value that will reflect in another controller. For your reference
https://www.appcoda.com/understanding-key-value-observing-coding/
I'm using Storyboards. I need to init instance variables of UIViewController just once. viewDidLoad and awakeFromNib fire each time I open a viewController from menu (I'm using SWRevealViewController for sidebar menu as in Facebook app). Is it normal for awakeFromNib to fire many times or is it SWRevealViewController bug?
So is there some special init method or do I need to set instance variables from outside of viewController (in AppDelegate?)
EDIT:
I found this question
SWRevealViewControllerSegue, reusing Viewcontrollers
I didn't realize that each time you show a controller via segue it creates a new instance of controller. So what does it mean? Does it mean that if I have a table of data loaded from web API - it will be reloaded each time I go back and forth through segue?.. Doesn't seem very effective to me. Is it normal for iOS?
View controllers are either recreated or reused depending on the situation. When you push a view controller onto a navigation controller's stack, you almost always push a new instance. When using a tab bar controller, the view controllers it contains are often held in memory. To avoid excessive memory consumption, it makes sense that view controllers are cleaned up when possible, rather than held around.
In the case of your SWRevealViewController then yes, it sounds as though your view controller should be recreated every time. You ideally shouldn't be directly loading any data from a web API within your view controller; instead, extract your API calls and models into separate classes that you can reuse from any view controller. Then, rather than reloading the data over the network when your view controller loads, you just need to fetch the latest data from your model / store class.
The docs on viewControllerWithRestorationIdentifierPath:coder: say:
Your implementation of this method should create (or find) the
corresponding view controller object and return it... It is not always
necessary to create a new view controller object in your
implementation of this method. You can also return an existing view
controller object that was created by another means. For example, if
the view controller had already been loaded from a storyboard file,
you would return that object rather than create a new one. [My italics.]
This has always seemed like complete nonsense to me. This is a class method! We don't have any access to any instances at this moment — unless we create one. I'd be grateful if someone can explain to me how on earth a class method can find or know about "the view controller that has already been loaded from a storyboard file".
EDIT: To earn the bounty you must show me an actual case, from your own app, of the class method viewControllerWithRestorationIdentifierPath:coder: being used to "return an existing view controller object that was created by another means."
The most common example of this I can think of is any of the view controllers that are owned by the App Delegate. This is traditionally a tab bar controller or a navigation controller in traditional apps, but sometimes it can be something completely custom, which is when this functionality might be useful.
Since the UIApplication is pretty much a singleton and has one delegate, it means your App Delegate has global state, which makes it accessible from anywhere, including in class methods with: [[UIApplication sharedApplication] delegate].
Of course, any singleton is accessible from anywhere and a common pattern (but one I personally dislike) is to have a NavigationManager singleton which manages any global view controller transitions, so in this case you'd be able to access the existing instances as well.
I am creating a tab based application using MonoTouch and has a need to pass the data from one tab to another. For example - my default tab loads a list of articles and I need to have that list passed to another tab if user selects it.
At first I thought that I could populate the list in the first view controller and pass it to AppDelegate from where the second view controller can pick it up but that doesn't seem to work.
What is the best way pass data between tabs in iOS? I am looking for MonoTouch example as I am not much familiar with objective-C syntax.
If you are doing this in code rather than using InterfaceBuilder...
Make your own UITabBarController by inheiriting from it. Add your shared data items to that new class. Inherit from UIViewController to create xyzViewController. Add a contructor to this which passes in and stores a reference to your UITabBarController.
You can now ref the common data using the local UITabBarController reference.
If you are using InterfaceBuilder create all the classes and connect them up using outlets.
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?