I want to show a table with the list of strings which are localized.
The straightforward method would be:
a) Point data source to my ViewController
b) Define an array
c) Allocate the array in my ViewController and init (arrayWithObjects) it with the strings from localized resources (NSLocalizedString)
d) Use this array in UITableViewDataSource delegated methods
Mainly my concern is item b). The construction looks quite heavy and I wonder whether I can somehow specify and load whole list of localized string at once.
Do you mean that you want to have an array that contains all the keys defined in your Localizable.strings file?
That's pretty easy actually, as .strings files are in a format that correspond the the Old-ASCII-Style for the plist format containing a dictionary (the enclosing curly braces that normally need to be present in this Old-ASCII-Style plist format to enclose a dictionary being silently ignored).
So you can simply load the content of your Localizable.strings file into a NSDictionary and you are good to go!
NSString* stringsPath = [[NSBundle mainBundle] pathForResource:#"Localizable" ofType:#"strings"];
NSDictionary* locStringsDict = [NSDictionary dictionaryWithContentsOfFile:stringsPath];
NSLog(#"locStringsDict = %#", locStringsDict);
NSArray* localizedStrings = locStringsDict.allValues;
NSLog(#"All localized strings in current language = %#", localizedStrings);
Of course if you only want some of the localized strings, you could:
Either put the strings you want in a separate ".strings" file (a.k.a. different Strings table)
Or make an NSArray of all the keys corresponding to the strings you need, and then loop thru them to build your NSArray of localized string for these keys, calling NSLocalizedString on each key entry
[EDIT]
Note that it seems that strings files are compiled into binary plists before being embedded in the final application (just tested it on a sample project). Thus once your application is running, the Localizable.strings file is a binary plist (namely [NSString stringWithContentsOfFile:stringsPath encoding:0 error:nil] will not return the original content of your Localizable.strings file but some binary data interpreted as some junk string, and the original file is not accessible anymore)
So if you want to keep the order of the keys, the only other option is to parse the original strings file before compilation, and not at runtime. The best choice for that is probably IMHO to convert the strings file into an XML Plist using plutil -convert xml1 Localizable.strings -o - and extract the keys from there, for example using some simple XSLT stylesheet. The stylesheet could even directly turn the extracted keys into some new XML plist that will represent an NSArray of those keys, in the expected order, so you can load this plist into an NSArray by code and use them at runtime.
Related
I am learning Objective-C language. I have covered the following questions:
What is plist?
How to create a plist file?
What are the representation of plist file?
But I did not find the answer of these questions:
Why do we store a plist in NSArray?
What is the need to store a plist into NSArray?
Can you please help me to clear my doubts?
Sometime you want to do something at runtime or create something base on something else.
Let's imagine you have a game with a different levels and you want the levels to be vary you can hard code the levels in code but much nicer would be store it in the file. iOS lets you very easily load plist to array or dictionary and that's the reason why iOS developers choose to use it.
// Example of plist file
Level1:
NumberOfEnemies: 6
ScoreTarget: 100
....
Level2:
NumberOfEnemies: 12
ScoreTarget: 120
....
When you load the game you can read the plist and you can load the level base on the content.
It's much easier to add another level or add more customisation to the plist (file) that go back to the code any do it there.
It's just one of the examples but you could use plist to do much more.
Plist are mostly configuration files or place to store some values that you know that will never change. One particular example of the plist file is info.plist where you define attributes for the application.
Plist are nothing else but the same old XML file with attributes and elements. That said, you actually access plist through dictionary, not array.
For your question why do we store it in dictionary, you use dictionary to access these values since there is no other way to extract the information from it.
One more thing, plists have their own restrictions regarding the type you can store: Array, Dictionary, String, Date, Data, Number and Boolean.
PList : is a "Property List" file, uses the XML format to store objects such as arrays, dictionaries, String, Data, Number and Boolean.
How to create :
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:#"myPlistFile.plist"];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#”myPlistFile” ofType:#”plist”];
[fileManager copyItemAtPath:bundle toPath:path error:&error];
}
[myDict writeToFile:plistPath atomically: YES];
Representation : Based on what is stored in plist file .
Key and Value. (NSDictionaries)
Key and multiple value . (NSArray) etc..
What is PLIST?
Plist stands for Property List. Plist is used to store data in hierarchical manner.A Property List can contain containers and primitives.
Containers – Array, Dictionary
Primitives – Boolean, String, Number(Integer,Float), Date, Data
A Container can contain other containers and primitive data-types.
i.e. Dictionary can contain other Dictionaries,Arrays and Primitives. Array can contain other Dictionaries,Arrays,Primitives.
How to Create PLIST File?
STEP 1: Right Click the Project
STEP 2: Choose New File
STEP 3: Select Resource from left side of the Template.
STEP 4: Then Click Property List
STEP 5: Click NEXT button of the Bottom.
STEP 6: Give property List Name.
STEP 7: Finally Click OK
For more Reference please go through the below link
https://stackoverflow.com/questions/9044735/steps-to-create-and-edit-a-plist-file-in-xcode
What are the Representation of PLIST file?
A property list can be stored in one of three different ways:
1. in an XML representation,
2. in a binary format, or
3. in an “old-style” ASCII format inherited from OpenStep.
You can serialize property lists in the XML and binary formats. The serialization API with the old-style format is read-only
XML property lists are more portable than the binary alternative and can be manually edited, but binary property lists are much more compact; as a result, they require less memory and can be read and written much faster than XML property lists. In general, if your property list is relatively small, the benefits of XML property lists outweigh the I/O speed and compactness that comes with binary property lists. If you have a large data set, binary property lists, keyed archives, or custom data formats are a better solution.
I refer the link for Why do we store a plist in NSArray? and What is the need to store a plist into NSArray?
1.http://hayageek.com/plist-tutorial/
2.https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/PropertyLists/AboutPropertyLists/AboutPropertyLists.html
3.http://nscookbook.com/2013/02/ios-programming-recipe-13-using-property-lists-plists/
4.Getting plist data in a order
Is it possible to export data to a Xcode-project file?
For example, I want to generate a new "hello.csv" file, using swift, that says "hello world"
into my Xcode Project locally but not in in-app document.
To put it simply, no. If you want to use databases in code, use .plist (Preference List) files. Unfortunately, I don't know how to do this in Swift, but I do know how to in Objective-C.
To start off, make a PLIST file in Xcode, and add your data to it. Remember the key name values.
In your .m file, add this code to create an NSMutableDictionary that you can modify in code later:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"yourFile" ofType:#"plist"]];
Then, to pull data out of the dictionary you made (dict), do something like this. Switch data types as necessary.
NSString *helloWorld = (NSString*)[dict valueForKey:#"yourKeyName"];
(Note: the cast of NSString* is necessary because, otherwise, it will yell at you for having the incompatible type of id. In Swift, it's object. If you plan on modifying the string, then use NSMutableString.)
Then, to save it to the file, save the key/value pair in the dictionary:
[dict setValue:helloWorld forKey:#"yourKeyName"];
And finally, save the dictionary and overwrite the PLIST file.
[dict writeToFile:[[NSBundle mainBundle] pathForResource:#"yourFile" ofType:#"plist"] atomically:YES];
Note: the writeToFile method's atomically parameter is asking whether or not it has to write the file right away or after it does whatever it needs to (as in, it's not a high priority). I recommend setting this to YES or true.
I'm programmatically building an array of dictionaries with hundreds of values I'm pulling from various sources. I then plan to go in and manually change a few of them as needed. I don't want to use this pulling method in the production code, I want to just store it as a vanilla array with dictionaries. However when using NSLog it returns the array obviously, but not as code I can copy and paste. I'd hate to have to go through several hundred values and and manually convert everything to be proper objective c code.
So in short, is there any way to return my array as actual code?
One approach would be to write the final array to a plist file. Then make the plist file part of your project. No need to generate code for the array. Simply load the plist into an array at runtime.
To save the array as a plist:
[myFinalArray writeToFile:somePath atomically:YES];
I have a large number of nested dictionaries and the leaf (or most nested) dictionaries store integer data and integer keys. All the information remains constant (but may change in a future release). I am currently allocating the dictionaries from constants in code but I feel I should be reading that information from XML or similar. I have read about Core information, plists, databases and archives but I don't want the user to be able to change it, I never want to be able to write it (except maybe during the release procedure) and I never want to display it. I would like to be able to hand edit it before release.
What is the best method to store this constant data?
Basically you need to ship your data in files with the app -
XML or JSON are both suitable for this. When I have had to do something similar I used JSON
It works something like this :
Define your JSON in text file (UTF8) and then use the
NSString initWithContentsOfFile to load file contents into a NSString
You can then use the NSJSONSerialization JSONObjectWithData to give you the top level dictionary for your JSON
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
From this you can extract your NSStrings / NSArrays using NSDictionary objectForKey for your data. Obviously the exact format will depend on your JSON format
I'm creating a simple iOS application consisting of a few UITableViewControllers. The information displayed in the view controllers will come from a text file (that I'll include in the project's Resources). The text file's contents will come from a spreadsheet.
Since this is my first time working with Core Data I have a few questions:
What format is most common for the text file? CSV, XML or something else?
What's the easiest way to import the data?
A few notes:
The data is static. Ideally the app will load the data into "Core Data" just once (1st time the app is run).
Each additional run of the app will just pull data from some Core Data source (that I'm not completely familiar w/ yet) instead of re-loading it from the textfile.
If the data is structured in a relational way then XML or JSON allows that structure to be easily preserved and then easily parsed and saved in your Core Data store. You'll need to use an XML or JSON parser, which will turn your data into an array of dictionaries (or multiple levels thereof if your data structure requires it). You'll simply iterate through the array and dig into the dictionaries (and sub-arrays and sub-dictionaries, if appropriate) and add objects to your store as you go.
If it's flat data, a simple single table that will become a single entity in Core Data, then tab-delimited or CSV text files are fine (and tab-delimited is even easier to parse if there wouldn't be any tabs within the data itself). You can then grab individual rows, break the rows down into an array of data bits (this is where tab delimiting makes is super-simple), create a new object for each row, set its properties to the array elements, and save the context.
The XML/JSON version is more complex than is worth writing out here -- search SO and you'll find lots of examples -- but here's the tab-delimited version (this assumes you don't have a gigantic ball of data that can't reasonably be held in memory):
// Standard Core Data setup here, grabbing the managedObjectContext,
// which is what I'll call it
// Then parse your text
NSString *path = [[NSBundle mainBundle] pathForResource:#"YourTextFileName" ofType:#"txt"];
NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
NSArray *rows = [content componentsSeparatedByString:#"\n"];
// Now that we have rows we can start creating objects
YourManagedObject *yourManagedObject = nil;
for (NSString *row in rows) {
NSArray *elements = [row componentsSeparatedByString:#"\t"];
YourManagedObject *yourManagedObject = (YourManagedObject *)[NSEntityDescription insertNewObjectForEntityForName:#"YourManagedObject" inManagedObjectContext:managedObjectContext;
[YourManagedObject setName:[elements objectAtIndex:0]];
[YourManagedObject setCountry:[elements objectAtIndex:1]];
// Etc. You may need an NSNumberFormatter and/or an NSDateFormatter to turn
// your strings into dates and numbers, depending on your data types
[managedObjectContext save];
}
Poof, all done.
If the data doesn't change, why bother including the text file in the app? Instead, create Core Data file on your Mac and include that as a resource in the app. I presume it's a lot of data that'll take a while to parse, so there's no sense in making your users each wait for that to happen when you could do the parsing once and distribute the result.
To make that happen, take the data model and the parsing code from your app and use them to build a small command-line app that just reads the text file, writes the Core Data file, and exits.