Trying to build polygon from NSString - objective-c

So, I'm trying to build an array of CGPoints by breaking an NSString, typically look like this:
31.241854,34.788867;31.241716,34.788744;31.242547,34.787585;31.242661,34.787719
Using this code:
- (NSMutableArray *)buildPolygon:(NSString *)polygon
{
NSMutableArray *stringArray = [[NSMutableArray alloc] init];
[stringArray addObject:[polygon componentsSeparatedByString:#";"]];
NSMutableArray *polygonArray = [[NSMutableArray alloc] init];
for (int i=0; i < polygonArray.count; i++)
{
NSArray *polygonStringArray = [[NSArray alloc] init];
polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
CGFloat xCord = [[polygonStringArray objectAtIndex:0] floatValue];
CGFloat yCord = [[polygonStringArray objectAtIndex:1] floatValue];
CGPoint point = CGPointMake(xCord, yCord);
[polygonArray addObject:[NSValue valueWithCGPoint:point]];
}
NSLog(#"return polygonArray: %#", polygonArray);
return polygonArray;
}
But eventually I get an empty array.
What I'm doing wrong?

You're defining polygonArray as an empty array just before the start of your for loop. You should define polygonArray like:
NSArray *polygonArray = [polygon componentsSeparatedByString:#";"];
And you don't even need to bother with that stringArray variable.

You have confusion over alloc & init, and one simple typo...
The confusions first:
NSMutableArray *stringArray = [[NSMutableArray alloc] init];
This creates a new NSMutableArray and stores a reference to it in stringArray. All good so far.
[stringArray addObject:[polygon componentsSeparatedByString:#";"]];
And this obtains a reference to an NSArray ([polygon componentsSeparatedByString:#";"]) and adds it as a single element to the mutable array referenced by stringArray. There is nothing wrong per se with this, but it is not what you want in this case - you just want the array returned by componentsSeparatedByString:. You do this with:
NSArray *stringArray = [polygon componentsSeparatedByString:#";"];
Which takes the reference returned by componentsSeparatedByString: and stores it in the variable stringArray - no alloc or init required as you are not creating the array yourself. You don't even own this array, so if you are using MRC there is no need to release it later.
NSArray *polygonStringArray = [[NSArray alloc] init];
Now this allocates an immutable empty array and stores a reference to it in polygonStringArray. This is not a very useful array, as it contains nothing and cannot be modified! But you don't keep it around long...
polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
This obtains a reference to an array from componentsSeparatedByString: and stores it in polygonStringArray. If you are using MRC this will cause a leak - your pointless zero-length array created above will leak, and a new zero-length array will be created and leaked every time around the loop.
You are confused over allocation - you only need to allocate things you are creating; when you receive a reference to an already allocated object you only need to store that reference. (If using MRC you may also need to retain/release/autorelease it as well - but let's stick with ARC.) So all you needed here was:
NSArray *polygonStringArray = [[stringArray objectAtIndex:i] componentsSeparatedByString:#","];
Now your code is almost correct, just one typo:
for (int i=0; i < polygonArray.count; i++)
Well you are filling polygonArray in this loop and it starts off as empty, what you need is stringArray.count.
HTH

Related

Filling nsmutablearray objective-c

can somebody please explain me the difference between the following code snippets for filling the myStrings array:
NSString *match = #"ad*.png";
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSFileManager *fm = [NSFileManager defaultManager];
NSArray *dirContents = [fm contentsOfDirectoryAtPath:bundleRoot error:nil];
NSPredicate *fltr = [NSPredicate predicateWithFormat:#"SELF like %#", match];
NSArray *onlyPNGs = [dirContents filteredArrayUsingPredicate:fltr];
myStrings = [NSMutableArray array];
for(int i=0;i<[onlyPNGs count];i++)
{
[myStrings addObject:(NSString *)[onlyPNGs objectAtIndex:i]];
}
NSLog([myStrings description]);
When I fill my array this way, after the constructor, myStrings becomes null somehow but instead of filling with filter, if I add items manually everythings fine:
[myStrings addObject:#"adburgerking1.png"];
[myStrings addObject:#"adburgerking2.png"];
[myStrings addObject:#"adburgerking3.png"];
[myStrings addObject:#"addominos1.png"];
[myStrings addObject:#"admcdonalds1.png"];
[myStrings addObject:#"admcdonalds2.png"];
[myStrings addObject:#"admcdonalds3.png"];
[myStrings addObject:#"admeshuriskender1.png"];
[myStrings addObject:#"adquickchina1.png"];
[myStrings addObject:#"adsencam1.png"];
[myStrings addObject:#"adsultanahmetkoftecisi1.png"];
Thanks in advance!!!
From your first comment: myStrings is a property with retain semantics - a property will only retain a value if accessed as a property (self.myStrings = ...), if you directly assign to a underlying variable (myStrings = ...) there will be no retain.
From your second comment: [[NSMutableArray alloc] init] vs. [NSMutableArray array] - [[NSMutableArray alloc] init] returns an array you own, you don't retain it to keep it; however [NSMutableArray array] returns an array you do not own, you must retain it if you wish to keep it.
So what you need is:
self.myStrings = [NSMutableArray array];
The RHS returns an array you do not own, the LHS will retain it - now it will stay around.
You might be tempted to use:
myStrings = [[NSMutableArray alloc] init];
as the RHS returns an array you own and the LHS just stores it without retaining it as you're accessing the variable and not the property. However this version will not release any previous array referenced by myStrings so does not work in general.
The rule is always access a property using dot notation, with the possible exception of a classes init and dealloc methods (this last bit is debated).

How does Object copying work in objective c

I'm a bit confused on how copying objects works in Objective C. Here's what i know: When you copy an object, you get a distinct object in memory that contains all the same elements from the object that you have just copied and increments the retain count for each element. Also, copying each element in the array object from the original to a new location meant just copying the reference from one element of the array to another. So, the old and the new are pointing to the same element.
look at the below code: why is it that when you remove an object it only affects one object and when you change the element, it affects both the original and the copy object? Shouldn't the remove affects both objects?
NSMutableArray *dataArray = [NSMutableArray arrayWithObjects:
[NSMutableString stringWithString:#"one"],
[NSMutableString stringWithString:#"two"],
[NSMutableString stringWithString:#"three"], nil];
NSMutableArray *dataArray2;
NSMutableString *mStr;
NSLog(#"1-dataArray: ");
for( NSString *elem in dataArray)
NSLog(#" %#", elem);
dataArray2 = [dataArray mutableCopy];
[dataArray2 removeObjectAtIndex:0];
NSLog(#"2-dataArray2: ");
for( NSString *elem in dataArray2)
NSLog(#" %#", elem);
mStr =[dataArray objectAtIndex:1];
[mStr appendString:#"ONE"];
NSLog(#"3-dataArray: ");
for( NSString *elem in dataArray)
NSLog(#" %#", elem);
NSLog(#"4-dataArray2: ");
for( NSString *elem in dataArray2)
NSLog(#" %#", elem);
[dataArray2 release];
mutableCopy performs a 'shallow copy' of the NSArray's contents. eg. it is copying the pointers (and presumably retaining them) from the origin array. It is not copying the data those pointers are pointing to.
If we were to do this explicitly it's essentially doing:
-(NSMutableArray*)mutableCopy
{
NSMutableArray *newArray = [[NSMutableArray alloc] init];
for (id elem in originalArray)
[newArray addObject: elem];
return newArray;
}
Though presumably it's doing it more efficiently by using its access to the internal data structures.

How to deallocate objects in NSMutableArray?

i have this Mutable Array:
NSMutableArray *points = [pgroute getPoints:self];
where [getPoint...] do this:
{
NSMutableArray *normPoints = [[NSMutableArray alloc] init];
[normPoints addObject:#""];
[...]
return normPoints;
}
now,
points is an array of objects, right?
is correct to release *points array in this way?
for (int i = 0; i < [points count]; i++) {
[(NSString *)[points objectAtIndex:i] release];
}
[points release];
or it is another correct way?
Xcode compiler, with RUN_CLANG_STATIC_ANALYZER tell me there is an
Incorrect decrement of the reference
count of an object that is not owned
at this point by the caller
How can i resolve this?
thanks,
alberto.
If you want to empty the array, just do this:
[points removeAllObjects];
If you want to release the array, you can even skip that and release it right away:
[points release];
The array will handle releasing the objects on its own. Then again if you're only adding NSString literals (#"using this notation") to the array, they don't need to be released since they are constants. That's a different story of course; my point is that NSMutableArray will deal with releasing stuff where necessary for you.

problems during object release

I have some problems during when and which object to be release
You can say my knowledge towards this is less
i have following conditions please suggest me the answer accordingly
situation-1
NSMutableString *str=[[NSMutableString alloc]initWithFormat:#"Hello World!"];
NSMutableArray *array=[[NSMutableArray alloc]init];
[array addObject:str];
Now when i tried to release str then usage of array affected in future...and Vice Versa
Tell me can i release both?
situation-2
NSMutableString *str=[[NSMutableString alloc]init];
str=#"Hello World !";
str=[self getData]; //calling a method which returns a string
[str release];
I think i am creating a memory leak here(how to solve it?)
please clear these situations
in the first situation, you'll need to call [str release]; after adding it to the array, like this:
NSMutableString *str = [[NSMutableString alloc] initWithString:#"Hello World!"];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:str];
[str release];
This way, array holds the only retain call on the string. Once you release array later, you won't have any memory leak issues.
I'm a little confused about the second situation. str here is a pointer. You seem to be assigning three different objects to to same pointer:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
str=#"Hello World !"; //second object
str=[self getData]; //third object
by the time you call [str release], you've created a memory leak because you've lost the first mutable string. The second time you called str =, you lost any way to access that first NSMutableString.
Assuming that you're looking to concatenate all of these (since you chose NSMutableString), you might try this:
NSMutableString *str = [[NSMutableString alloc] init]; //first object
[str appendString:#"Hello World!"];
[str appendString:[self getData]];
[str release];
If the [self getData] method returns an autoreleased string, you'll be fine. If getData returns a retained string (if you used alloc and init), you'll need to assign it to an intermediate pointer and release it after adding it to str.
What is the need of creating the NSMutableString You can directly use NSString for this purpose

Getting an NSString out of an NSArray

I am trying to save and read back some application settings stored as NSStrings in an iPhone app and have been having some trouble.
The code to save looks like:
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:accountID];
...
[array writeToFile:[self dataFilePath] atomically:YES];
[array release];
And the code to read looks like (accountID is an NSString*):
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
accountID = [array objectAtIndex:0];
...
[array release];
NSLog(#"Loading settings for: %#", accountID);
The read code throws an exception because after the array is released the accountID variable also appears to have been released (moving the NSLog call before releasing the array works fine). So I'm guessing that I'm creating a reference to the array instead of pulling out the actual string contained in the array. I tried several things to create new strings using the array contents but haven't had any luck.
You guess is on the right lines although you have a reference to the 0th element of the array not the array. The array consists of pointers to NSString objects. The Strings will get get released when yhe array is released.
You need to retain the element you are using e/g/
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
NSString* accountID = [[array objectAtIndex:0]retain];
...
[array release];
NSLog(#"Loading settings for: %#", accountID);
When you release the array the reference to the accountID will also be released. You need to retain it.
accountID = [[array objectAtIndex:0] retain];
Then obviously at some point you need to release it.
try [accountID retain] before you release the array