Working with an array of UIViews and UIImageViews ([[[UIApplication sharedApplication] window] subviews]). I need to remove only the object of the highest index of the UIImageView type.
Asked
Active
Viewed 1,579 times
3
-
NOTE: You need to use an NSMutableArray instead of a NSArray. – Moshe Feb 03 '12 at 15:37
3 Answers
6
You can use indexOfObjectWithOptions:passingTest:
method to search the array in reverse for an object that passes a test using a block, and then delete the object at the resulting position:
NSUInteger pos = [myArray indexOfObjectWithOptions:NSEnumerationReverse
passingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [obj isKindOfClass:[UIImageView class]]; // <<== EDIT (Thanks, Nick Lockwood!)
}];
if (pos != NSNotFound) {
[myArray removeObjectAtIndex:pos];
}

Sergey Kalinichenko
- 714,442
- 84
- 1,110
- 1,523
-
2This is a nice solution, but you should compare the type using isKindOfClass instead of ==, otherwise if the UIImageView is actually a subclass of UIImageView it won't work. – Nick Lockwood Feb 03 '12 at 16:26
-
@NickLockwood That's a nice catch, thank you very much for spotting the problem! – Sergey Kalinichenko Feb 03 '12 at 16:31
-
1You also need to add a check that pos != NSNotFound, or it will crash if the array doesn't contain a UIImageView. – Nick Lockwood Feb 03 '12 at 17:50
5
another block-based solution
[window.subviews enumerateObjectsWithOptions:NSEnumerationReverse
usingBlock:^(id view, NSUInteger idx, BOOL *stop)
{
if ([view isKindOfClass:[UIImageView class]]){
[view removeFromSuperview];
*stop=YES;
}
}];
non-block solution:
for (UIView *view in [window.subview reverseObjectEnumerator])
{
if ([view isKindOfClass:[UIImageView class]]){
[view removeFromSuperview];
break;
}
}
I published some demo code, that shows both solutions.

Zoe
- 27,060
- 21
- 118
- 148

vikingosegundo
- 52,040
- 14
- 137
- 178
-
These could be improved by removing the view directly inside the loop, then you wouldn't need the viewToRemove variable any more. – Nick Lockwood Feb 03 '12 at 16:22
-
are you sure? in fast enumeration it is forbidden to alter the array while enumerating. – vikingosegundo Feb 03 '12 at 16:24
-
@NickLockwood For the reverseObjectEnumerator you are right. but not, if you fast enumerate over the array directly. – vikingosegundo Feb 03 '12 at 16:31
-
Yeah, true. I forgot you can't safely modify an array while iterating over it. – Nick Lockwood Feb 03 '12 at 16:44
-
@Kyle I confirmed it myself. see my edit for even prettier code. – vikingosegundo Feb 03 '12 at 17:20
3
How about:
UIWindow *window = [[UIApplication sharedApplication] window];
UIView *imageView = nil;
for (UIView *view in window.subviews)
{
if ([view isKindOfClass:[UIImageView class]])
{
imageView = view;
}
}
//this will be the last imageView we found
[imageView removeFromSuperview];

Nick Lockwood
- 40,865
- 11
- 112
- 103
-
Well Kyle liked your solution better anyway, so i guess you win, lol ;-) – Nick Lockwood Feb 03 '12 at 16:21
-
1:) My code usually spends 30 min in front of the mirror every day, to become pretty. – vikingosegundo Feb 03 '12 at 16:22
-
-
I bow to your dedication to the pursuit of perfection! +1s all round. – Nick Lockwood Feb 03 '12 at 17:47
-
-
I preferred vikingosegundo's solution because it enumerated from the last element to the first. Since I only expect there to be a single other view on the stack following the last UIImageView it might be marginally faster. Your solution was the first one that worked, and had no errors/edits. – Kyle Feb 03 '12 at 18:48