NSArray remove last object of type? - objective-c

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.

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

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.

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

Related

UIImageView Disappear after remove image

I tried to remove my images one by one; for that it's ok but when I tried to add a new image by my library nothing appear, I think my code removes my UIImageView.
-(IBAction)remove:(id)sender {
for (NSUInteger i = 0; i < [self.imageArray count]; i--) {
UIImageView *view = self.imageArray[i];
for (view in [self.view.subviews reverseObjectEnumerator])
if ([view isKindOfClass:[UIImageView class]]){
[view removeFromSuperview];
break;
}
}
}
If you are simply trying to remove and add UIImageViews from a mutable array, you can use the following the code.
//Create and add items to mutable array
NSMutableArray *arr = [#[] mutableCopy];
[arr addObject:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"myImage1"]]];
[arr addObject:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"myImage2"]]];
[arr addObject:[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"myImage3"]]];
//Create temp array to to hold items to remove
NSMutableArray *arrWithItemsToRemove = [#[] mutableCopy];
for(UIView *view in arr)
if([view isKindOfClass:[UIImageView class]])
[arrWithItemsToRemove addObject:view];
//Remove objects
[arr removeObjectsInArray:arrWithItemsToRemove];
NSLog(#"%#", arr);
There are problems with the code you are showing. I am not sure why you have two for loops, and self.imageArray[i] is not even valid Objective-C.
So I am going to assume that you have a view (self.view) which contains subviews, some of which are UIImageViews, and that these are the views you wish to remove.
I would do it like this:
NSMutableArray* viewsToDelete = [NSMutableArray new];
for(UIView* view in self.view.subViews) {
if([view isKindOfClass:[UIImageView class]){
[viewsTodDelete addObject:view];
}
}
// Now remove these
for(UIImageView* imageView in viewsToDelete){
[imageView removeFromSuperView];
}
Note that [subview removeFromSuperview] will delete the subview from its parents subviews array, and that is a potential source of problems.
I am not sure if my code will solve your original problem, but this code is cleaner and simpler than the code you showed us, so it is a good place to start.

Objective C UIActionSheet custom button color

I'm trying to change the color of the button in my UIActionSheet. The problem (a really weird problem) is that if the orientation of the device is Landscape the button color doesn't change!
Some screenshot:
I can't figure out why!
Here's the code:
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet
{
[actionSheet.subviews enumerateObjectsUsingBlock:^(id _currentView, NSUInteger idx, BOOL *stop) {
if ([_currentView isKindOfClass:[UIButton class]]) {
[((UIButton *)_currentView).titleLabel setTextColor:[[MSAppDelegate sharedInstance] defaultColor]];
}
}];
/*
for (UIView *subview in actionSheet.subviews) {
if ([subview isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)subview;
[button setTitleColor:[[MSAppDelegate sharedInstance] defaultColor] forState:UIControlStateNormal];
[button setTitleColor:[[MSAppDelegate sharedInstance] defaultColor] forState:UIControlStateSelected];
}
if ([subview isKindOfClass:[UILabel class]]) {
UILabel *label = (UILabel *)subview;
label.textColor = [[MSAppDelegate sharedInstance] defaultColor];
}
}
*/
}
I also tried the commented code, both work in Portrait but not in Landscape!
By the way either in Landscape and in Portrait the code is executed!
If you want to see all the code here's the link
Thank you in advance!
You could Subclass the UIActionSheet class and implement the tableView:willDisplayCell:forRowAtIndexPath: selector:
#interface MSActionSheet : UIActionSheet
#end
#implementation MSActionSheet
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
[[cell subviews] enumerateObjectsUsingBlock:^(id v, NSUInteger idx, BOOL *stop) {
[[v subviews] enumerateObjectsUsingBlock:^(id v2, NSUInteger idx, BOOL *stop) {
if ([v2 isKindOfClass:[UILabel class]]) {
[(UILabel *)v2 setTextColor:[[MSAppDelegate sharedInstance] defaultColor]];
}
}];
}];
}
#end
use this method to set button title color then i am sure your problem will solve
[[[actionSheet valueForKey:#"_buttons"] objectAtIndex:0] setTitleColor:[[MSAppDelegate sharedInstance] defaultColor] forState:UIControlStateNormal];

How to find UIButton by title

I am having a UIView that has button in it. The buttons are not in some array.
I would like to look at the whole UIView (using for loop) and look for a button by its title, and later remove it.
- (void)removeButtonByTitle:(NSString*)name
{
for (buttons in view) {
// find the button with the name "name" and remove it from the view
}
}
I couldn't find a way to do that without saving their names/pointers to an array.
It's generally preferable to use the tag property for this. Then you can simply find the button with the viewWithTag: method and don't have to adjust your code if you decide to change the button title or localize your app.
If you really need to find a button by its title, you could do it like this:
NSString *buttonTitle = #"name";
UIButton *buttonWithTitle = nil;
for (UIButton *button in view.subviews) {
if (![button isKindOfClass:[UIButton class]]) continue;
if ([[button currentTitle] isEqualToString:buttonTitle]) {
buttonWithTitle = button;
break;
}
}
//do something with the button...
Well you could do it like this:
for (UIView *v in view.subviews)
if ([v isKindOfClass:[UIButton class]] && [[(UIButton *)v currentTitle] isEqualToString:#""])
//remove
But I must say that doesn't sound like a robust solution, your button title could change during localization or it may be different for different states.
Do that:
- (void)removeButtonByTitle:(NSString *)name
{
for (UIView *tempView in self.subviews)
{
if ([tempView isKindOfClass:[UIButton class]]) // make sure it's actually a UIButton
{
UIButton *button = tempView;
if ([button.titleLabel.text isEqualToString:name]) // compare the title
{
[button removeFromSuperview];
}
}
}
}
Check this:
-(void)removeButtonWithTitle:(NSString*)titleString {
NSArray *subViews = [self.view subviews];
[subViews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if([obj isKindOfClass:[UIView class]]) {
NSArray *subViewsArray = [(UIView*)obj subviews];
for (int i=0; i<[subViewsArray count]; i++) {
id subViewObj = [subViewsArray objectAtIndex:i];
if([subViewObj isKindOfClass:[UIButton class]] && [[(UIButton*)subViewObj titleLabel].text isEqualToString:titleString]) {
[subViewObj removeFromSuperview];
*stop = YES;
break;
}
}
}
}];
}

NSMutableArray remove object 1 before last object

I have many UIImageView in an NSMuatableArray and I need to remove a certain UIImageView from the view, but I think that if I release the UIImageView it will still be in the array.
I don't want that, but there is a little problem. The UIImageView that I need to remove is exactly 1 object before the last object in the array, so I can't use removeLastObject. I do know the tag number, but I can't write it like this because I would change the array while using it.
for (UIImageView *k in array1) {
if (k.tag==tagzahl-1) {
if (x==1){
[k removeFromSuperview];
[array1 remove object:k];
}
}
}
I am using: [array1 addObject:myimage]; to add the UIImageViews to the array, so I do not know the index.
If you know that tag which you say you do then
UIView *view = [viewContainingImageView viewWithTag:tagzahl-1];
[view removeFromSuperview];
[array1 removeObject:view];
if ([array1 count] >= 2)
{
NSUInteger index = [array1 count] - 2;
UIImageView *view = [array1 objectAtIndex:index];
[array1 removeObjectAtIndex:index];
[view removeFromSuperview];
}

Resign first responder from separate class

I have a class that makes a keyboard toolbar which has "Next", "Previous", and "Done" buttons on it. Is there a way for this class to know (or find out) what objects are on the screen at any time?
E.g., can it see what the current view is and what the text fields on it are, and then be able to resign the first responder?
If you specifically want to resign first responder without the need to known which view is the first responder you can send resignFirstResponder to "nil" like this:
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
This is documented behaviour although I cannot find in the docs right now.
Is there a way for this class to know
(or find out) what objects are on the
screen at the time?
Find the momma view and you can iterate through all the objects on the screen (because they will be UIViews too) like this. Note that you may need to add recursion:
for (UIView *view in mommaView.subviews) {
do something to the view
}
You can start at the Window class and go down from there, asking [view respondsTo:#selector(isFirstResponder) && [view isFirstResponder] on each. Some debugging code that I use might come in handy as a template and also while debugging:
+ (void) dumpWindowFrom:(NSString *) fromText {
[self dumpViews:[[UIApplication sharedApplication] keyWindow] from:fromText];
}
void dumpViewsRecursive(UIView* view, NSString *text, NSString *indent)
{
Class cl = [view class];
NSString *classDescription = [cl description];
// while ([cl superclass]) //restore to print superclass list
// {
// cl = [cl superclass];
// classDescription = [classDescription stringByAppendingFormat:#":%#", [cl description]];
// }
if ([text compare:#""] == NSOrderedSame)
NSLog(#"%d: %# %# %#", (int)view, classDescription, NSStringFromCGRect(view.frame), view.hidden ? #"Inv" : #"Vis");
else
NSLog(#"%d: %# %# %# %#", (int)view, text, classDescription, NSStringFromCGRect(view.frame), view.hidden ? #"Inv" : #"Vis");
for (NSUInteger i = 0; i < [view.subviews count]; i++)
{
UIView *subView = [view.subviews objectAtIndex:i];
NSString *newIndent = [[NSString alloc] initWithFormat:#" %#", indent];
NSString *msg = [[NSString alloc] initWithFormat:#"%#%d:", newIndent, i];
dumpViewsRecursive (subView, msg, newIndent);
[msg release];
[newIndent release];
}
}
+ (void) dumpViews: (UIView *) view {
dumpViewsRecursive (( (!view) ? [[UIApplication sharedApplication] keyWindow] : view), #"" ,#"");
}
+ (void) dumpViews: (UIView *) view from:(NSString *) fromText{
dumpViewsRecursive ((!view) ? [[UIApplication sharedApplication] keyWindow] : view, fromText, #"");
}
yes, the methods provided below will be called whenever a textField becomes Active. I think you are looking for
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return 1;
}
or
- (void) textFieldDidBeginEditing:(UITextField *)textField
{
[textField resignFirstResponder];
}
- (void) textFieldDidEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
}
and if you are looking for a specific textField in your view, you should assign them tags:
textField.tag =1 // for textField 1
textField.tag =2 // for textField 2
// You may check for these tags and then resign specific ones.