So I want to know if this is a good idea or a bad idea.
I'm building a simple iOS game (using standard UI Controls) which allows a user to create Characters, and Monster "Templates", then build Encounters which references Characters and Monsters and interact with them.
When the user creates an encouner, there is a simple Modal View which allows them to name the encounter, then push to another VC to select the characters participating, go back, push to a second view controller to select the Monster Templates involved, as well as how many of those monsters will be participating.
The goal, in the end, is to have the Monster Templates be used to construct "real" monsters that will be references in the Encounter.
Sample Encounter
Player Characters
Ramza Beoulve
Delita Hiral
Monsters
Orc 1
Orc 2
Orc 3
For the character selection piece, I used an NSSet to store the Character Entities selected and pass it between view controllers. (This way I avoid having to mess with the managed object context very much prior to actually saving the new encounter)
For the monsters, since I need to store a quanitity as well as the entity, it's a little more complicated.
So my original thought was to store them in an NSArray of NSDictionaries which in turn contain the Monster Template and the Quantity.
The problem with that approach is I have to loop through the NSArray and open each individual dictionary to check if a particular monster template exists or not.
It might not matter much at this scale of application, but it seems inefficient.
So I thought instead it might be better to simply maintain two NSMutable Arrays
NSMutableArray *selectedMonsterTemplates;
NSMutableArray *selectedMonsterTemplateQuantities;
This way I can simply call
[selectedMonsterTemplates containsObject:monsterTemplate];
when I need to check if something is already in there, and when I add or subtract the quantity for a particular monster, I can simply update both Arrays.
Then when the Encounter is saved I can simply iterate over the Array once to create my individual monster instances in the quantity desired, and associate them with the Encounter.
I'm concerned that this approach, while simple and efficient, might lead to concurrency problems if there is a small mistake in the code. Is there a better way to go about this?
Maybe its a better design to add a class, lets say TemplateStore. (Or whatever you like)
#interface TemplateStore : NSObject {
MonsterTemplate *template; //Super class of a monster entity.
NSInteger quantity;
}
- (id) initWIthMosterTemplate:(MonsterTemplate *)temp;
- (void) increaseQuantity;
- (BOOL) isKindOfTemplate:(MonsterTemplate *)otherTemp;
#property (readonly, retain) MonsterTemplate *template;
#property NSInteger quantity;
#end
WHen you store this kind of object in an array, you can iterate over it and use the isKindOfTemplate method to know if the MonsterTemplate exists. Then just increase the quantity.
Generally speaking, you wouldn't make an array of dictionaries just to hold structured data, you'd use a single dictionary with the item (template) as the key and the quantity as the value. Pseudocodey it would be like:
quantity=dict[template];
Of course that's assuming you have templates stored as pointers somewhere. A better alternative is to use structures:
struct monster_t { template_t t; int quantity; }
And then you hold an array of these things:
monster_t[] bestiary;
Or even better, figure out an ID of sorts (unique monster name file?) and hold it in a dictionary:
dictionary<string, monster_t> dict;
dict["big_monster_01"].quantity=5;
Of course this system is pretty useless, you don't care about quantity at all. What you do care about is about actual monster instances in the world, basically templates with customized values for hit stats, loot etc and a position:
struct monster_instance_t { monster_t template; vector position; }
monster_instance_t[] monsters; // who cares what they are?
// that's what polymorphism is for!
Related
I'm a new developer creating a simple "dictionary" app for personal use and my question is about how to properly implement the Model-View-Controller design in my particular situation. Please bear with me for the necessary background:
I want to be able to hit a button and have a label display a word on one side of the screen, and to have another label display a list of associated words on the other side.
For instance: when I hit the button I want the main label to display "cats" and for the list to display "tiger", "snow leopard", "lion", etc. The output would be random: the label displayed would be random and the list would be scrambled.
I've achieved this output in the Xcode 4.3 console through storing each list in an NSMutableArray, and using an NSDictionary to hold all of the NSArrays. Here is the code:
//creates lists
NSArray *catList = [NSArray arrayWithObjects:#"Lion", #"Snow Leopard", #"Cheetah", nil];
NSArray *dogList = [NSArray arrayWithObjects:#"Dachshund", #"Pitt Bull", #"Pug", nil];
...
//creates dictionary and stores lists values with dictionary keys
NSMutableDictionary *wordDictionary = [[NSMutableDictionary alloc] init];
[wordDictionary setObject: catList forKey:#"Cats"];
[wordDictionary setObject: dogList forKey:#"Dogs"];
...
//randomizes selection of dictionary key
NSInteger keyCount = [[wordDictionary allKeys] count];
NSInteger randomKeyIndex = arc4random() % keyCount;
//displays selected key, which is the main word
NSLog(#"%#", randomKey);
//selects array list corresponding to key
NSMutableArray *randomlySelectedArray = [wordDictionary objectForKey:randomKey];
//shuffles the output of the selected word list array
for( int index = 0; index < keyCount; index++ )
{
int randomIndex = arc4random() % keyCount;
[randomlySelectedArray exchangeObjectAtIndex:index withObjectAtIndex:randomIndex];
}
//prints word list and removes displayed dictionary selection
NSLog(#"%#", randomlySelectedArray);
[wordDictionary removeObjectForKey:randomKey];
(I need to add code that does displays a main word and list one at a time, maybe using NSTimer, but this is what I've got so far.)
Using a single-view template in Xcode, I've been able to get the simulator to show a main word and a corresponding list by adding some of this code to the IBAction method of the button in my view controller implementation file. (Of course I changed NSLog to initWithFormat.) However, none of my randomization code works.
My question, finally, is how do I separate things so that they conform best to the MVC design? I'm thinking that: My button and my two labels constitute the view. My view controller is the controller, and my NSArrays and NSDictionary data are the Model.
However, I've been keeping all of my model data inside the view controller, which I'm pretty sure is wrong. I think that I need to figure out how to create a class for my NSArrays and NSDictionary to store my model data. Then I must manage to get my button & labels to display the desired text of my model data via my view controller. At least I think that's how MVC works.
I'm wondering if that understanding is correct and if anyone has any pointers on how to organize my model data most effectively to get my desired output.
Thanks very much for any help! I'm stuck!
Before starting to design an application based on MVC. We first need to know what these different components are and what MVC help us to achieve?
Why we use MVC?(Model-View-Controller)
Because it helps us in:
Separating responsibilites also leads to reusability
By minimizing dependencies, you can take a model or view class you’ve already written and use it elsewhere
Think of ways to write less code
While designing an application based on MVC, we should focus on above points.
Lets relate this 'Dictionary' application with real world dictionary.
A dictionary is composed of words, their meaning, pronunciation, examples, usage, antonyms, synonyms, indexes and other similar information.
When a user wants to look for a particular word he will use top-margin word for fast look-up. Once he found the right page he will go to that word and see its meaning, usage or other needed information.
Model Part:
Lets draw analogy between your application and what I described above.
In your application you will be having a class : 'Dictionary' which
will represent the real world dictionary. This dictionary is composed
of words, their meaning, pronunciation, usage and other information.
So we will need an array of words which will contain 'Word' object.
The 'Word' class will have all the information that we wish to provide
for particular word. You can also provide other attributes that you
can think of that belongs to Dictionary and add them to it.(Here we are talking about content only)
Now we need to think of different operations to be performed on this dictionary. The most basic operation are creating a dictionary and accessing it.
We will have a DictionaryCreator class which will add all the words that our dictionary will have. So this is another class
'DictionaryCreator'. Or we can put this creating logic in 'Dictionary'
init methods. But it will be helpful to have this class this will
enable the dictionary add-word features.
Once DictionaryCreator creates a dictionary, User will be ready to use it. So we will need to provide different operations that a user
can perform on 'Dictionary' as its methods. In our case we can
consider user is over controller, which in fact is controlled by real
user.
The above techique will help you to create a component that performs only its responsiblity and can be reused in other application or extended for future use.
*Always remember Model is the most reusable component of MVC design. So whenever you are in doubt about Model just go remind the words 'Model must be reusable'.
(Not aware of views or controllers)
So we have just finished Model part of the application.
View Part:
This depends on you, what interface you wish to provide to user. But lets again consider the real world Dictionary. A real world dictionary's content(information) is spread across several pages. This view helps us to view/access/mark/bookmark in dictionary.(Remember that here user performs all the operation and not the pages neither the dictionary). The pages have easy look-up word on top or bottom and some pronunciation guidance at bottom.
In your application you said "I want to be able to hit a button and have a label display a word on one side of the screen, and to have another label display a list of associated words on the other side."
Here we have again have multiple options to implement this, you can create view using Interface Builder and connection them with your controller. But then again this controller and View will be tightly coupled and when we wish to use similar interface somewhere else we will be unable to do so. So for reusability we will create another UIView class and create it with a new View XIB and load this nib. So in future if you need similar kind of view you can easily reuse(like cocoa-touch provides us UIView, UIButton etc.).
*View also tends to be a reusable component in MVC.
(Not aware of controllers, may be aware of relevant model objects)
Controller Part:
Now we have created view and model but how will they communicate? Controller will help them in this. A controller :
Knows about model and view objects
The brains of the operation
Manages relationships and data flow
Typically app-specific, so rarely reusable
*The points and definition I have taken from Stanford University Lectures[CS193P - Lecture 6
iPhone Application Development
Designing iPhone Applications Model-View-Controller (Why and How?) View Controllers]
Update:
Recently, I have come across another good lecture on MVC. It explains this design concept in much better way with very nice examples. It is available at iTunes U or you can directly go to first lecture by iPad and iPhone Application Development (SD) by Paul Hegarty.
The question is quite simple: When I create a new API or Service Class should I create a custom class for the objects that are being passed around or should I just stick to an NSDictionary which simply holds the data in a key-value-style format.
Obviously there are pros and cons but where do you guys think is the threshold of using one over the other?
NSDictionary:
+ No dependencies
+ Very Flexible
+ Commonly used
+ Build-in support for NSCoding
- Structure not defined -> Runtime errors
A custom Object:
+ Structure defined
+ Property-style accessors: myObject.someProperty
- Can result in a rel. big number of classes for nested objects
Update: Included remarks from jbat100
I usually have a set of domain models, which fit better with the MVC approach of iPhone development. Having specific objects also enables you to enforce type-safety a lot easier and also reduces complexity in the long run. If you have NSDictionaries containing NSArrays and more NSDictionaries etc etc to represent your object graph, it can very quickly become unmanageable.
It really depends how much you expect your data model to change. Dealing with changes once you have a custom class based data model can be tricky especially when you have archives (NSCoding stuff) with different versions of the model (in already shipped versions of your app), you must be very careful to ensure backwards compatibility and avoid nasty run time surprises. In that respect NSDictionary based models are, as you say more flexible. However they do not allow all the customized checks and behaviour that custom classes do. Also custom classes make the data model more explicit for coders unfamiliar with the code, from my experience, developers often get sloppy (especially when inexperienced) when dealing with NSDictionary based models which can quickly result in an incomprehensible mess, so if you go down that route, document well and be disciplined!
If you need readonly access and do not need methods, you can do following:
#interface NSDictionary (MyClassCategory)
-(NSString*) someField;
#end
#implementation NSDictionary (MyClassCategory)
-(NSString*) someField {
return [self objectForKey:#"someField"];
}
#end
typedef NSDictionary MyClass;
And use it:
MyClass* myClass = ...;
NSString* value = [myClass someField];
I am little bit backward in knowledge on these three topics: NSMutableDictionary, NSEnumerator, NSMutableSet. When I want to use them, it feels very hard, even when I've gone through the developer documentation.
Is there any sample code to understand it clearly for all three topics?
Please help me.
Thank you,
Madan Mohan.
The best way to understand these depends on what your prior experience is. NSDictionary is exactly what it sounds like: a dictionary. What that means is that given a key (or a headword, as in a dictionary), you can look up a value (or definition):
For instance, this dictionary gives information about my dog:
KEY VALUE
-------------------------------------------
#"name" #"tucker"
#"species" #"canis lupus familiaris"
#"favorite" #"biscuits"
With a dictionary dogInfo containing that information, we could send [dogInfo objectForKey:#"name"] and expect to receive #"tucker".
The difference between NSDictionary and NSMutableDictionary is that the latter allows changes after initialization. This lets you do things like [dogInfo setObject:#"fetch" forKey:#"game"]. This is helpful for maintaining state, memoizing referentially transparent requests, etc.
NSSet is a way to have a bunch of objects, with a few important bits: there is no defined order to those objects, and there can only be one of each object (no duplicates). Use NSSet for when you need to contain unique, unordered objects. NSMutableSet is the variant of NSSet which allows for changes (such as adding or removing objects) after initialization.
NSEnumerator is a bit more complicated, but you usually won't need to deal with it unless you are writing your own libraries, are coding archaically, or are doing complex enumerations. Subclasses of NSEnumerator are used by collection classes, such as NSDictionary, NSArray, and NSSet, to allow their objects to be enumerated. Usually, you'd just enumerate over them using a foreach-loop, since they all implement <NSFastEnumeration>. But sometimes, you'll want to do more specific things, like enumerate over the objects (instead of the keys) of a dictionary, or enumerate over an array in reverse. This is where instances of NSEnumerator (usually defined as properties on your collection objects) will become helpful.
Update
Justin in the comments pointed out that NSEnumerator conforms to <NSFastEnumeration>; that means, the chances are next-to-nothing that you'll need to know how to use an NSEnumerator; you can just do a foreach loop over the enumerator itself, like so:
for (id object in [dogDict objectEnumerator]) {
// doing something with the object, disregarding its key
}
I have a model that essentially stores contact info: phone, twitter, address, etc.
I need to show that data in a UITableView, so I need essentially 3 pieces of information: a label ("Phone"), the actual data ("(123) 456-789") and a URL to handle that data with the right application ("tel://whatever").
I was thinking of using 3 arrays, one for each piece of info, and going through each attribute, see if it's given (could be optional), and if so, add stuff to the 3 arrays for that attribute.
Then, in the data source for the table view, each row can reference an index in the 3 arrays to populate the cell.
The order is important so I can show address before phone, etc.
Can anyone come up with a more elegant way to design the model so that I may not need 3 arrays, or lots of:
if(self.phone != nil)
{
[labels addObject:#"foo"];
[descs addObject:self.phone];
[urls addObject:#"baz"];
}
There will only be one "Contact" that can have a varying number of attributes, depending on some outside condition. So each attribute is optional. The table view will show the attributes of that one contact, in a certain order.
Thanks!
I believe you should create a model class, with properties for each attribute. Otherwise this will come back and bite your ass some day.
Storing the values in an array, means you have stored presentational meaning into the model. Breaking the MVC pattern.
This also means you can have some actual logic in your model object, which will reduce potential defects allot. As an example:
// Contact.h
#interface Contact : NSObject {
}
#property(nonatomic, copy) NSString* phoneNumber;
#property(nonatomic, readonly) NSURL phoneNumberURL;
#end
// Contact.m
#implementation Contact
#synthesize phoneNumber;
-(NSURL*)phoneNumberURL {
return [NSURL URLWithString:
[#"tel:" stringByAppendingString:self.phoneNumber]];
}
#end
This way you do not have to update the URLs from outside the model object. The model object should be able to derive this information itself. This will ensure that your application logic is not spread out into dozens of different places, but are kept in well defined pockets of logic that are easy to maintain.
I have a bunch of Boy objects and a bunch of Girl objects. I want to keep a list of the girl that each boy likes the most. It is OK if multiple boys like the same girl.
I was going to use an NSMutableDictionary, but the setObject: forKey: method of that class copies the key before adding the pair to the dictionary. So rather than the boy liking the girl, we would have a clone of the boy liking the girl.
Normally I would do this by adding a favoriteGirl property to the Boy class. But the problem is that the boys are really UIView objects, so I would have to subclass a bunch of different UIView subclasses.
Obviously I could write my own custom class to do this . . . but it feels like Apple must have a simple way to do what I want . . . what am I missing?
The speed of the lookup is important.
One option I thought of was to implement copying as a category on UIView objects, and just have the method retain the object. But I'm nervous about what side effects this might have.
EDIT: the girls are not UIViews. They are objects that contain information the boys will want to refer to from time to time.
You can do this with a CFMutableDictionaryRef (the Core Foundation equivalent of NSMutableDictionary). You can specify different options about how keys and values behave (like whether they're retained or copied, etc).
Using [NSValue valueWithNonretainedObject:] as the key is a better way, but be really careful that the objects will not be retained so you have to make sure to remove it from the dictionary when you release your original object.
I am not sure that I understand the model. Is it that you want to be able to map each Boy to a single favorite Girl? So, it would be okay to have a map from Boy to vector of Girl? If so, you could use std::map, std::vector > ... in other words, go over to Objective-C++ and use the Standard Template Library's map and vector containers.
It sounds to me that what you really need is separate model classes for Boys and Girls (then perhaps BoyView and GirlView if they're actually different, otherwise maybe a simple PersonView).
If you have a simple class to represent a Boy or Girl, then you can override isEqual: which I think would eliminate your issue with NSDictionary copying keys (though I'm not sure I entirely understand your model either).