Won't write to plist array Xcode. This was the code used and it doesn't work, does anyone know why? - objective-c

NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *finalPath = [path stringByAppendingPathComponent:#"HighScore.plist"];
NSMutableArray* plistDict = [[NSMutableArray alloc]
initWithContentsOfFile:finalPath];
[plistDict addObject:[highScoreLabel text]];
NSArray *regArray = [NSMutableArray arrayWithArray:plistDict];
[regArray writeToFile:#"HighScore.plist" atomically: YES];

Does the file exist and contains valid data?
See Apple's documentation about NSMutableArray initWithContentsOfFile::
Return Value
An array initialized to contain the contents of the file specified by aPath or nil if the file can’t be opened or the contents of the file can’t be parsed into an array. The returned object might be different than the original receiver.
Discussion
The array representation in the file identified by aPath must contain only property list objects (NSString, NSData, NSArray, or NSDictionary objects). The objects contained by this array are immutable, even if the array is mutable.
If initWithContentsOfFile: returns nil, it's clear that the rest of the code won't work either.

p list write to file means to write the p list or to save the data ,,,for retrieving view write the content of file .

Related

Creating new NSStrings for each item in a plist array

I am attempting to create a class that takes each item in a Plist array and assigns them to an NSString for use in other classes in the program. Here's what I have so far:
NSString *appBundlePath = [[NSBundle mainBundle] bundlePath];
NSString *plist = [appBundlePath stringByAppendingString:#"/Contents/Resources/Values.plist"];
plistArray = [[NSArray alloc] initWithContentsOfFile:plist];
for (NSString* plistItem in plistArray) {
finalPlistString = plistItem;
}
NSLog(finalPlistString);
This code goes and finds the plist within the app bundle, assigns the contents of the plist to an NSArray and uses a for loop to set the plistItem NSString to the items in the plist array. Then the resulting string is logged using NSLog. It logs the last item in the plistArray, which makes sense because there is only one NSString variable to assign to.
How can I create a new NSString for each item in the plist array? If you are wondering, plistArray and finalPlistString are defined in the .h file.
First, the easiest way to get he path for a plist from a bundle is
NSString *path = [[NSBundle mainBundle] pathForResource:#"Values" ofType:#"plist"];
Second, after you read in the array, you now have all the strings in the array for further use in your program. So it takes you two lines of code to get all the data.
To access, say, the third item in the array, just use
plistArray[2]
-- there is nothing else you have to do, i.e. you do not even need a variable. E.g. to assign to a label you write
label.text = plistArray[2];
Your for loop below that does not make sense. To get the last item of an array, it is easier to do this:
NSString *lastItem = plistArray.lastObject;

how to detect pasteboard item type

I am trying to identify between three types of objects:
if it is a URL of a file
If it is a URL of a directory
if it is a simple string
up till now, I have just this code, which does not work!
NSArray * classes = nil;
classes = [[NSArray alloc] initWithObjects:[NSURL class],
[NSAttributedString class],[NSString class], nil];
NSDictionary *options = [NSDictionary dictionary];
NSArray * copiedItems = nil;
copiedItems = [pb readObjectsForClasses:classes options:options];
Now I try to take the first object of the array copiedItems and try to call "types" property and i get a crash!
Check here and here:
You would need to use these pasteboard types, instead of the ones you're using.
NSString *NSStringPboardType;
NSString *NSFilenamesPboardType;
NSString *NSPostScriptPboardType;
NSString *NSTIFFPboardType;
NSString *NSRTFPboardType;
NSString *NSTabularTextPboardType;
NSString *NSFontPboardType;
NSString *NSRulerPboardType;
NSString *NSFileContentsPboardType;
NSString *NSColorPboardType;
NSString *NSRTFDPboardType;
NSString *NSHTMLPboardType;
NSString *NSPICTPboardType;
NSString *NSURLPboardType;
NSString *NSPDFPboardType;
NSString *NSVCardPboardType;
NSString *NSFilesPromisePboardType;
NSString *NSMultipleTextSelectionPboardType;
There's an pasteboard type for URLs. To distinguish between a file and a folder, you would need to instantiate an NSURL object with the pasteboard data, and find out if it is a directory by querying its attributes.
EDIT:
You also need to consider if the pasteboard data is being put there by your own application or other applications. If it's being put by other applications, I'm not sure the pasteboard types with the classes will work.
I use something like this in one of my projects:
supportedTypes = // array with supported types, maybe from the list
NSString *type = [pasteboard availableTypeFromArray:supportedTypes];
NSData *data = [pasteboard dataForType:type];
types is a method on NSPasteboard used to tell you what is available from the pasteboard. So, you shouldn't call it on the items you get back from the pasteboard.
If you're going to request multiple class types, iterate over the response and check the class type of each item, then decide how to interact with it.
Alternatively, decide which class type of data is most useful and make individual class type requests to the pasteboard. If you get a result back, use it and carry on, if not, try the next most useful class type. Look at using canReadObjectForClasses:options: to make this easier.

Why NSMutableArray doesn't get sorted?

NSFileManager *fileManager= [[NSFileManager alloc]init];
NSDirectoryEnumerator *myEnumerator= [fileManager enumeratorAtPath:[[theFolder URLByDeletingLastPathComponent]path]];
int f,size=0;
NSMutableArray *dirList=[[NSMutableArray alloc]init];
NSString *fpath;
while (fpath=[myEnumerator nextObject])
{
[dirList addObject:fpath];
}
[dirList sortedArrayUsingSelector:#selector(localizedStandardCompare:)];
dirList contains filenames like "name_0012345.tif". Despite the sort the array doesn't contain the file in the order i would see in the finder sorting by name.
-sortedArrayUsingSelector: is actually an NSArray method that returns a new sorted array (which you promptly ignore). You mean to use -sortUsingSelector:, which is an NSMutableArray method that rearranges the existing array itself.
It's pretty common in Cocoa to have one method for returning a modified immutable version of an object, and another method for modifying the mutable object itself (-stringByAppendingString: and -appendString:, for example).
From NSArray Class Reference
sortedArrayUsingSelector:
Returns an array that lists the receiving array’s elements in ascending order, as determined by the comparison method specified by a given selector.

Get data from a PList into UITableView?

I want to maintain a list of records, for each one I maintain the same type of data. I want to use this data in 2 different places:
UITableView that takes from each record the "Name" value
UIViewController that takes all the data to use in different fields.
I assume I should be using a plist to store the data; I also assume that the object that should be receiving the data for the UITableView is NSArray so I can use the cellForRowAtIndexPath method to create the table automatically.
So i created the plist "PLForArr.plist":
It seems that i can only get a NSDictionary when calling the plist using
NSString *path = [[NSBundle mainBundle] pathForResource:#"PLForArr" ofType:#"plist"];
NSArray * myArr = [[NSArray alloc] initWithContentsOfFile:path]; //doesn't work...
NSDictionary * myDict = [[NSDictionary alloc] initWithContentsOfFile:path]; //does work, but who to I make a NSArray out of it / or get the data from here to the UITableView?
I understand that i don't understand something basic here... Can someone take me step by step on:
How to keep the data - should I use plist or something else? Should I have a main record of type array (as I did on the example plist here) or can I just keep it as these Dictionaries without the unnecessary MyArr that I used considering the UITableView end target?
How to call the data - Is there a way to get it into a NSArray or must it get into a NSDictionary?
How to call it into the the UITableView - Can I fill in the lines using a NSDictionary?
Storing the data is an Array or a Dictionary is up to you. But if you want to make changes to it over time you can't store it in the main bundle.
Your pList file is a dictionary that contains an array. See code example below.
You will have to store the dictionary in an array for the data source for your table. See code example below.
Assuming that your UITableView's data source is called tableArray. You can use tableArray to fill in the information in the table and your view. Oh yeah,
NSString *path = [[NSBundle mainBundle] pathForResource:#"PLForArr" ofType:#"plist"];
NSDictionary *myDict = [[NSDictionary alloc] initWithContentsOfFile:path];
NSArray *myArray = [myDict objectForKey:#"MyArray"];
self.tableArray = [myArray copy];
[myArray release];
[myDict release];
This goes in tableView: cellForRowAtIndexPath:
cell.text = [[tableArray objectAtIndex:row]objectForKey:#"Obj Name"];
Storing your data either in a dictionary, or in an array is up to you. Depending on the kind of data you have, you will consider storing unordered collection of objects (dictionary), accessing the entries with keys; or rather in ordered collection (array), using numeric indexes.
It's fine to get arrays from property list files, but the root (top level) object is a dictionary (in the screenshot, "MyArr" isn't the top-level object, it is the key for accessing your array in the top-level dictionary). To get your array from it, simply alloc/init the plist dictionary the way you did, and access the array entry using its key ([myDict objectForKey:#"MyArr"]). Otherwise make sure you set the root object of the property list to be an array, and retry NSArray's initWithContentsOfFile:
The real question seems to be How can I fill the cells with my data ? The table views ask its delegate and dataSource about how many sections, rows in a section, to display. Based on these numbers, it will ask the dataSource for cells. Once again depending on the storage type you've chosen, you will implements these methods a little bit differently, but the concepts remain.
You will probably want to read documentation about :
Property List
Table views

Test NSmutable array from plist before saving

I'm trying to made a cocoa app that read-write to a .plist file.
I can retrieve informations from the .plist, write into, but when a key (only with strings) is empty, the app don't write to the plist.
here a sample:
-
(IBAction)saveBoot:(id)sender {
NSString *errorDesc;
NSString *bootPath = #"/myplist.plist";
NSMutableDictionary *plistBootDict =
[NSMutableDictionary dictionaryWithObjects:
[NSMutableArray arrayWithObjects:
Rescan,
RescanPrompt,
GUI,
InstantMenu,
DefaultPartition,
EHCIacquire,
nil]
forKeys:[NSMutableArray arrayWithObjects:
#"Rescan",
#"Rescan Prompt",
#"GUI",
#"Instant Menu",
#"Default Partition",
#"EHCIacquire",
nil]];
NSData *plistBootData = [NSPropertyListSerialization
dataFromPropertyList:plistBootDict
format:NSPropertyListXMLFormat_v1_0
errorDescription:&errorDesc];
if (bootPath) {
[plistBootData writeToFile:bootPath atomically:NO];
}
else {
NSLog(errorDesc);
[errorDesc release];
}
}
#end
I think i need a loop to check if each key is empty or not (and remove it if empty),
but i've tried different (objectEnumerator, objectForKey:..etc) method whitout success.
If someone can help a beginner like me,
thanks in advance.
Ronan.
The problem is probably that because nil is the terminator for variable argument lists, so if, say, RescanPrompt is nil, the object array will only contain up until that part (so you can't "remove if empty" since it won't exist in the dictionary in the first place). You should probably construct your dictionary piece by piece; something like:
NSMutableDictionary *plistBootDict = [NSMutableDictionary dictionary];
if (Rescan)
[plistBootDisc setObject:Rescan forKey:#"Rescan"];
if (GUI)
[plistBootDisc setObject:GUI forKey:#"GUI"];
// etc
(Also, there's no reason to be using NSMutableArray or NSMutableDictionary if you're never going to be mutating them later.)