Overwriting a plist file with content of a NSMutableArray (first item is always NULL in plist) - iphone

I am trying to use plist files to save a list of items from a text
file from a web site. When I first create the plist file and add
items to that, there is no problem. But when I try to remove an item
from plist, it is not removing the index, it only overwrites the
content of this index with NULL. And I tried an other way; I tried to
create a new array without the item I want to remove, and overwrite
plist file with the content of this new array. In this way, the item
I wanted to remove is removed, but surprisingly the first item gets
NULL! A more surprising situation is, I also write it to a new plist
file with same technique, and it is perferct! This is a very
primitive code, unfortunately it didn't worked for me. I searched
plenty of tutorials, but I couldn't overcome. How can I write the
content of a string array to a plist file without extra null objects
and without loosing datas?
========================================================================
I composed a sample code below :
- (IBAction)logFromPlist{
NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"]];
NSLog(#"LOG:");
NSLog(#"arrplist count : %d", [arr count]);
for(int a=0; a<[arr count]; a++){
NSLog(#"*** %#", [arr objectAtIndex:a]);
}
}
- (IBAction)logFromPlist2{
NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data3.plist"]];
NSLog(#"LOG:");
NSLog(#"arrplist count : %d", [arr count]);
for(int a=0; a<[arr count]; a++){
NSLog(#"*** %#", [arr objectAtIndex:a]);
}
}
- (IBAction)addValue{
NSString *deger = [field5 text]; //New value text field in IB
NSMutableArray *arr = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"]];
if(arr == NULL){
arr = [[NSMutableArray alloc] init];
}
[arr addObject:deger];
[arr writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] atomically:NO];
}
- (IBAction)removeFromPlist{
NSMutableArray *arr2 = [[NSMutableArray alloc] initWithContentsOfFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"]];
if(arr2 != NULL){
NSMutableArray *arr = [[NSMutableArray alloc] init];
NSString *key = [field8 text];
for(int i = 0; i < [arr2 count]; i++){
NSString *cntStr = [[NSNumber numberWithInt:i] stringValue];
if(![cntStr isEqualToString:key]){
NSString *tempDeger = [arr2 objectAtIndex:i];
if(tempDeger != NULL){
[arr addObject:tempDeger];
}else{
NSLog(#"it is NULL");
}
}
}
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] error:nil]; //I tried this line by removing next line
[arr writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] atomically:NO]; //It is writing the array to plist but first item is always null
[arr writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data3.plist"] atomically:NO]; //same technique but everything is ok in this plist
[fileManager copyItemAtPath:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data3.plist"] toPath:[NSHomeDirectory() stringByAppendingPathComponent:#"Documents/data2.plist"] error:nil]; // trying to copy correct plist file (data3.plist) to original plist file (plist2), but it does not fix the problem.
}
}
Project file : http://www.ozgunbursalioglu.com/files/plistWork.zip

At least your copyItemAtPath: will always fail since it won't overwrite files (data2.plist already exists).

Try to write your file by setting the automatically to YES
[arr writeToFile:PATH atomically:YES];
And also try to check the BOOL value returned to see if your oerration done successfully

Related

keysSortedByValueUsingSelector crashes but sortedArrayUsingSelector runs fine

I found a workaround myself, but still trying to understand the problem.
I created a Autocomplete text field with the use of uitableview which is hidden until textfield is edited. The UI part works fine. It's the searching for the results part that's the problem. I declared a local NSMutableDictionary to store my results because I wanted the results to be sorted by the key's values.
if I call keysSortedByValueUsingSelector on the dictionary directly, it crashes. However if I get the keys by [dict allKeys] first, then call sortedArrayUsingSelector, it works fine:
// This commented out line will crash
// NSArray *sortedKeysArray = [dict keysSortedByValueUsingSelector:#selector(compare:)];
// The next two lines runs fine.
NSArray *keyArray = [dict allKeys];
NSArray *sortedKeysArray = [keyArray sortedArrayUsingSelector:#selector(compare:)];
Here is the complete source code for the search method:
- (void)searchAutocompleteEntriesWithSubstring:(NSString *)substring
{
// Put anything that starts with this substring into the autocompleteUrls array
// The items in this array is what will show up in the table view
[autocomplete_symbol_array removeAllObjects];
rRSIAppDelegate *appDelegate = (rRSIAppDelegate *)([[UIApplication sharedApplication] delegate]);
NSString *input_str = [substring uppercaseString];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
int i = 0;
for(SymbolInfo *symbol_info in appDelegate.m_symbol_info_array)
{
i++;
NSString *info_str = [[[symbol_info.m_symbol uppercaseString] stringByAppendingString:#"|"] stringByAppendingString:[symbol_info.m_company_name uppercaseString]];
NSUInteger pos = [info_str rangeOfString:input_str].location;
if (pos != NSNotFound)
{
int tmp = pos * 10000 + i;
NSNumber *map_key = [[NSNumber alloc] initWithInt:tmp];
[dict setObject:symbol_info forKey:map_key];
}
}
// This commented out line will crash
// NSArray *sortedKeysArray = [dict keysSortedByValueUsingSelector:#selector(compare:)];
// The next two lines runs fine.
NSArray *keyArray = [dict allKeys];
NSArray *sortedKeysArray = [keyArray sortedArrayUsingSelector:#selector(compare:)];
for (NSNumber *key in sortedKeysArray)
{
SymbolInfo *symbol_info = [dict objectForKey:key];
[autocomplete_symbol_array addObject:symbol_info];
}
// NSLog(#"everything added: %d", [autocomplete_symbol_array count]);
[autocompleteTableView reloadData];
}
The NSMutableDictionary's method is:
- (void)setObject:(id)anObject forKey:(id < NSCopying >)aKey;
This means that the key should implement the NSCopying protocol.

add data to NSMUtableArrray with keys by for loop

I'm new in iPhone, I want to add elements to NSMutableArray with each element's name
I created a MutableArray for keys , then other array for elements that I get them from object called Pages.
I wrote the following code
NSMutableArray *myArray;
NSMutableArray *arrayKey = [[NSMutableArray alloc] initWithObjects:#"b_pag_id", #"b_pag_bo_id", #"b_pag_num", #"b_pag_note", #"b_page_mark", #"b_page_stop", #"b_pag_user_id", nil];
for (int x=0; x<[pages count]; x++) {
Pages *myPages = (Pages *)[self.pages objectAtIndex:x];
NSString *b_pag_id2 = [NSString stringWithFormat:#"%d",myPages.b_pag_id];
NSString *b_pag_bo_id2 = [NSString stringWithFormat:#"%d",myPages.b_pag_bo_id];
NSString *b_pag_num2 = [NSString stringWithFormat:#"%d",myPages.b_pag_num];
NSString *b_pag_note2 = myPages.b_pag_note;
NSString *b_page_mark2 = [NSString stringWithFormat:#"%d",myPages.b_page_mark];
NSString *b_page_stop2 = [NSString stringWithFormat:#"%d",myPages.b_page_stop];
NSString *b_pag_user_id2 = [NSString stringWithFormat:#"%d",myPages.b_pag_user_id];
NSMutableArray *arrayValue = [[NSMutableArray alloc] initWithObjects:b_pag_id2, b_pag_bo_id2, b_pag_num2, b_pag_note2, b_page_mark2, b_page_stop2, b_pag_user_id2, nil];
NSDictionary *theReqDictionary = [NSDictionary dictionaryWithObjects:arrayValue forKeys:arrayKey];
myArray = [NSMutableArray arrayWithObjects:theReqDictionary,nil];
}
NSLog(#"array size: %d", [myArray count]);
I want to add every element to its key for example
element (b_pag_id2) its key (b_pag_id) ..etc
is this right ?? or how to do this ??
consider that NSLog(#"array size: %d", [myArray count]); gives me 1 and the size of my elements is 14
Before the loop you need to initialize the aray
NSMutableArray *myArray = [NSMutableArray array];
Inside the loop replace following:
myArray = [NSMutableArray arrayWithObjects:theReqDictionary,nil];
with
[myArray addObject:theReqDictionary];
The problem is that you are creating a new array with 1 dictionary in every loop iteration. Instead you need to initialize the array and add values one by one.
Each time through your loop you are creating a new array for myArray that has only one element. You should initialize an empty NSMutableArray before the loop and then simply add your new object to it instead of using arrayWithObjects: to create myArray..
Here i'm giving a short example, and i hope this will help you.
see this code :-
NSMutableArray *arrayValue = [[NSMutableArray alloc]initWithObjects:#"Value1",#"Value2",#"Value3", nil];
NSMutableArray *arrayKey = [[NSMutableArray alloc]initWithObjects:#"1",#"2",#"3", nil];
NSMutableDictionary *dic = [[NSMutableDictionary alloc]init];
for(int i=0;i<3;i++)
{
[dic setObject:[arrayValue objectAtIndex:i] forKey:[arrayKey objectAtIndex:i]];
}
//and you can see this by printing it using nslog-
NSLog(#"%#",[dic valueForKey:#"1"]);
Thank you!!!

Xml parsing in Iphone and adding values to NSMutableArray

I am new to xml parsing. I have the following xml
<myMainList>
<mySubList>
<edited>true</edited>
<mySharedNumber>W59QYBZKJ4</mySharedNumber>
</mySubList>
<mySubList>
<edited>false</edited>
<mySharedNumber>TOW4KLP9WD</mySharedNumber>
</mySubList>
<mySubList>
<edited>true</edited>
<mySharedNumber>XH8JDIZA64</mySharedNumber>
</mySubList>
<mySubList>
<edited>false</edited>
<mySharedNumber>V2YOHSNODT</mySharedNumber>
</mySubList>
</myMainList>
I have edited my question.
I am not familiar with looping through the whole xml and adding the values into my array. Can someone show me how I can add the 4 sharedNumberList values into my array.
Edit:
GDataXMLElement *node;
NSArray * array = [node nodesForXPath:#"//return/myMainList/mySubList" error:nil];
NSLog(#"count :%d",[array count]);
int sharedContacts = [array count];
NSMutableArray *mySharedListArray = [[NSMutableArray alloc]init];
for(int i = 1; i<= sharedContacts; i++){
NSString *xmlDataFetcher = [NSString stringWithFormat:#"//return/myMainList/mySubList[%d]",i ];
NSString *parsedNumbers = [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/mySharedNumber"]];
NSString *parsedEdit = [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/edited"]];
NSLog(#"Parsed Edited %#", [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/edited"]]);
NSLog(#"Parsed sharedNumber %#", [node nodeStringForXPath:[xmlDataFetcher stringByAppendingString:#"/mySharedNumber"]]);
NSString *arrayEntry = [NSString stringWithFormat:#"%#%#", parsedNumbers, parsedEdit];;
[mySharedListArray addObject:arrayEntry];
}
NSLog(#"Array entry %#", mySharedListArray);
I have added a lot of NSLog in the answer, so that you could log it as you wish
I haven't done this most probably this is returning an array from the xpath query so Try this instead
[mySharedListArray addObjectsFromArray:[node nodesForXPath:#"//return/MyList" error:nil]];

Unable to replace NSArray derived from output of "ps aux" UNIX command

Im trying to replace the 7th index of the array "lines2". The NSMUTABLEARRAY "lines2" is derived from the UNIX command "ps aux", and I suspect that this command returns an array of NSCFStrings. Im basically trying to replace "Ss" with "Ss (Running)" for now. The problem is that I get a SIGABRT error every time The program reaches the part where it tries to replace the particular array element. The code for my viewController is below.
NSLog(#"myString is :%#", myString);
int processID = [myString intValue];
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/ps"];
arguments = [NSArray arrayWithObjects: #"aux", [NSString stringWithFormat:#"%i", processID],nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
//[task setStandardOutput: pipe];
[task setStandardOutput:pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data
encoding: NSUTF8StringEncoding];
// NSLog(#"%#",string);
NSArray *lines= [string componentsSeparatedByString:#"\n"];
NSString *lastline = [lines objectAtIndex:[lines count]-2];
// NSLog(#"%#",lastline);
lines2= [lastline componentsSeparatedByString:#" "];
NSLog(#"%#",lines2);
for (int i=0; i<[lines2 count]; i++) {
if([[lines2 objectAtIndex:i] isEqualToString:#""]){
[lines2 removeObjectAtIndex:i];
}
}
for (int i=0; i<[lines2 count]; i++) {
if([[lines2 objectAtIndex:i] isEqualToString:#""]){
[lines2 removeObjectAtIndex:i];
}
}
for (int i=0; i<[lines2 count]; i++) {
if([[lines2 objectAtIndex:7] isEqualToString:#"Ss"]){
[[lines2 objectAtIndex:0] replaceObjectAtIndex:7 withObject:#"SS (Running)"];
}
}
Any help is very much appreciated!
Please look at the documentation for the method -componentsSeparatedByString:. The signature is:
- (NSArray *)componentsSeparatedByString:(NSString *)separator
Notice the return type is NSArray. This is an immutable object. You must not change it even if inspecting the returned object (say with a debugger or an NSLog) shows it to actually be mutable. You must respect the API contract. (Read the section of the link entitled "receiving mutable objects".)
That said, the immediate cause of your error is this line:
[[lines2 objectAtIndex:0] replaceObjectAtIndex:7 withObject:#"SS (Running)"];
^^^^^^^^^^^^^^^^^^^^^^^^ This is wrong
lines2 is an array of strings. [lines2 objectAtIndex: 0] is a string. Why are you sending -replaceObjectAtIndex:withObject: to it?
You don't say what the error you're seeing is, but you cannot change the values in the NSArray because an NSArray is an immutable container.
Use an NSMutableArray when you want to make modifications. If you have an NSArray already (as in the return value from -componentsSeparatedByString:), you can get a mutable array by doing this:
NSMutableArray * myMutableArray = [NSMutableArray arrayWithArray:lines2];
NSArray is not mutable. First copy it to an NSMutableArray (e.g. using [NSMutableArray arrayWithArray:]) so you can manipulate it.
Didn't you get any warnings during compilation?

SQL select statement equivalent for query on plist

I am trying to figure out the best approach for queries on a plist. Thus, attempting at making an sql equivalent to "SELECT * FROM sometable WHERE somecol = someval AND someothercol = someotherval AND ".... so on and soforth ... using a plist as the sql table equivalent. Coming from Ruby and mysql, this just seems like a lot of code for one simply query. The results come back as expected (at least at first run they did, I have not tested this rigorously) with no errors.
So here is the question: Is there some simple method hiding in the docs somewhere that would make this less clunky?
and if not what is a better approach?
EPFramework.m
// LOAD PLIST AND FILTER MULTIPLE TIMES
-(NSMutableArray *)loadPlistAndFilterMultipleTimes:(NSString *)plist ArrayOfKeys:(NSArray *)arrayOfKeys ArrayOfKeyValues:(NSArray *)arrayOfKeyValues
{
// set the array counts
int arrayOfKeysCount = [arrayOfKeys count];
int arrayOfKeyValuesCount = [arrayOfKeyValues count];
// initialize the array to return
NSMutableArray *arrayFilteredResults = [[[NSMutableArray alloc] init] retain];
// qualify the search
if(arrayOfKeysCount == arrayOfKeyValuesCount && arrayOfKeysCount > 0 && arrayOfKeyValuesCount > 0)
{
// get the plist
NSString *fullFileName = [NSString stringWithFormat:#"%#.plist", plist];
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:fullFileName];
// put the plist records into an array
NSArray *arrayOfDictionaryItemsInPlist = [[NSMutableArray alloc] initWithContentsOfFile:path];
// load our dynamic array for mutability throughout the loops
NSMutableArray *arrayFiltered = [[[NSMutableArray alloc] initWithArray:arrayOfDictionaryItemsInPlist] retain];
// build an array of the final results to return
for(int i=0; i < arrayOfKeysCount; i ++)
{
// initialize this loops search criteria
NSString *key = [arrayOfKeys objectAtIndex:i];
id value = [arrayOfKeyValues objectAtIndex:i];
// set the filter
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"%K == %#", key, value];
// filter the result
arrayFilteredResults = [[[NSArray alloc] initWithArray:[arrayFiltered filteredArrayUsingPredicate:predicate]] retain];
}
} else {
NSLog(#"arrOfKeys count does not match arrayOfKeyValues count"); // the search did not qualify
}
// return the results
return arrayFilteredResults;
// release the allocated memory
[arrayFilteredResults release];
}
IndexController.m
NSArray *arrayOfKeys = [NSArray arrayWithObjects:
[NSString stringWithString:#"recordset"],
[NSString stringWithString:#"ep_object_attribute_id"],
nil];
NSArray *arrayOfKeyValues = [NSArray arrayWithObjects:
[NSString stringWithString:#"1778587279"],
[NSNumber numberWithInt:133],
nil];
NSMutableArray *arrayOfResult = [epFrameWork loadPlistAndFilterMultipleTimes:#"FormEntries" ArrayOfKeys:arrayOfKeys ArrayOfKeyValues:arrayOfKeyValues];
NSLog(#"arrayOfResult: %#", arrayOfResult);
Here's the link for fmdb. Should be quick to pick it up, be faster and you get a real database instead of simulating one with plists :)
https://github.com/ccgus/fmdb
Hope that helps