Array does not load data from plist - iphone

I'm not sure what exactly is my problem since I have been using this method for a while now and never had this problem.
Basically, as the title says. This code loads data from a plist located in the "Resources" group
NSString *myFile = [[NSBundle mainBundle] pathForResource:#"myList" ofType:#"plist"];
myArray = [[NSArray alloc]initWithContentsOfFile:myFile];
NSLog(#"%#", myArray);
It displays (null). Anyone know why?
I have in the same ViewController another one setup and works just fine. This particular plist does not load however. And I've also even deleted the plist and just created a duplicate from the other one to make sure is not a structure issue.
I am doing this the wrong way? Should I use FileManager?
UPDATE -------------------------------------------------------------------------
Ok so, I can't believe what I am about to say. lol
I am using XCode 4, the way you edit plists in Xcode is different from Xcode 3.x. As in the earlier versions you get to choose the root of the plists to be w/e you want them to (Array, Dictionary, etc) My problem was that the plist I was trying to load into a NSArray was in fact structured as a dictionary. However I never saw this in Xcode, and I have no idea how to see this other than browsing the contents using TextEdit or some other text editor.
Pretty silly I must say. Does anyone know why XCode 4 won't show the root of the plist the way XCode 3.x does?
XCode 3.x: http://dl.dropbox.com/u/919254/XCode3.png
XCode 4: http://dl.dropbox.com/u/919254/Screen%20shot%202011-04-10%20at%202.30.35%20AM.png

Use a dictionary instead. I've had undefined behavior with NSArrays and property lists. e.g.
NSString *myFile = [[NSBundle mainBundle] pathForResource:#"myList" ofType:#"plist"];
NSMutableDictionary* myDict = [[NSMutableDictionary alloc]initWithContentsOfFile:myFile];
NSLog(#"%#", myDict);

I had a similar situation. Solving:
select *.plist in tree
call context menu
select "Open with external editor"
root will be visible - change "Class" to "Array"
save

What you have looks right. Check that the file is in the right directory, and has contents. Might want to NSLog myFile while your at it.

Related

Writing values to a .plist more than once?

I have an iPhone App in the works, and I have a settings page within the app. I use a .plist to store the settings that the user picks, and then I read the data from the .plist later. This is not the -Info.plist that comes with it when you create the project, it is another plist file. When I tested the settings after coding it, it worked. The setting was able to be read, and it was the correct setting that I used. However, I went back to the settings in the same app-session, and changed the same setting. When I went to the app to see if it read the new setting, it only used the old (first) one. I tried again, but it yielded the same result. I am only able to write the setting once, and I cannot 'rewrite' or 'overwrite' the same setting. I cannot figure out what is wrong for the life of me.
You can't overwrite or write to files in the app bundle itself. If you want to write to a file, you should first copy it to the app's Library or Documents directory, something like this:
NSString *docsDir = [NSSearchPathsForDirectoriesInDomains(NSDocumentsDirectory, NSUserDomainMask) objectAtIndex:0];
NSString *plistFile = #"myplist.plist";
NSString *plistInBundle = [[NSBundle mainBundle] pathForResource:plistFile ofType:nil];
NSString *plistInDocsDir = [docsDir stringByAppendingPathComponent:plistFile];
[[NSFileManager defaultManager] copyItemAtPath:plistInBundle toPath:plistInDocsDir error:NULL];
// now `plistInDocsDir` is (over)writeable
However, for storing preferences of your app, it's better practice to use the NSUserDefaults class:
[[NSUserDefaults standardUserDefaults] setObject:#"Some string" forKey:#"MySettingKey"];
and/or create a Preference Bundle for your app.

How to get file path in iPhone app

I have a problem accessing my files in my app.
I am currently using
//Directly from TileMap example from WWDC2010
NSString *tileDirectory = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"Tiles"];
to access my tiles for my MKOverlay. This gives me this directory
/Users/xxxx/Library/Application Support/iPhone Simulator/4.2/Applications/9D62025C-C53B-472C-8309-xxxx/xxxx.app/Tiles
The x's is only for privacy reasons
I have my tiles in a folder called Tiles in the root of my application which is in Xcode in a group called Tiles which is in directly in the Resources group.
When I run my app, I get a simple error saying that it could not find my tiles at the generated directory (the one quote above) If I replace that piece of code and make it:
NSString *tileDirectory = #"/Users/xxxx/Documents/xxxx/Tiles";
Then my app works fine. This is obviously because it finds my tiles in its direct location on my Mac. This is fine for testing, but I need it to work on my iPhone/iPad.
This problem might be occurring due to:
The generated directory is incorrect.
The tile images aren't getting included in the builded .app file.
Either way, I have no clue of what to do to solve it.
How can I solve this problem?
[EDIT]
I changed that piece of code to:
NSString *tileDirectory = [[NSBundle mainBundle] resourcePath];
Now it works in simulator, because all files are in the apps root folder and I don't ask for it to enter another directory called "Tiles".
This runs with no error on the simulator, but when on my iPhone it gives the original error (just a different file path but also ending with /xxxx.app
How can I ensure a directory in my app file such as xxxx.app/Tiles - TileMap does this.
Since it is your files in your app bundle, I think you can use pathForResource:ofType: to get the full pathname of your file.
Here is an example:
NSString* filePath = [[NSBundle mainBundle] pathForResource:#"your_file_name"
ofType:#"the_file_extension"];
Remember that the "folders/groups" you make in xcode, those which are yellowish are not reflected as real folders in your iPhone app. They are just there to structure your XCode project. You can nest as many yellow group as you want and they still only serve the purpose of organizing code in XCode.
EDIT
Make a folder outside of XCode then drag it over, and select "Create folder references for any added folders" instead of "Create groups for any added folders" in the popup.
If your tiles are not in your bundle, either copied from the bundle or downloaded from the internet you can get the directory like this
NSString *documentdir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *tileDirectory = [documentdir stringByAppendingPathComponent:#"xxxx/Tiles"];
NSLog(#"Tile Directory: %#", tileDirectory);
You need to use the URL for the link, such as this:
NSURL *path = [[NSBundle mainBundle] URLForResource:#"imagename" withExtension:#"jpg"];
It will give you a proper URL ref.
You need to add your tiles into your resource bundle. I mean add all those files to your project make sure to copy all files to project directory option checked.

Can't write on plist file after deploying on iPhone

Dear all.
I am facing a problem.
I can read and write on plist while working on simulator of xcode. but when I deploy the app in iPhone, i can't write on plists.
I have created a sample project having 2 button on it. By one button, I can display the text from plist. By second button, I try to write on that plist. But the writing doesn't happen. The app doesn't crash while clicking on the second button. I can't understand the problem in my code.
/*code is given below*/
-(void)writePlist:(NSString *)fname withArray:(NSMutableArray *) myArray
{
NSString * path = nil;
path = [(NSString *) [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fname];
[myArray writeToFile:path atomically:NO];
}
It could be that myArray variable contains non-serializable object values (probably custom objects or something like that).
Does the directory you are trying to write to exist? You may want to verify its existence (and create it if it isn't already there) before trying to write a file into it.

Add String Attribute to CoreDataBooks

I've been messing around with CoreDataBooks and trying to add another field to the sqlite file in addition to the current three. I've added the attribute string in the .xcdatamodel, and declared it in the book.h, book.m, and localized file (all without changing the sqlite file). However, these changes never add the field in sqlite, and the app never loads. Each time I am deleting the app in the simulator and performing a build--> clean, but to no avail. I've also tried changing the sqlite file to match the .xcdatamodel but the app still fails to load.
Is this a problem with CoreDataBooks or me? Do I need to version the app before doing this? Doesn't seem like I should have to as long as I'm deleting the app in the simulator.
Anyone know how I can add this forth string attribute (sqlite field) in CoreDataBooks?
Thanks in advance!
I've found such a nice piece of code in CoreDataBooks
NSString *storePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"CoreDataBooks.sqlite"];
/*
Set up the store.
For the sake of illustration, provide a pre-populated default store.
*/
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"CoreDataBooks" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
in CoreDataBooksAppDelegate.m:154, this means for me that every time apps does not find sqlite file it is copied from bundle where it was not changed by modification of CoreDataBooks.xcdatamodel.
Try to use another approach, or just modify bundled sqlite file.
If the app doesn't load then there might be something wrong with your datamodel. Check the console for error messages.
And you have to decide if you want to use sqlite or core-data. If you want to monitor sqlite files for changes or add fields to sqlite files you should use sqlite and not core-data.
If you want to use core-data you should ignore the sqlite file.
Figured it out. The application WAS creating the new sqlite file, I just needed to find it within the simulator files. Grrrr, so much time wasted when I was doing everything correctly. Lessons learned I guess :)

Problem getting path to .plist using [[NSBundle mainBundle] pathForResource

I'm an Objective C noob, and I don't know enough to explain the following problem.
This code works:
NSString *plistPath = #"/Users/andrewf/MyApp/Resources/Plates.plist";
dicPlates = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
My dictionary object is loaded with values as expected.
This code does not work:
NSString *plistPath = [[NSBundle mainBundle] pathForResource:#"Plates" ofType:#"plist"];
dicPlates = [[NSDictionary alloc] initWithContentsOfFile:plistPath];
plistPath comes back with a value of nil. This is the case irrespective of whether I include inDirectory:#"Resources" in the call or not. All the examples that I have found do not include inDirectory when trying to open a .plist file in the Resources directory.
I have confirmed that the file exists in the correct location and even recreated it to be sure.
This seems like such a simple problem, but I am mystified. Please assist.
I think you're confused as to where pathForResource: is looking.
This works:
NSString *plistPath = #"/Users/andrewf/MyApp/Resources/Plates.plist";
Notice that this path does not point to your application. It points to your project directory. Your plist is supposed to be at #/Users/andrewf/MyApp/build/Release/MyApp.app/Resources/Plist.plist" (for an iPhone app this would be different, more like #"/Users/andrewf/Library/Application Support/iPhone Simulator/User/Applicatons/(unique id)/MyApp.app/Resources/Plates.plist"), and it is inside the Resources folder of your app that pathForResource: is looking.
What this implies is that your resource is not in the "Copy Bundle Resources" phase of your build target. You need to drag it from the Groups and Files area to inside that phase.
I have found the problem!
The .plist file was included in the target correctly.
When the .plist was originally created, I named the file "plates.plist". Immediately after creating the file, I renamed it to "Plates.plist", and this is what I used henceforth.
Even though the file was named "Plates.plist" in my resources folder, in the target section and in the iPhone Simulator location mentioned above, the file was named "plates.plist". Curiously, the contents of the file was still updated correctly.
Now that I have changed the code to refer to "plates.plist", and renamed the file in the Resources folder to the same for good measure, everything works. I can only assume that this is a bug in the iPhone SDK.
Check that the plates.plist file has been added to the target in Xcode.
If the file is not added to the target it will not be inside the build product and NSBundle will not find it.