Could you tell me please, how can I make something like this:
For example I have an app which contains info about your pets. But firstly, you should add a pet to a database. In a special view, you enter your pet's name, age, breed, color and etc (keys) and then you save it. Here we are, now you have your first pet in the app. But then you wanna add new pets...
How can I save all these dictionaries with same keys ? You don't know how may dictionaries to create because you don't know how many pets an user wanna add in the app. What is the easiest way?
What if user wants to add like thousands of pets in the app ? I am sure, I shouldn't create thousands of dictionaries in the code for every possible animal. But how do I do that ?
Like dictionary1 for Deisy, dictionary2 for Bruno, dictionary3 for Hamlet and etc.
Here is a rough description of how it could work:
Somewhere you need to define a collection to hold that pets.
NSMutableSet *myPets = [[NSMutableSet alloc] init];
When the user has entered the data and presses the save button, some method is called in your view controller. Within that method you collect the data, like this:
NSDictionary *pet = [NSDictionary dictionaryWithObjectsAndKeys:nameField.text, #"name", breedField.text,#"breed", nil];
[myPets addObject:pet];
At this point the pet has been put into the myPets NSMutableSet and the compiler will release it, so it doesn't exist anymore. The next time the user enters data and presses the button again, a new pet will be created and put into myPets. Don't worry about millions of instances being created, the compiler will take care of it.
If you want to retrieve individual pets afterwards, you can do something like this
for (NSDictionary *aPet in myPets) {
if ([[aPet objectForKey:#"name"] isEqualToString:#"Lassie"]) {
// do what you want to do with Lassie
}
}
You need an NSArray to hold the NSDictionaries.
Related
When I click a button, a UIAlertView prompts the user to type a name. This name is then created as a new 'Customer' object and inserted into a mutable array.
There is a separate mutable array called 'CustListByName', which stores a list of all names.
The problem im having is that when adding a second or third name, the app crashes. Sometimes it happens on the second try, other times on the third try. There is no information given in the debugger except for (lldb). The program reports EXC_BAD_ACCESS and then it dumps me to a screen with a bunch of assembly code.
The crash is happening in these lines of code:
Essentially, it clears the array of names and then repopulates it based upon the object array. I've studied in step by step with a breakpoint but everything seems correct up until the point of crash. It is also confusing why this happens on the second or third try, never the first.
[custListByName removeAllObjects];
for (Customer *object in custListByObject) {
[custListByName addObject:object->name];
}
Here is the code where a customer is created and inserted everytime the new customer button is clicked:
Customer *tempCust = [[Customer alloc] init];
tempCust->name =[[alertView textFieldAtIndex:0] text];
[custListByObject addObject:tempCust];
[tempCust release];
I would really appreciate help with this, thanks!
What I suspect is happening is that the UIPickerView is attempting to load a row using information from your customer array after you have already cleared it, and before you repopulate it. This would cause a bad access error.
What you may consider doing instead, is keeping two arrays, an NSMutableArray for loading the customers, and an NSArray as the actual data source for the UIPickerView. Then right before you reload the UIPickerView, you say:
dataSourceArray = [loadingArray copy];
[pickView reloadAllComponents];
Hopefully this helps.
Edit:
Here's what your updated code would look like if your loading array was called loadingCustListByName:
[loadingCustListByName removeAllObjects];
for (Customer *object in custListByObject) {
[loadingCustListByName addObject:object->name];
}
custListByName = [loadingCustListByName copy];
[pickView reloadAllComponents];
Doing this will ensure that the UIPickerView's datasource array always matches up with the number of rows it thinks it has.
I retrieve 6 values(say name, age, sex, address, id, tag) from a web service. All are string variables. I concatenate these strings and add it to an NSMutableArray. I pass this array to another class, where I need each of these strings separately. That is I need to be able to retrieve these values from the array separately. How can I do this.
Do I need to add tags like "Name", "Age" etc along with the values to make the retrieval easier. Whats the appropriate way to do it.
Edit: i concatenate it into a single string. How should I be adding my values to the collection, so that I can retrieve the elements easily.
IMO, the most appropriate way of doing what you are trying to do is using an NSMutableDictionary, that allows you to access individual elements based on their key.
Example:
loadedBuffers = [[NSMutableDictionary alloc] initWithCapacity:CD_BUFFERS_START];
[loadedBuffers setObject:bufferId forKey:filePath];
...
[loadedBuffers objectForKey:filePath]
You do no strictly need using a dictionary, but it will make your life so much easier.
In your case (if I understand it correctly), I would do:
NSMutableArray* result = [NSArray arrayWithCapacity:kNUM_OF_ROWS];
NSString *name, *age, *sex....;
<for each set of strings from the web service>
<retrieve strings>
NSMutableDictionary dict = [NSMutableDictionary dictionaryWithCapacity:kNUM_OF_FIELDS];
[dict setObject:name forKey:#"name"];
...
[dict setObject:address forKey:#"address"];
[result addObject:dict];
<end_for>
return result;
By doing like this, you will be able to access sequentially each set of strings; then access each string individually.
In short, instead of encoding your set of strings by concatenating them into another string, you would expand them in a dictionary to make retrieval easier.
I would agree that the best practise here would be to use a dictionary or custom object. That way each string gets stored with its companions (e.g. you have one person's data all together) and you don't have to deal with the messy method you already have implemented. It sounds like you might want to save data, so here's a snippet to help you. If that's not what you're after, let me know and I'll modify my response to help!
Say you have a custom object class Person, where you create and manage data objects to save to disk via the app delegate. You'd do something like:
Person *newPerson = [[Person alloc] init];
[newPerson setName:#"John"];
[newPerson setAge:#"25"];
[newPerson setSex:#"M"];
[yourAppDelegate.newPersonArray insertObject:newPerson atIndex:[mainDelegate.newPersonArray count]];
Currently, I have an application where a user clicks on a map and adds annotation points with certain subtitles. However, when the phone is power-cycled, all their added points are gone. I'm interested in making these annotations persistent. I've been trying to figure out how to do this with Core-Data, but after reading this tutorial here: http://www.raywenderlich.com/934/core-data-tutorial-getting-started, I'm a bit lost on where to start.
Any help would be appreciated, thanks.
If you have a core data application set up, you will only need to create an entity in the xcdatamodel file. Add attributes for whatever you may want to store.
latitude - double
longitude - double
title - NSString
etc. until you have what you want.
When you want to add an annotation, you should create a new core data object for your entity. It will look something like this
Location *newLocation = (Location *)[NSEntityDescription insertNewObjectForEntityForName:#"Location" inManagedObjectContext:self.managedObjectContext];
Location.latitude = ....
// and so on to store the information you want in its attributes;
You can set the attributes at different point if you change the values at a later point. You just need to be able to access the right object to go with the annotation. You should be able to do this by using NSFetchRequest in your managedObjectContext. You can use NSPredicate to filter the objects to the one you want. Then when you are ready to exit the app, save your context using
NSError *error = nil;
if ([managedObjectContext save:&error]) {
// handle the error;
}
which will store all the objects you've added to be used next time you open the app. You will then be able to create your annotations based on the objects in your managedObjectContext. I hope this is what you were looking for, or at least gives you an idea how to approach what you'd like to do.
I'm trying to create a user editable plist where the user can store a custom created workout routine including strings referenced from another data.plist in the app bundle.
I'm assuming NSCoding is the best way to go about this. So far I have the interface setup as a nav bar and table view.
I want it to be blank be default and the user has to press the "+" that is in the top right of the nav bar. Then he could enter a name for an entry in an array, for example chest day, or bicep day. And within that array, will be a dictionary or another array of strings of the particular exercises for that day, for example bench press, or bicep curl.
This plist needs to be editable so it will be going in the users document folder and not in the app bundle.
Example:
Top array consists of Chest Day, Back Day, Leg Day. Within Chest Day dictionary, include bench press, chest pull, pushup, etc.
Update:
Adding this method to search for routine file;
-(void)loadData
{
if(YES)
{
NSString* documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* routineFile = [documentsPath stringByAppendingPathComponent:#"routine.plist"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:routineFile];
}
else
{
//load file
}
}
NSCoding is the protocol used by NSArchiver, NSKeyedArchiver, etc., not for serializing an array into a property list.
Forget about the idea that the user is going to edit a property list. The user is going to edit data in your app -- the fact that it's stored as a property list is just an implementation detail. When your app starts, you read the data stored in the data file. The user edits it, looks at it, whatever. At some point later, perhaps after each edit, perhaps just before the app quits, you write the data back out to the file. Since it's a property list, don't worry about updating the file; you already have all the data, so write a whole new property list and then use that file to replace the old one.
Perhaps I'm wrong and you really do intend for the user to edit the property list by hand, with a text editor. This would be a mistake. It's great the property lists are human readable, but asking your users to edit your raw data files by hand is a strong indication that your app is broken. The whole purpose of your app is to keep track of this information for the user; if they wanted to use a text editor to manage it, they wouldn't need your app. So, with that said, I hope I'm not wrong. ;-)
I don't think I'd use NSCoding for this - if all you're working with is standard plist objects like NSArray, NSDictionary, and NSString, the top array's -writeToFile:atomically: method is an easy way to do the job.
greetings Cocoa masters - this simple issue has me crawling the walls. I have a custom class called Movie which consists of a bunch of properties and a few collections. I am populating it successfully using FMDB and SQLite. However, with each pass through the result collection from the DB, my addObject: seems to be writing over the entire array:
SciFiLib = [[NSMutableArray alloc]init];
FMResultSet *SciFiResultSet = [db executeQuery:#"select Movie.*......];
Movie *m = [[Movie alloc] init];
while ([SciFiResultSet next]) {
m.movieID =[SciFiResultSet stringForColumn:#"movie_id"];
m.title = [SciFiResultSet stringForColumn:#"title"];
.....
[SciFiLib addObject: m];
At this point - I have NSLog'd the output of m - and it contains a different movie (title, ID, release date, etc. - so I know the data is OK). However, starting with the 2nd pass through the WHILE loop each subsequent addObject replaces the entire array with copies of the next data item. So at the end of my loop, I have 6 copies of the same movie data.
I have mirrored my custom class here with just an array of the movie titles, and that seemed to work, but I'd like to collect all of the properties of the movie(s) for my Model data. Can anyone shed some light on what might be causing this behavior?
Thanks in advance for your help and advice!
...
I think it's because you're just adding a pointer, and then reapplying the data to the same object "m". Make "m" inside the loop and release it so it gets remade each time.