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

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?

Related

Unable to create NSMutableArray using for-loop

i want to have an array with values "25 kg", "26 kg"... "149 kg", "150 kg". To simplify task i wrote this:
-(NSMutableArray*)weightArray{
NSMutableArray *myArray;
for (int i=25; i++; i<150){
NSString *weightString;
weightString = [NSString stringWithFormat:#"%d kg", i];
[myArray addObject:weightString];
}
return myArray;
}
And then in viewDidload in my view i wrote: NSLog (#"%#", [self weightArray]);
But it looks like it's not working. I might be missing something obvious like syntax. Why is it not working?
UPDATE:
Finally i found a solution - first, i declare weightArray in #implementation section, then i wrote:
-(void)fillingArray{
if (!weightArray){
for (int i=25; i<150 ;i++){
NSString *weightString = [[NSMutableArray alloc] init];
weightString = [NSString stringWithFormat:#"%d kg", i];
[weightArray addObject:weightString];
NSLog(#"%#", weightString);
}
}
}
In viewDidLoad i wrote:
[self fillingArray];
NSLog(#"%#", weightArray);
I think, my problem was in that string NSLog(#"%#", [self weightArray]); In square brackets it suppose to be method name, but i was trying to point at array, and nothing happening.
There are 3 problems with what you are doing.
You need to create your array like this: NSMutableArray *myArray = [[NSMutableArray alloc] init]; so that it will actually exist.
Your NSLog needs to be NSLog (#"%#", [self weightArray]); since you are lgging an array and not a number.
(thanks rmaddy for pointing this out) The 2nd and 3rd part of your for statement are reversed. So, i++ is your condition and is always non-zero. This infinite loop is what causes your machine to lock up.
EDIT: Here's a better way that only creates the array once.
-(NSMutableArray*)weightArray{
static NSMutableArray *myArray;
if (!myArray){
myArray = [[NSMutableArray alloc] init];
for (int i=25; i<150 ;i++){
NSString *weightString;
weightString = [NSString stringWithFormat:#"%d kg", i];
[myArray addObject:weightString];
}
}
return myArray;
}
You don't allocate and initialize the array. So it has an indeterminate value, and your program invokes undefined beahvior. Create it actually:
NSMutableArray *myArray = [NSMutableArray new];

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]];

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

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

how to create an array of string or float in Objective-C

i need some help here, i need to know how to create an array of string retrieved from an array. i'm using powerplot for graph and it only accept float or string array.
i need to create something something like this dynamically.
NSString * sourceData[7] = {#"2", #"1", #"4", #"8", #"14", #"15", #"10"};
Below are my code to find out the numbers in strings.
NSInteger drunked = [appDelegate.drinksOnDayArray count];
NSMutableArray * dayArray = [[NSMutableArray alloc] init];
NSMutableArray * sdArray = [[NSMutableArray alloc] init];
//float *sdArray[7];
for (int i=0; i<drunked; i++) {
DayOfDrinks *drinksOnDay = [appDelegate.drinksOnDayArray objectAtIndex:i];
NSString * dayString= [NSDate stringForDisplayFromDateForChart:drinksOnDay.dateConsumed];
[dayArray addObject:dayString];
NSLog(#"%#",[dayArray objectAtIndex:i]);
drinksOnDay.isDetailViewHydrated = NO;
[drinksOnDay hydrateDetailViewData];
NSString * sdString= [NSString stringWithFormat:#"%#", drinksOnDay.standardDrinks];
[sdArray addObject:sdString];
NSString *tempstring;
NSLog(#"%#",[sdArray objectAtIndex:i]);
}
thanks for the help :)
Array's in Objectice-C aren't that hard to work with:
NSMutableArray *myArray = [NSMutableArray array];
[myArray addObject:#"first string"]; // same with float values
[myArray addObject:#"second string"];
[myArray addObject:#"third string"];
int i;
int count;
for (i = 0, count = [myArray count]; i < count; i = i + 1)
{
NSString *element = [myArray objectAtIndex:i];
NSLog(#"The element at index %d in the array is: %#", i, element); // just replace the %# by %d
}
You can either use NSArray or NSMutableArray - depending on your needs, they offer different functionality.
Following tutorial covers exactly what you are looking after:
http://www.cocoalab.com/?q=node/19
You can also add the elements to the array when you init (and optionally add them later only if you are using the Mutable version of a collection class:
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:#"2", #"1", #"4", #"8", #"14", #"15", #"10", nil];
[myArray addObject:#"22"];
[myArray addObject:#"50"];
//do something
[myArray release];
You can use malloc to create a C-style array. something like this should work:
NSString **array = malloc(numElements * sizeof(NSString *))
some code here
free(array)
Be aware that unlike NSMutable array, c arrays won't do a retain, so you have to manage it if needed. And don't forget the free

Creating a long NSString causing memory issues

My code below is causing my app to quit i.e. get black screen and then see in debugger console: Program received signal: “0”.
Basically it is causing problem when my orderArray has count of 2000 or more. I am using iPhone 3GS with iOS 4.2
Question: Is there a more efficient and less memory consuming way to create my long outStr?
NSString *outStr = #"";
for (int i = 0; i < count; i++) {
NSDictionary *dict = [[ARAppDelegate sharedAppDelegate].orderArray objectAtIndex:i];
outStr = [outStr stringByAppendingFormat:#"%#,%#,%#,%#\n",
[dict valueForKey:#"CODE"],
[dict valueForKey:#"QTY"],
[[ARAppDelegate sharedAppDelegate].descDict valueForKey:[dict valueForKey:#"CODE"]],
[[ARAppDelegate sharedAppDelegate].priceDict valueForKey:[dict valueForKey:#"CODE"]]];
}
Update: Thanks to very kind people who helped, below is my modified code:
NSArray *orderA = [ARAppDelegate sharedAppDelegate].orderArray;
NSDictionary *descD = [ARAppDelegate sharedAppDelegate].descDict;
NSDictionary *priceD = [ARAppDelegate sharedAppDelegate].priceDict;
NSMutableString *outStr = [[[NSMutableString alloc] init] autorelease];
for (int i = 0; i < [orderA count]; i++) {
NSDictionary *dict = [orderA objectAtIndex:i];
NSString *code = [dict valueForKey:#"CODE"];
[outStr appendFormat:#"%#,%#,%#,%#\n",
code,
[dict valueForKey:#"QTY"],
[descD valueForKey:code],
[priceD valueForKey:code]];
}
[self emailTxtFile:[NSString stringWithString:outStr]];
// This reaches end of method
The problem is that in every iteration a new string object is formed. This consumes a lot of memory. One solution could be to use a local autoreleasepool, but that's rather complicated here.
You should use an NSMutableString, like:
NSMutableString *outStr = [[[NSMutableString alloc] init] autorelease];
for (int i = 0; i < count; i++) {
NSDictionary *dict = [[ARAppDelegate sharedAppDelegate].orderArray objectAtIndex:i];
[outStr appendFormat:#"%#,%#,%#,%#\n",
[dict valueForKey:#"CODE"],
[dict valueForKey:#"QTY"],
[[ARAppDelegate sharedAppDelegate].descDict valueForKey:[dict valueForKey:#"CODE"]],
[[ARAppDelegate sharedAppDelegate].priceDict valueForKey:[dict valueForKey:#"CODE"]]];
}
Then you can use outStr, just as if it was an NSString. As Tom points out in the comments, you could turn the NSMutableString into an NSString when you're finished, using:
NSString *result = [NSString stringWithString:outStr];
[outStr release]; // <-- add this line and remove the autorelease
// from the outStr alloc/init line
making your code re-usable and easier to maintain.