same class in different views - objective-c

I have an App with 3 views, and 2 classes that each take care of parsing messages and connecting to a server.
The thing is, i would need to use the parser in all three views (and the connection too)
But i think that including and initializing an instance of both in all views may not be correct performance wise, am i right?
It it's not correct, how should i do it?
I am thinking about creating an instance of them in appDelegate, but i don't know how
to do it to use the methods of the instances.
Thanks in advance

Passing back to the AppDelegate is possible, but not really OOP is it? Pretty soon you'll be using it to pass data back and forward between view controllers in larger application.
The better way to do it, and similar to the way you pass the managed object context around in Core Data programs is to create a property in the view controllers to hold the parser. Create this parser in one place and after you create the new view controllers, set the property to point to your parser. That way you are just passing around one instance, and in in a more controlled manner.

It will be better in this case to create it in the appDelegate. The appDelegate can be reached anywhere in the code as follows:
MyAppDelegate *delegate=(MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate parse:data];

Related

IOS: is it possible to bind one story board view controller to several different classes?

I know it's possible to attach a custom view controller class to several different view controllers on a storyboard, but can it be done in the other direction; that is, depending on the situation, I want to bind different custom classes to a single view controller on the storyboard that will be instantiated using:
[self.storyboard instantiateViewControllerWithIdentifier:]
background: I used to have several view controllers on my storyboard that are almost identical. In fact, the custom classes that they each bind to are very similar as well. In an effort to clean this up, I refactored my custom classes into one base class and several subclasses. I then removed all the similar view controllers from the storyboard leaving only one which I've bounded to my base class. I then call:
MySubclass* mySubclass = [self.storyboard instantiateViewControllerWithIdentifier:#"StoryboardControllerBoundToBaseClass"];
Unfortunately, my subclass code is being ignored and only the base class code is ever run. Does anyone know how I can make it work without duplicating view controllers on the storyboard and binding each one to a different subclass?
It's not possible. Just because you say MySubclass *object = something doesn't magically convert object into a MySubclass object. It's stored in the storyboard with whatever class was assigned at storyboard compile time.
Rather than using subclassing, I figure I can reuse a view controller on the storyboard by using a delegate/proxy model. More specifically, I can bind the storyboard's view controller to a custom class that delegates all of its methods/events to others classes to handle. This isn't as elegant as subclassing but at least I can keep my storyboard leaner, not having to keep several copies of pretty much the same view controller. Plus, I won't need to duplicate future changes to every copy of these controllers to boot.
As guylegend writes. Apple doesn't support the way to do that. There are many workarounds e.g. with delegates but I finally found the answer and answered in another topic. Hope it helps!
https://stackoverflow.com/a/32103618/1943053

Access the same object inside two different nib files

I want to know how the same reference of an object of a particular class can be accessed inside two different Xibs.
I understand that by creating an object reference for the class inside each xib creates different objects. Even when using AppDelegate its creating different objects.
What I want to achieve is that referenced object inside both the xibs should be the same (so that I can use the object as the datasource of two different table views for instance.)
Only create the object once, and put it somewhere you can get to it from both classes. For instance, you could create the object as a property of your application delegate. Then add
AppDelegate *app = [[UIApplication sharedApplication] delegate];
to your classes (after importing AppDelegate.h) and access the object with app.objectName.
The other answer will work but it's a bad design.
You should stick to the tell don't ask rule. Give your objects the dataSource you want them to use, do not have them asking for a dataSource, which is actually a nasty global.
The other issue is your understanding of nibs. They store an object graph, when a nib is loaded the graph is un archived and each object in it is instantiated. If you have two of the same objects in the graph then you will end up with two instances not two references to one instance. It is the same for when you drag out multiple views, you end up with multiple instances of UIView (and subclasses) which is exactly what you would expect.
It's well worth the effort in learning the boundaries between what you can/can't do in a nib and what you have to do in code and how they all fit together.
Interesting !
Try using singleton approach, check out this link http://www.duckrowing.com/2010/05/21/using-the-singleton-pattern-in-objective-c/
Using this approach, you can create an instance which will be available throughout the application life cycle

iOS: Uniquely identify ViewControllers from Storyboard

I have a custom ViewController that is meant to be reusable, and an arbitrary number of instances will be chained together in a NavigationController in Storyboard, all sharing the same model as a delegate.
The ViewControllers need to tell the model which instance they are. Currently, they have an int property that they get from the segue, but it doesn't seem very idiomatic and doesn't lend itself to having multiple instances onscreen (for iPad). I figure there's got to be a cleaner way to do this, so does anyone know what it is? Thanks.
RESULT: self.view.tag
A UIViewController's UIView has a tag property which you can set from anywhere you want. You could also simply identify the type of the controller by using [self class]. Or simply use the memory location by referencing the controller directly.
Update You could simply implement a unique identifier for a UIViewController using a category.
I guess the "cleanest" way in terms of design architecture would perhaps be an array of ViewControllers. (It could be managed in the app delegate.) However, there are memory considerations - on the iPhone you would likely want to create and the destroy the view controllers as needed. The array could contain the identifier and perhaps some other model-related information in order to recreated the controllers as needed.
Too bad there is no property storyboardIdentifier of UIViewController. They can be instantiated with this id but it would be helpful if the viewcontroller can query its id.
I recently ran into this. I figured out you can add a "Restoration ID" in the storyboard. Then you can access it perhaps like this (depending on your use case)
navigationController?.viewControllers.first?.restorationIdentifier

Traversing the ViewController hierarchy properly?

I'm having trouble referencing one view controller from another. The code works but I get warnings which makes me think I'm going about it wrong. I'm trying to reload the data in a tableView whose controller is in a NavigationController.
What's wrong with a message like this:
From the AppDelegate:
[self.tabBarController.selectedViewController.topViewController.tableView reloadData];
Although this works, I get the warning request for member 'topViewController' in something not a structure or union because Xcode doesn't know that the selectedViewController will return a navigationController. So I could do the following:
UINavigationController *myNavigationController = self.tabBarController.selectedViewController;
[myNavigationController.topViewController.tableView reloadData];
But then I get this warning: incompatible Objective-C types initializing 'struct UIViewController *', expected 'struct UINavigationController *'
How far do I have to go with this? The first line works. To get to the "right way" is it gonna take 8 lines of code?
A major code smell here, IMO. You're trying to do action at a (great) distance. It's not exactly clear what you're trying to accomplish, nor why you need to do this action from the app delegate. I have seen some developers treat the app delegate like a giant catch-all global lump of mud, and I think this is an anti-pattern that should be eliminated from iOS development.
Back to your question: you're trying to force a table view controller, inside a tab view controller, to reload its data. I'm assuming this is in response to something happening. Why not have the view controller in charge of that table watching for that event instead of the app delegate? That way, the thing that owns the table view is directly controlling it -- which is the entire point of the MVC pattern. This is a much better approach than having the app delegate drill down through a hierarchy to find a table view... in terms of complexity, readability, and brittleness.
If, for some reason, you can't or won't have that view controller observing for the event directly (hard to fathom why offhand), you could always have the app delegate post an NSNotification and let the view controller in charge of the table register as an observer for it. Not as good as direct observation, but definitely better than your current approach.
You can't use dot-notation unless the compiler knows what type of object you are using it on, and that that object type can receive a message with that name.
You can use dot-notation with a bunch of type-casts (which in this case, is hideously ugly):
[((UITableViewController *) ((UINavigationController *) self.tabBarController.selectedViewController).topViewController).tableView reloadData];
Or you can break it up into discrete steps:
UINavigationController *navController = (UINavigationController *) self.tabBarController.selectedViewController;
UITableViewController *tableViewController = (UITableViewController *) navController.topViewController;
[tableViewController.tableView reloadData];
Note that I'm assuming that your top VC is a sub-class of UITableViewController.
You really shouldn't be accessing the .tableView property externally - you should encapsulate that behaviour with a reloadData method on the View Controller itself. Even if all it does is call reloadData on its .tableView, you should encapsulate it. This will make your code more modular (which makes it easier to understand for you and others), and make it easier to expand on and add complexity to your View Controller down the track.
Without knowing exactly how this app is structured, I would guess that you're probably better off using notifications or observers to get your VC to reload its data. If you have some global event that requires a UI refresh, an NSNotification is a good way to make the UI layer get the message while keeping your code nice and modular.

Passing variables to different view controllers

I've searched and searched but nothing has really worked.
I'm trying to set a textvalue from a text box, into a string or whatever, so that I can call it up later in a different view controller. I can't seem to get it to work!
I'd also like numbers to be carried over, such like currency's.
Any ideas on them?
Cheers.
You could make an instance variable on the other view controller retain or copy the value before you push/pop the view. For example:
OpenNextViewController *varNextPageController = [[OpenNextViewController alloc] initWithNibName:#"OpenNextViewController" bundle:nil];
varNextPageController .textString= self.textString;
[[self navigationController] pushViewController:varNextPageController animated:YES];
[varNextPageController release];
In "OpenNextViewController" in this example have an instance variable "textString" that retains or copies (depending on your needs) your text.
Spend some time trying to grok the Model View Controller pattern.
In your case you may be looking to share data between different views sharing a common Model. The Model is the store of your data, in your case the textvalue.
Your question is a bit vague. Could you give any more specifics.
It sounds like you want to know:
How to get values from controls. In the case of a text field there should be a text property you can get the value from.
How to share values between controllers. Not sure exactly what you mean. The controller usually orchestrates the sharing of values between different views by using a model as the authoritative version of the data.
Again, if you can be any more specific we may be able to help more
If you want it in several controllers, then I would think you need to run it through the model?
Do you guys think that using the AppDelegate as the holder for one's model is fundamentally wrong? I mean AppDelegate is easily visible to all controllers so it's easy to bind to and get/set it's properties.
pom