As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I would like to develop an application where the main Window would have a NSTabView with several NSTabViewItems, and in each item it will have a different NSTableView.
How would you organize the class architecture in order to be able to access from each tab tableview controller to the others? What is the best way to do it?
I have read a lot of stuff about passing data between controllers using delegates and so on, but I think there must be another clearer way to do address this problem.
Having the next example scenario:
TabOneController.h
#interface TabOneController : NSControl {
NSMutableArray *listOne;
...
}
TabTwoController.h
#interface TabTwoController : NSControl {
NSMutableArray *listTwo;
...
}
These two controllers implements NSTableView dataSource and delegate methods using its NSMutableArray list for it. I would like a proper scenario where both controllers could have access to each other (class methods, View Controller, another controller managing all or whatever a good idea would fit here). What do you think it is the best way for it?
Thanks in advance
If you want to share data between controllers, a good solution is to pass all controllers the same instance of the data object. If there’s more data to be shared or if there’s some extra functionality attached to the data, wrap it in a model class and let the controllers share a pointer to the same model.
If you want the controllers to call each other, there are many possibilities with different implications and there is no definitive answer, everything depends on the situation. The important question is: why would all the tab controllers want to access other tab controllers? Generally you should keep the controllers isolated. This is called loose coupling and it’s very good for your design.
If the controllers need to call each other, try to rethink the design. Maybe some of the behaviour should go to the model instead? For example, instead of calling another controller to delete an item from a list, you can move the deletion code to the model, and other interested controllers can learn about the model changes by observing the model.
Whatever you do, just don’t use singletons :) I have put some sample code on GitHub that shows how to wire a project without (mis)using singletons.
First option:
Declare instance variables for each controller that point to other controllers? For example, say you created a property anotherController in CustomController1 and:
CustomController1 *controller1 = [[CustomController1 alloc] init];
CustomController2 *controller2 = [[CustomController2 alloc] init];
controller1.anotherController = controller2;
This way, controller1 will have access to controller2. And then just do similar stuff to other controllers. You can even apply some inheritance there.
Second option:
From a particular controller do:
CustomController *customController =
(CustomController *)[self.tabBarController.viewControllers objectAtIndex:x]
Assuming CustomController is the class of the controller you want to access, and x is where it is located in the array that is maintained by the tab bar controller.
I would create a singleton class that will store data and handle all data operations...
You can store the data in the NSUserDefaults as the simplest practice.
If you are only going to be working with a few shared variables, I would just use the AppDelegate.
Related
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
In objective-c?
I had a class made and then I decided that I want another class that's like the first class. Should I use protocol and ensure that both classes support that protocol or should I create a parent class and decide that the 2 classes inherit from that one class?
Note:
The classes are: Business, Catalog, AddressAnnotation (currently works only on business only) and AddressAnnotationView (currently works only on business only). I want the same thing to work on Catalog. There is also BGGoogleMapCacheForAllAnnotations that manage when the annotations are clumped together (which now should be able to handle both AddressAnnotation for Catalog and Business. Also there is BGGoogleMap View Controller that I want to turn into a parent class.
If you use a protocol, then you have to define methods shared by both class types twice. Protocols are generally reserved for specific patterns, such as the delegation pattern, to add security and make it harder for you to make a mistake, or when several classes already embedded in a class hierarchy need to share common methods and have this sharing be documented in some way. If one class can be represented as a more specialized version of another, you should inherit.
For instance, let's say you you have a Vehicle class in your game that knows how to do all sorts of stuff, such as move around. If you wanted to make a Car class, you'd probably subclass the Vehicle class so that you could inherit all of its method implementations; either to utilize them wholesale or implement your own version of the methods, probably performing some task specific to the subclass before calling the superclass's implementation as well. Subclassing is for when you want to inherit the traits and behaviors of your superclass while modifying it in some way. This is especially true when additional data must be added to the class, such as instance variables, because you can't do that with categories (although you can with a Class Extension, often seen as a sort of private interface). Generally, subclasses have more specialized purposes than their superclasses as a result.
Protocols are just that, protocols. They're there to prevent you from screwing up or forgetting something, and ensure that every object does what it's supposed to, triggering compiler warnings when classes aren't behaving like they are supposed to. This is important for patterns such as delegation, since it's the only way to ensure that the delegate implements the methods you need beyond breaking encapsulation and knowing what type of object your delegate is. For instance, look at the the code below, from one of my projects.
//SGSprite.h
#protocol SGSpriteDelegate
- (BOOL) animation:(int)animationIndex willCompleteFrameNumber:(int)frame forSprite:(id)sender;
#end
#interface SGSprite : NSObject
#property (nonatomic, assign) id<SGSpriteDelegate> delegate;
#end
//SGViewController.h
#interface SGViewController : UIViewController <SGSpriteDelegate>
//...dreadfully boring stuff
#end
Many classes utilize my SGSprite class for rendering textured 2D quads. Sometimes, they need to know when a sprite reaches a certain frame of animation, so SGSprite instances need to call a method on their delegates to let them know when certain frames are reached. The only way to ensure that delegates to instances of this class implement this method, and, indeed, warn me if someone tries to assign an object that doesn't as a delegate, is through the use of a protocol. You'll notice that if I simply make the delegate a plain id I'll get a warning whenever I call this method on my delegate, since its implementation cannot be found, while if I import the delegate's header/statically type the delegate, the class is no longer well encapsulated.
You don't technically need protocols in most cases; you could define all of the methods without a protocol in all of the classes that would ordinarily adhere to said protocol, and everything would work fine. However, these common methods are no longer documented. Thus, beyond the security of knowing certain classes or anonymous objects implement methods you need them to implement, you can also quickly tell what does what and how. Protocols are for when you need to ensure that a class, or instance of a class, implements some method, especially when an object's type shouldn't be known to keep a class encapsulated.
There are a lot of factors that could influence that decision. For one, when you say that the other class is "like the first class", what does that mean? Does it mean that they'll do 90% of the same things in exactly the same way? Does it mean that they'll do a lot of the same kinds of things, but each in a slightly different way?
If many of the existing methods in the first class will work as-is or with little modification in the second class, subclassing lets you get all of those methods "for free" so you can just focus on the differences. If you would need to rewrite most of the code, however, and just want to define the two classes as performing similar actions then a protocol might make more sense.
I've personally used subclassing exclusively, primarily because I haven't run into a situation where a protocol made sense to me in my code - of course, after a while it's more out of habit than conscious decision. When I began converting my app to using Core Data, subclassing fit in very nicely because Core Data offers the ability to create subentities with inherited attributes and relationships. That made it easier to grasp conceptually.
If you think about your current code, you're already subclassing (NSObject, view controllers, etc.) and possibly using protocols (NSCoding, view delegates, etc.). Think about how you use those existing classes and protocols and how those use cases would apply to your own classes.
Still on assignment 4 of cs193p. - http://www.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/assignments/Assignment%204_2.pdf
I've fully (ish) implemented the displaying photos from a list of places.
I'm adding the second tab of the application (required tasks 10 & 11) , which is to generate and display a list of the 20 most recent photos viewed in chronological order.
My question relates to the MVC pattern and setting/accesing NSUserdefaults.
Basically, anytime a photo is viewed, a property list stored in NSUserdefaults needs to be updated.
When selecting the "recent photos" tab, those values need to be read and displayed, so that the user can select a recently viewed photo, and then view it by selecting it.
I think I can implement this quite easily from a writing lines of code and it will probably work point of view.
I've seen this question: CS193P UITabBarController MVC Help on Assignment 4 which is kind of related, but doesn't really address my more theoretical question about the nature of the pattern.
My question is more about the MVC pattern.
In the lecture, when he demonstrated this with favourite graphs, from the previous calculator assignment he used a delegate to communicate between the favourites list view controller and the graphviewController (see diagram on slide 64 of lecture 9). http://www.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/Lecture%209_1.pdf
I'm trying to work out if I need to do something similar to avoid breaking the MVC pattern, or if I can just use NSUserdefaults in both the viewWillLoad of my imageViewController to add a photo to the favourites and and then in my setter in RecentImagesViewController. I know NSUserdefaults is designed for persistence, it just feels a bit like I"m using a global variable.
I realise this question is worded in a way which makes it difficult to follow if you aren't familiar with the cs193p course - sorry.
Thanks for any advice!!
I don't think you have to transform something rather simple in something complex. You are storing the favorites using the NSUserDefaults and that's it. The place where you are using might not be the best (I am not saying the viewWillLoad is a bad place, I don't know your code), but I don't think you need a delegate to just update the NSUserDefaults. Botton line, don't forget the KISS principle. :)
Well, it probably feels like you're using a global variable because the user defaults themselves are a global concept. And they should be. You don't want different parts of the app operating on unsynchronized versions of user preferences.
But, if you use the term variable in the sense of an old C/C++ global static piece of data, then, no ... that's not what it is. NSUserDefaults was written by Apple to be a nice tidy class that encapsulates the user default data. The fact that you use [NSUserDefaults standardUserDefaults] to access something like a singleton instance (not sure if that's how Apple chose to implement it) still doesn't mean it's a true global variable.
I agree with Jacky Boy that keeping it simple is best, but your question is really asking whether doing it the way you are is a violation of the MVC pattern (and adhering slavishly to a pattern is not always going to make your code the best). That depends on what you consider the model to be. I could justify saying that Apple built NSUserDefaults to be a model layer encapsulation of the preferences data. So, there you have your model layer, and your controllers should be able to use it.
Or do you feel the need to write the entire model layer yourself, in which case your model layer would just have a wrapper for NSUserDefaults. That would seem like overkill for most situations.
Here is maybe one situation that could warrant it. If you have a lot of preference data that seems logically related, but some of it is not appropriate for NSUserDefaults. Perhaps it's a lot of binary data, stored in a hierarchy of objects, and you want to persist it with Core Data. But, it still seems logically related to what you're keeping in NSUserDefaults. Maybe then, you decide to write your own model layer, that encapsulates both the Core Data and NSUserDefaults data. Your view controllers could then use that directly.
But, generally, I think iOS is well designed to have whoever needs to just use the standardUserDefaults object directly.
If I understand the question correctly, it sounds like the setting/loading should be occurring from the appropriate view controller. Creating a delegate (which may or may not be a singleton) that you can call from each of the different tab's view controllers will help prevent you from duplicating code.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 11 years ago.
Improve this question
I want to find a good resource and/or book on this matter.
I am already really comfortable and efficient with creating apps with interface builder and see the value in using it in terms of all the visual feedback it provides in realtime / how good of a time saver it is.
So many questions like this were answered by people trying to persuade people to be ignorant of how to create an interface programmatically and to just use interface builder all the time.
I see the value in using IB but I feel that my knowledge of Cocoa is incomplete without knowing how to create an interface from both approaches.
Any help is gladly appreciated!
Thanks in advance!
Every setting in the Interface Builder has a corresponding property in the object. For example, compare the Interface Builder inspector for NSTextField/UITextField and the documentation of NSTextField/UITextField.
IBOutlet and the target/action mechanism are not special either: the former just uses Key-Valued Coding to set the outlet to an object, and the latter just uses setTarget: and setAction: of NSControl (or a similar method of UIControl on iOS.)
What the IB does is to precook these objects with the properties set as you specify in the inspector. When loaded, the data is fed to initWithCoder: of the class.
So, if you'd like to go IB-less just for fun, all you have to do is to alloc+init the UI object, and set all the properties by code. There's nothing more than that (except for special menu items on OS X which is somehow handled implicitly when MainMenu.nib is loaded, that is.)
There is an open source project called nib2objc which translates a nib/xib to a .m file with explicit Cocoa calls. That will help you understand what is going on.
On a bit more about nib files, read Apple's own documentation. The special magic at the loading of MainMenu.nib is described in this series of blog posts. But this is not really about how you would create UI without the nib in general; it's about how the special menu items are treated by the system.
In any case, internally speaking, there's almost no difference between loading a nib and writing UI codes programatically; both just create UI objects and set the UI properties appropriately. With IB, you set the properties beforehand and the precooked objects are read at the run time. If you do it in your code, the properties are set at run time. But once they are set, the resulting objects are exactly the same. So, there's really not much to learn.
This is a question about best-practices.
I have an application that uses a standard iOS tab controller.
One of the things that I'd like to do is split the XIB up into separate files. I can achieve this by specifying the 'child' XIB in the 'NIB Name' section for each tab controller. So far, so good.
In this application, I have an object that is used by virtually all of the UIViewControllers (e.g: provides web service calls). Let's call it MyServices.
In the single XIB solution, I can drag an object onto the Objects list, set the type to be 'MyServices'. I can declare in each ViewController an IBOutlet of type MyServices*, and wire the two together. This works nicely.
However, if I move my view out to a separate XIB, any controllers further down the stack that need access to the MyServices object are out of luck, because the object no longer exists within that XIB to perform wiring with.
What I'd expected to be able to do is to declare an 'external object', and wire to that instead. But I can't see how I 'pass' the MyServices Object in the 'parent' XIB as the 'external' object in the child XIB.
Is this just not supported in IB? What is the best alternative?
I could not specify the XIB name in the controller, and perhaps programatically create it at runtime (presumably with some kind of loadFromNib code declaring a dictionary to provide the external object). This does mean that the controller that does this has to be aware of MyServices, even if it doesn't use it directly.
Alternatively, I could have a 'dataProvider' in each UIViewController, so instead of setting the MyServices directly as an IBOutlet, it could do do [dataProvider getServices]. Again, will have to be wired to something that can do that - which limits where XIBs can be broken up. And it feels a bit needlessly verbose..
What's the best practice here?
It looks like with using External Object, you take the object instantiation back into your own hands and you also have to instantiate the NIBs manually. At least that's what I gathered from the answer to How to use a common target object to handle actions/outlets of multiple views?
Can I use Interface Builder to inject dependencies across multiple nibs? asks very similar question to yours, also without a real solution.
In How do I set up a proxy object in the main application NIB? the author also gives up on the idea of using Interface Builder as a dependency injection tool.
So I would guess that we, the Java immigrants, are banging our heads against invisible walls here. The metaphors we use to shape the code in our heads (and the code qualities we've come to value and associate with quality), do not apply to Objective-C, as is. That might be because we are not familiar with Obj-C idioms. Or it might be, that we are dealing with different evolutionary stages of language and community development (for example see the staggering immaturity of TDD practice in Obj-C). I, personally, have not seen much best practices described in Obj-C world in the 9 months that I am seriously dealing with it.
I just want to make sure that I am heading in the right direction with how a simple MVC application is constructed.
// MODEL
#interface Reactor: NSObject {
NSNumber *temperature;
NSString *lastInspection;
NSNumber *activeRods;
}
.
// CONTROLLER
#interface viewController: UIViewController {
UITextField *tempTextField;
UITextField *inspectTextField;
UITextField *activeTextField;
Reactor *reactor;
}
#property ...
...
-(IBAction)ButtonPressed;
#end
.
Am I right in declaring the reactor (dataModel) in the controller? The way I see it the controller sits between the [VIEW] and the [MODEL] so its going to need links to both.
The [VIEW] is linked via "IBActions" to methods implemented within the [CONTROLLER] which in turn sends messages to methods in the [MODEL]. The [MODEL] does any processing/data manipulation needed, sending any required results back to the [CONTROLLER] which in turn may be used to update the [VIEW].
Does this sound sensible, in simple terms?
gary
You can risk this for a very small, simple model but you really shouldn't develop it as a habit because this method will breakdown as your projects get larger.
What happens when you have an app two or more views both taking data in and out of the model? What happens when you have an app with multiple views and gets data from a URL? What happens if you want to use the data model in an html or even a command line interface. What happens when you want to use the data model in another app altogether?
If your going to be writing serious code that will have thousands of users, multiple versions and possibly spinoffs, you need to develop good habits early.
The best method for a data model is to create a singleton to hold it. I would suggest creating a generic singleton class and then making your model for any particular project a subclass of that class. That way you have a neat contained model that can be accessed from anywhere in your app.
The second best method is to park the data model object in the app delegate. However, that to can become unwieldily as the project scales.
It certainly doesn't help that every piece of instructional/tutorial information I have seen pretty much ignores the data model in favor of teaching you how to do the eye candy for the interface. The data models are just simple arrays or some such tacked onto the side of a controller.
Trust me, you don't want the nightmare of growing and growing your app only to discover that its data model logic and data are scattered over a a dozen view controllers. Grit your teeth and do it correctly from the get-go and you'll never have to sweat it.
Edit01:
Singleton, I will have to do some
research, can you explain a little how
you would access that from the
[CONTROLLER]? Just curious if the
[MODEL] goes in the AppDelegate again
how would you access it from the
[CONTROLLER]?
You park a data model in the app delegate by (1) making the data model object a property of the app delegate and (2) using the global reference form for the app delegate:
MyDataModelClass *theModel=[[UIApplication sharedApplication] delegate] dataModelProperty];
Creating a singleton is a little more involved. You use it like you use the NSFileManger. You would reference it the same way.
NSFileManger *fm=[NSFileManager sharedInstance];
This ensures that only one file manager is active in an app. You would call the data model the same way from a controller:
MyDataModelClass *theModel=[MyDataModelClass sharedInstance];
If you carefully design the data model object such that it has complete control over what information is written to it, you can safely use it anywhere without having to worry that your data will be trashed by a one careless line of code.
You're right the model should store all your bussiness related object and they can be MODIFIED through the controller, the view make calls on the controller depending on the user actions.