Property List management - iphone

I am trying to create an app that has a list of users and each user will be assigned an array of data that is editable. I am new to persistent data so i thought a property list would be the easiest to use. The first view of the app will have a list of the users that have already edited at least their name, and then have "New User" for each property list that has not yet had anything edited. (I am sure there is code to have the program create new property lists each time a person clicked on "New User" but that is probably far too difficult for me so for the time being I have just simply defined 3 property lists that will correspond with my 3 users.)
So, for the 'viewDidLoad' portion of my apps main screen i need to populate a UIPicker with the names of the 3 users (or "New User" if there have not been any editing). I did this:
NSString *filePathForProfile1 = [self dataForProfile1];
NSString *filePathForProfile2 = [self dataForProfile2];
NSString *filePathForProfile3 = [self dataForProfile3];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePathForProfile1]) {
NSArray *arrayProfile1 = [[NSArray alloc]initWithContentsOfFile:filePathForProfile1];
NSArray *arrayProfile2 = [[NSArray alloc]initWithContentsOfFile:filePathForProfile2];
NSArray *arrayProfile3 = [[NSArray alloc]initWithContentsOfFile:filePathForProfile3];
NSArray *array = [[NSArray alloc]initWithObjects:[arrayProfile1 objectAtIndex:0],[arrayProfile2 objectAtIndex:0],[arrayProfile3 objectAtIndex:0],nil];
self.profileData = array;
arrayProfile1.release;
arrayProfile2.release;
arrayProfile3.release;
}
Now, because I have been running the program, there is already a file saved for Profile1 so the picker does display the name for that one - but for the life of me I can't quite figure out how to have it display "New User" for the other 2. I tried to set up an if-then statement with that fileExistsAtPath argument to create init the array with "New User" but then I couldn't pass the array out of the argument. Help Please!!

I would recommend you to have a look at the Archives and Serializations Programming Guide.
The most proper solution (well there is core data as well...) for your problem could be object serialisation.
You probably have an array of "Person"-Objects and the Person Class has a MutableArray of "Data"-Objects.
All you have to do then is make the Person-Class and the Data-Classe(s) NSCoding compliant. Afterwards you can easily persist your Array of Persons by something as easy as : [NSKeyedArchiver archiveRootObject:yourPersonsArray toFile:yourFilePath];
also there is a usefull tutorial found NSCoding / NSkeyedArchiver Tutorial
cheeers,
sam

Related

How to get values of a specific key from an array of custom model objects

