I am creating an application that has to interact with server data and then display the results from a database accordingly. I am writing the client side app in Cocoa.
Example: A user logs on to a web application. They have some options for filing a web report. Choices: single line and multiple line. They can choose how many of these fields they have for various variables that they want to input. This is then saved in a MYSQL database for later use.
Example (part 2): The client side application fetches the data in the MYSQL databases and then displays it. The problem is that it is a variable number of fields and a variable number of types.
In other words, the database basically stores if we want to display a NSSecureTextField, NSTextField, etc. and then displays that on the screen. As I pointed out above, the problem is that they are allowed to choose how many and the type of the element they want - so I am not quite sure how to transfer this to code.
And just to clarify, I am not attempting to build an online Interface Builder. Simply a online way to input data which has a variable amount of fields, and various types of these fields. I have the online system created, but I am having difficulty with the client side part.
Any help would be greatly appreciated!
I'm not sure I understand what you're asking for. Isn't it pretty trivial to figure out how many NSTextFields the user wants and then have a little for() loop to create them? You'll probably want to keep track of the textfields, so I would probably do it like this:
NSMutableDictionary * interfaceElements = [[NSMutableDictionary alloc] init];
for (NSInteger i = 0; i < numberOfTextFields; ++i) {
//this is just to make a frame that's indented 10px
//and has 10px between it and the previous NSTextField (or window edge)
NSRect frame = NSMakeRect(10, (i*22 + (i+1)*10), 100, 22);
NSTextField * newField = [[NSTextField alloc] initWithFrame:frame];
//configure newField appropriately
[[myWindow contentView] addSubview:newField];
[interfaceElements setObject:newField forKey:#"someUniqueIdentifier"];
[newField release];
}
The dictionary of course would not be local to this method, but I think you get the idea.
Alternatively, you might be able to coerce NSMatrix into automating the layout for you.
If you're writing a client application for the iPhone, then I would highly recommend looking to the Settings Application Schema reference for inspiration. If you're unfamiliar with this, here's a brief introduction: The iPhone allows developers to move their preferences area from the actual app to the Settings app. This is done by creating a settings bundle and building a plist in a very specific way. Settings.app then discovers that plist, parses it, and builds an interface according to the definition it contains. You can do switches, textfields (even secure ones), sliders, groups, and a couple other kinds of interface elements.
Related
I looked over the following threads:
1.What's the difference between outlet and referencing outlet in a simple sentence?
2.What is a referencing outlet?
But still have a big trouble understanding of why we need referencing outlet. Functionally, I mean. Could anyone give as detailed as possible example, explaining it to a beginner?
Right now I am going through Big Nerd Ranch textbook on iOS and they have in 10th chapter (about UINavigationController) a view that has three textfields. They make outlets in a controller and connect them to the textfields. But then happens what I can not get: they say to also connect these fields to the File Owner's delegate. Why do we need to do this?
At the end of Chapter 10, you'll encounter a code like this
item.itemName = self.nameField.text;
item.serialNumber = self.nameField.text;
item.valueInDollars = [self.valueField.text intValue];
To put it in simpler terms, we need to connect these textFields to make a reference to these outlets.(nameField, serialNumberField, valueField)
If we don't make a reference to these outlets, xCode would not be able to tell which text field the user is referring to when the user edits each text field.
As for why we connect text fields to the File Owner's delegate? We need to do this so that view controller can conform to a protocol and then later call [self.view endEditing:YES] which tells xCode when the user is done editing text fields.
Look at the end of Chapter 7 "Delegates" and "Protocols" for more information.
i'm building an app in Xcode where there are a 81 textviews in the NIB, each with a sequential name, so box1, box2, box3, box4 etc.
When doing data manipulation i want to be able to use the data in each box to add to an array for example. What i would like to be able to do is put this in a loop, so for example something like:
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i=1; i<82; i++) {
[array addObject: [Indirect("box" & i).text];
}
Similarly when outputting back to the textviews, i want to be able to loop from the array rather than referring to each textview independently. so something like:
for (int i=1; i<82; i++) {
indirect("box" & i).text = [array objectAtIndex:i];
}
Any ideas? Sorry if this is obvious - fairly new to the game.
Consider the MVC design pattern. Your calculation shouldn't be based directly off the views (the UI) but rather off some state in the controller, which is set by the views. Each time a field is edited, it notifies your controller via target/action or via Cocoa Bindings. When that happens, the controller updates your data model (in your case, that means it updates the computation and probably reflects the result in another part of the UI - the "total" field).
In Cocoa, there are two ways to do it:
Add all of the fields to an array in awakeFromNib. Enjoy writing 82 addObject: messages.
Remove the fields from the nib and create them in a loop in code, adding each one to an array. (This is what I'd do.)
Once they're in an array, you can refer to them by index, same as you do with the strings.
But you mention that you're accessing the fields' text property. This only exists in Cocoa Touch, not in Cocoa. If you're using Cocoa Touch, then you have a third option:
Replace your 82 outlets with an outlet collection.
The value of an outlet collection property is an array, so you get to create your fields in the nib but still refer to them by index into the array in the code.
On the other hand, I'd probably still create them in code, even though I'm more pro-nib than most Cocoa Touch devs. Part of it is habit (I'm still almost entirely a Mac developer), but part of it is the DRY principle. If I create the fields in a loop in code, I can describe all of the fields exactly once, along with the ways in which they differ. I won't have the risk of changing one field and forgetting (or even just having) to update the others, or of going to change all the fields (again) and forgetting to change one.
I would handle this using the tags: you can set them from 1 to 81 in the nib (look for the field under Control).
Then in -awakeFromNib you can call [self viewWithTag:i] inside a for loop.
It's definitely less work than individual outlets, and I think even simpler than an outlet collection – filling in the number means you don't have to connect outlets for all the text fields.
Imagine an application that has a number of buttons it is displaying to the user. This application wants to allow the user to move the buttons around on the screen, customizing the display, and then save this configuration for later use. That is, when the app is closed and relaunched, it will come back up with the same configuration.
I would like to create a nib file with the "factory default" button layout, but then create a new nib file storing the new UI after the user has configured it just the way they like it. How does one do this?
Thanks!
Have a look at
NSData * viewData = [NSKeyedArchiver archivedDataWithRootObject:yourView];
NSView * yourView =[NSKeyedUnarchiver unarchiveObjectWithData:viewData];
This will do what you want. With all subviews, properties etc.
you really don't create a new nib.
for one, you can't expect the user to have the devtools installed. so you need to implement these dynamic parts programmatically.
perhaps export a dictionary with colors, positions, etc. for the mutable properties; then apply those properties to those objects (so it's quite like a simple layer over a nib's xml representation).
if you are not currently using tags to identify your nib's objects, that may be an easy way to identify objects in your exported dictionary.
good luck
As per the tags indicate I'm developing in Xcode for the iPad.
So, I have a New Game setup screen that sits between my main menu screen and the actual game screen. The new game setup screen is supposed to allow the user to customize their game by selecting the number of players, choosing an avatar for each and setting their names. What I've done is I've setup the continue button to write all the settings to a appData.plist file before moving onto the actual game screen. When the game screen appears (the viewDidLoad method) it reads from the plist to add the players to the table with their respective Avatars and so forth.
The question is, is this the right way to pass the data from a new game setup screen to the game screen? Should I use some method to gather the information from the screen and pass it along to the game screen without writting to some file? I guess the ultimate question is how you're supposed to pass data from one view controller to another? I'm using some plist file to write to and then read from when the board appears. I get a sneaking suspicion that this is not the right way to do this. However, I figure at some point I need to save this data to file anyway since I have to be able to restore the state of my app in the even that it gets closed or interrupted. But what is YOUR preferred method to accomplish this?
You can always use the built-in settings screen for your app by making use of the Settings.bundle too. This is very easy and allows you to use the default iPad settings screen for your application settings, rather than setting up a hand-made one.
For passing through information, the information I need is usually a single object (in your case maybe Player.m) and so I create a property in the next view to hold this. And before showing the view I then do (for instance):
GameViewController *gameView = [[GameViewController alloc] initWithNibName:#"GameViewController" bundle:[NSBundle mainBundle]];
gameView.player = player;
[self.navigationController pushViewController:gameView animated:YES];
[gameView release];
Well, "not getting it" is too harsh; I've got it working in for what for me is a logical setup, but it does not seem to be what iOS deems logical. So I'm not getting something.
Suppose I've got an app that shows two pieces of information; a date and a table. According to the MVC approach I've got three MVC at work here, one for the date, one for the table and one that takes both these MCVs and makes it into a screen, wiring them up.
The master MVC knows how/where it wants to layout the two sub MVC's. Each detail MVC only takes care of its own childeren within the bounds that were specified by the master MVC. Something like:
- (void)loadView {
MVC* mvc1 = [[MVC1 alloc] initwithFrame:...]
[self.view addSubview:mvc1.view];
MVC* mvc2 = [[MVC2 alloc] initwithFrame:...]
[self.view addSubview:mvc2.view];
}
If the above is logical (which is it for me) then I would expect any MVC class to have a constructor "initWithFrame". But an MVC does not, only view have this.
Why?
How would one correctly layout nested MVCs? (Naturally I do not have just these two, but the detail MVCs have sub MVCs again.)
Thanks all for replying. I will study the links that were provided.
Let me try to explain my issue one more time, hopefully to making it more clear. Do note that I already figured out that my view does not match iOS's, since I do not like where my code is going.
Yes, I'm calling a UIViewController an "MVC", since it for me at the moment implements all aspects of a MVC; it has controller code and an embedded view, plus the controller usually also holds and provides the data (all TableView examples implement it like this).
MVC can be present on many levels; basically a UITextField could (should?) be a MVC; there is a view, but also controller logic involved that you do not want to mix with other code. Encapsulation. For example: Java's Swing JTextField has a MVC. So does a JTable, JList, ... Multiple MVC patterns nested in other MVC's to build a whole screen.
This what I expect when some platform says it uses the MVC pattern. So When I coded the table, I created a MVC and only send the loadData message with a date as the parameter to it. It needs to take care of the rest itself. I have a Detail MVC that can slide in; I then tell it the object it needs to show and it needs to take care of the rest itself. Encapsulation.
So I have a lot of UIViewControllers with embedded UIViews. And that is not the way to do it...
One more potential link is the great talk from WWDC 2010 on MVC.
http://developer.apple.com/videos/wwdc/2010/
It is Session 116 - Model-View-Controllr for iPhone OS
The session is chock full of practical advice on how MVC really works, what makes it tick, why it's good. But it also has a lot of intro stuff to help folks new to the concept to wrap their heads around it.
If I understand your sentence on Java's Swing classes above are you talking about the anonymous classes that respond to events? If so those are not "MVC's", they are what is termed 'Observers', when they observe an event from the view they take some action (usually send a message to a controller). Cocoa Touch uses the Target/Action paradigm (and delegation) to achieve this.
I'd also strongly suggest you take Matthew and Stephen's advice and write a bunch of code. If you don't build that base of intuition, asking the right question (which is most of what is needed to get a good answer) is very difficult.
I really think the WWDC 2010 talk will help.
Good Luck!
If I understand your question -- and I may not, see my comments on it -- I think you're applying the MVC design pattern far too granularly. Most commonly in the setup you describe you'll have a single Model, a single Controller, and multiple Views that are grouped/combined, as in a .xib file.
In Cocoa Touch terms you'd have one UIView that contains a UILabel with the date and a UITableView for your table. These are your Views.
You'll certainly have a Model for the table data, likely an array of data. Your date data might be from its own model if it's a date retrieved from something or calculated or whatever, something entirely separate from the array of data. If it's instead associated with the array data -- they're both pulling from a database, or the date is calculated from the array data, or what have you -- then you have a single Model.
If the data is all coming from a single Model then a single Controller is likely fine. Even if the data is coming from more than one source/Model you likely only need/want one controller in this setup. The UITableView will have a UITableViewController, and that same controller can take care of providing your date as well.
To sum, the Model View Controller design pattern doesn't call for having a bunch of nested sets of models, views, and controllers. They could be, and sufficiently complex projects may call for it. Broadly, though, you'll have a controller that's associated with a model and one or more views, and that set of objects works together to provide a piece of functionality.
Tbee,
I'll post a tiny code example here, since it seems you're not really getting it.
#interface MyView : UIView
#property (retain) IBOutlet UIButton *button1;
#property (retain) IBOutlet UIButton *button2;
#property (assign) bool myData;
-(IBAction) doButton1:(id)sender;
-(IBAction) doButton2:(id)sender;
#end;
#implementation MyView
#synthesize button1 = _button1;
#synthesize button2 = _button2;
#synthesize myData = _myData;
// I'm leaving out the initWithNib, viewDidLoad, etc.
- (IBAction) doButton1:(id)sender
{
// do something as a result of clicking button1
_myData = YES;
}
- (IBAction) doButton2:(id)sender
{
// do something as a result of clicking button2
_myData = NO;
}
#end
Connect those up in InterfaceBuilder, and you've got a working "MVC." You don't need a completely new UIViewController for each button. The one for the View takes care of it.
UITableView and it's associated Views are more complex, and may require an additional UIViewController to help encapsulate. I really don't suggest starting out by using them, but this is a good tutorial here. It's got a lot of images which will show you how to connect things up in IB and the like. It's old, so your XCode may not look like the images, but it helps.
Thanks for the links, I'll look into them.
So far I've rewritten most of my application to using views instead of viewcontrollers (except the toplevel one) and it starts to match up with the API calls that are available like layoutSubviews. What I find disturbing that I need to do this now:
[tableDataSource loadData:date];
[tableView reloadData];
Where in my previous setup all I did was:
[tableViewController loadData:date];
But apparently that is the way to do it. One thing is unclear to me ATM. Since I construct and layout the view in loadView in my AppViewController, how do they get relayouted if the orientation changes. The VC does not have a layoutSubviews, so I should use the didRotateFromInterfaceOrientation and reposition the subviews from there?
BTW, I'm not mixing registering anonymous inner classes as listeners (observers). I'm very experienced with writing Swing components and JavaFX controls. And that probably is the culprit, in Java(FX) every component has a view and a controller (not always a model).