Objective-C: `continue` in collection enumeration block? - objective-c

If I have an NSArray and I use enumerateUsingBlock to loop through elements in the array, but in some cases I need to skip the loop body and go to next element, is there any continue equivalent in block, or can I use continue directly?
Thanks!
update:
Just want to clarify, what I want to do is:
for (int i = 0 ; i < 10 ; i++)
{
if (i == 5)
{
continue;
}
// do something with i
}
what I need is the continue equivalent in block.

A block is a lot like an anonymous function. So you can use
return
to exit from the function with return type void.

Use "continue" when using Fast Enumeration to do this.
Sample code:
NSArray *myStuff = [[NSArray alloc]initWithObjects:#"A", #"B",#"Puppies", #"C", #"D", nil];
for (NSString *myThing in myStuff) {
if ([myThing isEqualToString:#"Puppies"]) {
continue;
}
NSLog(#"%#",myThing);
}
and output:
2015-05-14 12:19:10.422 test[6083:207] A
2015-05-14 12:19:10.423 test[6083:207] B
2015-05-14 12:19:10.423 test[6083:207] C
2015-05-14 12:19:10.424 test[6083:207] D
Not a puppy in sight.

You can not use continue in block, you will get error: continue statement not within a loop. use return;
[array enumerateObjectsUsingBlock: ^(id obj, NSUInteger idx, BOOL *stop) {
/* Do something with |obj|. */
if (idx==1) {
return;
}
NSLog(#"%#",obj);
}];

Related

How to safely remove object from a nsmutablearray while iterating through it?

I am using a nsmutablearray in loop and want to remove its object (or assign nil) that has just traversed.
But if I am doing so, I get an error as <__NSArrayM: 0x8c3d3a0> was mutated while being enumerated.' . The code is as below
- (TreeNode*)depthLimitedSearch:(TreeNode *)current costLimit:(int)currentCostBound {
NSMutableArray *children=[NSMutableArray arrayWithArray:[current expandNodeToChildren]];
for (TreeNode *s in children) {
if (s.puzzleBox.isFinalPuzzleBox) {//checking for final puzzleBox
return s;
}
/*exploredNodes++;
if (exploredNodes %10000==0) {
NSLog(#"explored nodes for this treshold-%d are %d",currentCostBound,exploredNodes);
}*/
int currentCost =[s.cost intValue]+[s.heuristicsCost intValue];
if (currentCost <= currentCostBound) {
//[s.puzzleBox displayPuzzleBox];
TreeNode *solution = [self depthLimitedSearch:s costLimit:currentCostBound];
if (solution!=nil){//&& (bestSolution ==nil|| [solution.cost intValue] < [bestSolution.cost intValue])) {
bestSolution = solution;
return bestSolution;
}
}else {
if (currentCost < newLimit) {
//NSLog(#"new limit %d", currentCost);
newLimit = currentCost;
}
}
// here I want to free memory used by current child in children
[children removeObject:s]
}
children=nil;
return nil;
}
and I have commented the place where I want to release the space used by the child.
You should not be using a for...in loop if you want to remove elements in the array. Instead, you should use a normal for loop and go backwards in order to make sure you don't skip any items.
for (NSInteger i = items.count - 1; i >= 0; i--) {
if (someCondition) {
[items removeObjectAtIndex:i];
}
}
You can collect the items to be removed in another array and remove them in a single pass afterwards:
NSMutableArray *toRemove = [NSMutableArray array];
for (id candidate in items) {
if (something) {
[toRemove addObject:candidate];
}
}
[items removeObjectsInArray:toRemove];
It’s easier than iterating over indexes by hand, which just asking for off-by-one errors.
Not sure how this plays with your early returns, though.

How to recognize the first element in Objective-C style enumeration?

I have an NSMutableArray of NSNumbers, I want to enumerate through all of them with Objective-C styled enumeration. Here's what I've done so far.
for ( NSNumber* number in array )
{
//some code
}
I want to be able to recognize the first object fast, I am able to do this of course,
if ( [array indexOfObject:number] == 0 )
{
//if it's the first object
}
Is there any way to do this faster? There's of course the old-fashioned C style way, and remove the object from array first, and then put it back after enumeration. Just want to know if there's a better technic.
You can try using a method that provides the index of the object currently being enumerated:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx == 0) {
// this is the first object
}
}];
Or if you simply want to access the first object of an array:
id obj = [array objectAtIndex:0];
or with the new Objective-C style/syntax:
id obj = array[0];
This solution is faster than accessing and comparing the first array element:
BOOL firstIteration = YES;
for (NSNumber *number in array) {
if (firstIteration) {
// Handle first iteration
firstIteration = NO;
}
// Do something
}
In fast enumeration you cant alter the array. So if you want to remove you have to use old style for(;;) loop.
To find the first object simply use [array objectAtIndex:0]

Cocoa/Objective-C - How do I step through an array?

Not sure if I am wording this correctly but what I need to do is iterate through an array sequentially but by 2 or 3 or 4 indices.
So you can iterate through an array like this
for(id arrayObject in NSArray) {
//do something amazing with arrayObject
}
which will iterate sequentially through each indexed object, [NSArray objectAtIndex: 0], [NSArray objectAtIndex: 1], etc.
so what if I just want object 0, 4, 8, 12, etc.
Thanks
Not quite. The way you wrote it, you are omitting the class of the arrayObject, and you are iterating through the NSArray class name rather than an instance. Thus:
for (id arrayObject in myArray) {
// do stuff with arrayObject
}
where myArray is of type NSArray or NSMutableArray.
For instance, an array of NSStrings
for (NSString *arrayObject in myArray) { /* ... */ }
If you want to skip parts of the array, you will have to use a counter.
for (int i=0; i< [myArray count]; i+=4) {
id arrayObject = [myArray objectAtIndex:i];
// do something with arrayObject
}
You could use enumerateObjectsUsingBlock: and check the index inside the block:
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if( 0 == idx % 3 ){
// Do work
}
else{
// Continue enumeration
return;
}
}];
This would also allow you to operate on non-stride-based selections of your array, if necessary for some reason, e.g., if( (0 == idx % 3) || (0 == idx % 5) ), which would be much more difficult with a plain for loop.
I'd like to add, that there are also block-based enumeration methods, you could use.
NSMutableArray *evenArray = [NSMutableArray array];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (idx % 4 == 0)
[evenArray addObject:obj];
}];
Now evenArray will contain the objects with the indexes 0,4,8,… in the original array.
But often one will want to have just the filtered objects in the original array, and won't need a additionally mutable array.
I wrote some block-based convenient methods to achieve this:
array = [array arrayByPerformingBlock:^id(id element) {
return element;
} ifElementPassesTest:^BOOL(id element) {
return [array indexOfObject:element]%4 == 0;
}];
This will have the same result but hides the boilerplate code of creating and filling a mutable array.
You'll find my arraytools on GitHub.
You can do this with an NSEnumerator:
NSEnumerator *arrayEnum = [myArray objectEnumerator]; //Or reverseObjectEnumerator
for (MyThingy *thingy in arrayEnum) {
doThingyWithThingy(thingy);
[arrayEnum nextObject]; //Skip element
}
You can have zero or more nextObject messages at either point. For every third object, you would have two nextObjects at the end of the loop:
for (MyThingy *thingy in arrayEnum) {
doThingyWithThingy(thingy);
//Skip two elements
[arrayEnum nextObject];
[arrayEnum nextObject];
}
Basically, this is the same way you gather multiple objects in a single pass through the loop, only without actually using the other objects.
You can also have zero or more nextObject messages before the loop to skip some number of objects before the first one you want.
(I hope you're doing this to an array you read in, not one you generated yourself. The latter case is a sign that you should consider moving from array manipulation to model objects.)

What is faster? Enumeration VS For loop

What is faster in objective C and iphone? self enumeration or for loop?
i have 2 fragments of code to help me compare.
for this example we have as a fact that array is an NSMutableArray with "x" items.
Case 1:
-(void)findItem:(Item*)item
{
Item *temp;
for (int i = 0 ;i<[array count];i++)
{
temp = [array objectAtIndex:i];
if(item.tag == temp.tag)
return;
}
}
Case 2:
-(void)findItem:(Item*)item
{
for(Item *temp in array)
{
if(item.tag == temp.tag)
return;
}
}
it is almost obvious that case2 is faster, is it?
It's called fast enumeration, for a reason.
See: http://cocoawithlove.com/2008/05/fast-enumeration-clarifications.html

Getting the size of an array

i have some code that requires the use of a for loop to read variables from an array.
int size=sizeof names;
NSLog(#"thelast one is %d",size);
NSString *usersName=userName.text;
NSString *usersPass=passWord.text;
for (i=0; i<=size;i++){
NSString *namesArray=[names objectAtIndex:i];
NSString *passArray=[pass objectAtIndex:i];
NSLog(#"namesArray %#",namesArray);
NSLog(#"passArray %#",passArray);
if([namesArray isEqualToString:usersName]){
userValid=1;
NSLog(#"The content of arry4 is %#",namesArray);
}
if([passArray isEqualToString:usersPass]){
passValid=1;
NSLog(#"The content of arry4 is %#",passArray);
}
else {
userValid=0;
passValid=0;
}
}
I've been having some problems because every time this function is called from within the program, it's almost as if the 'sizeof names' is wrong, therefore not all values in the array are checked.
I'm generally a Java programmer so i'm used to names.length, and i was told sizeof names is essentially the same thing... any help?
Cheers.
Don't use sizeof. Use [names count].
You want to use [names count] not sizeof names. Sizeof is going to give you the size of the actual names object pointer itself and not the number of elements, since it's dynamic memory type.
To get the number of elements stored in an NSAarray you should use the instance method count, which returns an NSUInteger.
Alternatevely, you can iterate over these elements using the for in loop, which is available also in Java, if I recall correctly.
for (MyClass *element in myArray) {
NSLog(#"%#", element);
}
Note that sizeof is a C operator that returns the size in bytes of its operand, so it doesn't tell you how many elements are stored in that NSArray, but the size in bytes of one NSArray instance.
I know your question has already been answered - but here is a more Cocoa way of writing it
NSString *userName = userName.text;
NSString *userPass = passWord.text;
// Use a block enumerator
NSUInteger nameIdx = [names indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return ([obj isEqualToString:userName]);
}];
// Is the name in the array
if (nameIdx == NSNotFound) {
// Name not in array - so set to zero
userValid = 0;
passValid = 0;
} else {
userValid = 1;
// See if the corresponding password is correct
NSString password = [pass objectAtIndex:nameIdx];
if (![password isEqualToString:userPass]) {
passValid = 0;
} else {
passValid = 1;
}
One can also use Fast Enumeration, in some cases it can be more clear to a reader:
NSString *userName = userName.text;
NSString *userPass = passWord.text;
BOOL userValid = NO;
BOOL passValid = NO;
int index = 0;
for (NSString *eachName in namesArray) {
if ([eachName isEqualToString:userName) {
userValid = YES:
if ([[passArray objextAtIndex:index] isEqualToString:passWord) {
passValid = YES;
}
break;
}
index += 1;
}