I have an array of custom objects which contains a custom object Address with properties street, area, state, country.
I need to get all the the names of the areas from that array so i did some thing like this.
NSMutableArray *areas = [[NSMutableArray alloc]init];
for (Address *item in addresses) {
[areas addObject:item.area];
}
Now areas contain all the names of the area.
Is there any other way to get the all the areas of address items with out looping through the array of addresses (as above), using predicates or some other way.
Well as long as the object is KVC-compliant for the area property then simply:
NSArray *areas = [addresses valueForKey:#"area"];
(If you want areas to be mutable, as per your code, then you'll need to use mutableCopy in the above statement).
See [NSArray valueForKey:]:
Returns an array containing the results of invoking valueForKey: using
key on each of the array's objects.
Also We are using mutableArrayValueForKey: method to get the array of values corresponding to the key
NSMutableArray *areas = [addresses mutableArrayValueForKey:#"name"];

Instantiating Custom Object with Core Data

Currently whenever I want to save a custom object called List I use
(Core Date + Magical Record)
List *list = [List MR_createInContext:_managedObjectContext];
Now I'm wondering whether I could instantiate a List item like this
List *localList = [[List alloc] init];
// set some properties
localList.name = #"foobar";
List *newList = [List MR_createInContext:_managedObjectContext];
newList = locaList
Will this cause any problems with Core Data/memory issues?
No, for a couple of reasons:
You can't use init with managed objects. The designated initializer is initWithEntity:insertIntoManagedObjectContext:. There's also a convenience constructor on NSEntityDescription called insertNewObjectForEntityForName:inManagedObjectContext:. If you don't use one of those, you'll have problems.
When you assign newList = localList, you throw away the previous object in localList with all of its data. All that's left after this point is the one you originally assigned to newList. Your assignment to localList.name, for example, disappears with the localList object.
Since you've defined List it's hard to say whether you're creating a List instance correctly in both cases. At the very least your code leaks the second List that you create, and it seems unlikely that that code does what you think it does.
Your code is equivalent to:
List *localList = [[List alloc] init];
// set some properties
localList.name = #"foobar";
List *newList = localList;

copying object from NSMutableArray to another using IF statement

OK, maybe I'm not seeing clear anymore and hope you can help.
I'm trying to select an Object from a NSMutableArray using:
if([car.seat isEqualToString:#"fancyOne"]){
fancyThings = [[NSMUtableArray]init];
[fancyThings addObjects: car];
}
Now I forgot to tell you I'm new at this Objective-C, so maybe I'm thinking the wrong way.
What I'm basically trying to do is to get an Object from one array by selecting a value of it's components.
This is the way to do it, I am however keep having trouble with my if-statement.
If I leave out the IF-statement it does fill my other NSMutableArray with the exact same object (thisCar) but if I put in the IF-statement it doesn't pick up that the string is the same in thisCar.seat.
I next example it puts everything in the normalThings but there are some aCar.seats which contain the string FANCYONE. I checked the XML file on spaces and that sort of things but everything is in order as far as I can see.
Shall I build it using NSScanner instead of IsEqualToString?
- (void)viewDidLoad {
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.fancyThings = [[NSMutableArray alloc]init];
for (CARS *aCar in appDelegate.someCars) {
if ([aCar.seats isEqualToString:#"FANCYONE"]){
[appDelegate.fancyThings addObject:aCar];
}
else {
[appDelegate.normalThings addObject:aCar];
}
}
self.title = #"Cars";
super viewDidLoad];
}
EDIT:
My BAD!! The code supplied was in fact in order!
There was a mistake in my XMLParser, which added blank lines to the strings, so I couldn't get an equal string!
Hopefully this will give you some guidance:
//init new array
NSMutableArray *fancyThings = [[NSMutableArray alloc] init];
//walk your array
for (SomeCarObject *thisCar in arrayOfCars) {
//is thisCar a qualifying object
if ([thisCar.seat isEqualToString:#"fancyOne"]) {
//yes, add thisCar object
[fancyThings addObject:thisCar];
}
}
You'll want to create that NSMutableArray outside of the for loop (assuming you're iterating through a collection). Then you can add to that NSMutableArray like you did.
Hope this helps!
BTW, you should edit your question with the comment you made to elaborate on it..
It's depends from volume of objects, which u deal with. If there is 1000 objects or less, this method looks good. But if there is more objects, u have risk to freeze u application and have a big memory leaks.
Also if u will need concurrency code later, u have to keep in u mind some
other solutions.
U can using not just a string objects in u array, u can try to fill u array after application startup in objects, which response if string is same or not. Or using nsdictionary with appropriate keys.
Please read my post multithread search design

iPhone: How to write plist array of dictionary object

I'm a young Italian developer for the iPhone. I have a plist file (named "Frase") with this structure:
Root Array
- Item 0 Dictionary
Frase String
Preferito Bool
- Item 1 Dictionary
Frase String
Preferito Bool
- Item 2 Dictionary
Frase String
Preferito Bool
- Item 3 Dictionary
Frase String
Preferito Bool
exc.
An array that contains many elements dictionary, all the same, consisting of "Frase" (string) and "Preferito" (BOOL).
The variable "indirizzo", increase or decrease the click of the button Next or Back. The application interface:
http://img691.imageshack.us/img691/357/schermata20100418a20331.png
When I click on AddPreferito button, the item "Preferito" must be YES. Subsequently, the array must be updated with the new dictionary.The code:
(void)addpreferito:(id)sender {
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Frase" ofType:#"plist"];
MSMutableArray *frase = [[NSMutableArray alloc] initWithContentsOfFile:plistPath];
NSMutableDictionary *dictionary = [frase objectAtIndex:indirizzo];
[dictionary setValue: YES forKey:#"Preferito"];
[frase replaceObjectAtIndex:indirizzo withObject:dictionary];
[frase writeToFile:plistPath atomically:YES];
}
Why not work?
Thanks Thanks Thanks!
What Jason said is correct, but it looks like there's another, more serious problem in your code: it appears that you're passing a primitive value (the defined constant YES) as the first argument to -setValue:forKey:, which expects an argument of type id (in other words, an object, not a primitive).
Instead, you can use an instance of NSNumber to wrap the boolean value, and then put it in the array, like so:
[dictionary setValue:[NSNumber numberWithBool:YES] forKey:#"Preferito"];
You are loading your initial plist from inside your application bundle. Unfortunately, you cannot write to this directory. When you need to do is check if your plist already exists in the user documents directory. If it does, load it from there. If not, load your template (original) from inside the application bundle. When you write the file back, you must always write it to the user documents directory.
For more information on managing your application's files, please see the Files and Data Management section of the iPhone Application Programming Guide.

Good practices for multiple language data in Core Data

i need a multilingual coredata db in my iphone app. I could create different database for each language but i hope that in iphone sdk exist an automatically way to manage data in different language core data like for resources and string.
Someone have some hints?
I've done something similar to Shortseller, but without the use of categories.
InternationalBook and LocalizedBook are both custom managed objects with a one-to-many relationship (one international book to many localised books).
In the implementation of InternationalBook, I've added a custom accessor for title:
- (NSString *)title {
[self willAccessValueForKey:#"title"];
NSString *locTitle = nil;
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"locale==%#", [DataManager localeString]];
NSSet *localizedSet = [self.localizedBook filteredSetUsingPredicate:predicate];
if ([localizedSet count] > 0) {
locTitle = [[localizedSet valueForKey:#"localizedTitle"] anyObject];
}
[self didAccessValueForKey:#"title"];
return locTitle;
}
[DataManager localeString] is a class method which returns the user's language and country code: en_US, fr_FR, etc. See documentation on NSLocale for details.
See the "Custom Attribute and To-One Relationship Accessor Methods" section of the Core Data Programming Guide for an explanation of willAccessValueForKey: and didAccessValueForKey:.
When populating the data, I grab a string representing the user's current locale ([DataManager localeString]), and store that along the with localised book title in a new LocalizedBook object. Each LocalizedBook instance is added to an NSMutableSet, which represents the one-to-many relationship.
NSMutableSet *bookLocalizations = [internationalBook mutableSetValueForKey:#"localizedBook"]; // internationalBook is an instance of InternationalBook
// set the values for locale and localizedTitle
LocalizedBook *localizedBook = (LocalizedBook *)[NSEntityDescription insertnNewObjectEntityForName:#"LocalizedBook" inManagedObjectContext:self.bookMOC];
localizedBook.locale = [DataManager localeString];
localizedBook.localizedTitle = theLocalizedTitle; // assume theLocalizedTitle has been defined.
[bookLocalizations addObject:localizedBook];
[bookLocalizations setValue:localizedBook forKey:#"localizedBook"];
Since the localised titles are being stored in the LocalizedBook managed object, you can make the title attribute a transient, but if you do that you can't use title in a predicate.
The nice thing about this approach is that the implementation of the to-many relationship is transparent to any consumers. You simply request internationalBook.title and the custom accessor returns the appropriate value based on the user's locale behind the scenes.
I have generated model classes for the core data entities.
Then I defined category helper classes with functions to set and get the multilanguage properties (e.g. name).
So I have a Product (with e.g. code and price) and a ProductLanguage (with language and name properties) Entity.
I never directly access ProductLanguage, but always use the name function defined on the the Product model (via category). This has worked well for me sofar.
Like Gordon, I use quite similar code, but not written files generated by model. I use this code in my .m file where I want to show the data.
As I start from Apple template, I put this code exactly in
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
of my TableViewController.m
P.S: Just to understand, I use these prefixes: tbl_ for tables (entities), rel_ for relationships, fld_ for fields (attributes).
Hope this helps.
NSSet *sourceSet = [NSSet setWithArray:[[tbl_MainTable rel_Localization]allObjects]];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"fld_Locale == %#", [[NSLocale preferredLanguages] objectAtIndex:0]];
NSSet *filteredSet = [sourceSet filteredSetUsingPredicate:predicate];
//NSLog(#"%#", filteredSet); NSLog(#"%#", [[filteredSet valueForKey:#"fld_Name"] anyObject]);
if ([filteredSet count] > 0)
{
[cell.detailTextLabel setText:[[filteredSet valueForKey:#"fld_Name"] anyObject]];
}