why does __block not adding values to array - objective-c

I am enumerating ranges inside a block and storing the values inside an array. I expected using __block should store the values inside block into array?
__block NSMutableArray *array;
[indexSet enumerateRangesUsingBlock:^(NSRange range,BOOL * stop ) {
[array addObject:#(range.location)];
[array addObject:#(range.length)];
NSLog(#"location is %d, %ld", range.location, range.length);
}];
NSLog(#"%#",array );
But this result in
location is 4, 2 location is 8, 2 location is 14, 2
and for array
(null)
I expected array to be filled with values.

You have to initialize it, a just declared array is nil:
__block NSMutableArray *array = [NSMutableArray array];
(The Swift compiler would throw an error ... 😉 )

__block NSMutableArray *array = [NSMutableArray array];
It does work fine.
However when I declared array as property then block became redundant.

Related

Trying to build polygon from NSString

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

obj-c fetching strings from array

i'm new to obj-c (this is my first day class eheh) and i'm trying to change a label with a random string from a multidimensional array. plus, every time the button is hitten you switch the array. i know it's a bit odd eheh… this is the IBAction:
UIButton *button = (UIButton *)sender;
NSMutableArray *firstArray = [NSMutableArray array];
[firstArray addObject:#"foo"];
NSMutableArray *secondArray = [NSMutableArray array];
[secondArray addObject:#"bar"];
NSMutableArray *frasi = [NSMutableArray array];
[frasi addObject:firstArray];
[frasi addObject:secondArray];
NSMutableArray *array = [NSMutableArray arrayWithObjects:[frasi objectAtIndex:[button isSelected]], nil];
NSString *q = [array objectAtIndex: (arc4random()% [array count] )];
NSString *lab = [NSString stringWithFormat:#"%#", q];
self.label.text = lab;
all works, but the new label is
( "foo" )
instead of just foo (without quotes)... probably i mess in the last block of code...
ty
So, you create 2 mutable arrays, then add them to a new mutable array frasi. Then you get one of those two arrays and use it as the single element (because you use arrayWithObjects: instead of arrayWithArray:) of a new array array.
So array is an array that contains a single array element (instead of an array of strings as you may believe).
When you get an object from array, it's always the same single object that was used to initialize it: either firstArray or secondArray.
So you get an array of strings where you expect a string. When using stringWithFormat:, the specifier %# is replaced with the string description of that object.
A string returns itself as its own description. But the description of an array is the list of all its elements separated with commas and surrounded by parenthesis, which is why you get ( "foo" ).
So instead or creating unneeded arrays, you may just replace all the 8th last lines with this:
NSArray *array = [button isSelected] ? secondArray : firstArray;
self.label.text = [array objectAtIndex:arc4_uniform([array count])];
Actually u have array within array
Replace this line with yours:
NSString *q = [[array objectAtIndex: (arc4random()% [array count] )] objectAtIndex:0];

NSMutableArray not being saved

I'm trying to insert objects (NSNumbers) into an NSMutable array, but when I check it, the objectAtElement always returns 0.
NSNumber *indexNum = [NSNumber numberWithInt:indexInt];
[last100 insertObject:indexNum atIndex:prevCount];
NSLog(#"Entry #%d : %d", prevCount, (int)[last100 objectAtIndex:prevCount]);
prevCount++;
indexInt is coming in through the method, I already checked it and its valid. indexNum has also been checked and matches indexInt. The problem is NSLog(#"Entry #%d : %d", prevCount, (int)[last100 objectAtIndex:prevCount]); which always returns
2012-01-08 14:08:11.551 ThoughtSpreader[20746:fb03] Entry #9 : 0 The entry number will change, but the 0 is always there.
Oh, I also checked [last100 count] after every time I insert something new into it, and it always returns 0, so I believe its a problem with how I'm inserting something into the NSMutable array
If your count always returns 0 the likelihood is you haven't actually instantiated your NSMutableArray.
NSMutableArray *array = [NSMutableArray array];
[array addObject:[NSNumber numberWithInt:1]];
NSLog(#"%lu", [array count]); // Count => 1
//-------
array = nil;
[array addObject:[NSNumber numberWithInt:1]]; // Calling methods on nil is a no-op
NSLog(#"%lu", [array count]); // Count => 0
Updated %d to %lu thanks to #markhunte - it's hard to remember the finer details without testing it
Use
[[last100 objectAtIndex:prevCount] intValue]
instead of
(int)[last100 objectAtIndex:prevCount] - this explict conversion won't work.
[... intValue] is the message of NSNUmber which converts it to int.
NSNumber is an object, you can't just cast it to an int. Use intValue:
NSLog(#"Entry #%d : %d", prevCount, [[last100 objectAtIndex:prevCount] intValue]);

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.