Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

iOS

Add multiple image in same UIImageView and change them at each tap

I'm trying to implement a UIImageView that shows different .png (organized in a NSArray) at each tap. When the tap reaches the last .png, the next tap will show the first .png and so on. I do not use any IBAction for getting the touch but I rather do everything programmatically via:

[myButton addTarget:self action:@selector(myButtonWasTapped:) forControlEvents:UIControlEventTouchUpInside];

The best solution would be to define a method in a separate class that takes the NSArray of pictures as argument and goes through it at each tap. However, my difficulty is to understand how to pass the NSArray as selector in the action above. Does anybody have an idea on how to subclass then entire ImageView to get the expected result?

6 Answers

You cannot pass a custom value to the selector this way. A detailed explanation can be found here, have a look at the selected answer.

What you could do, though, is create a helper property that holds the index of the currently displayed image, increment that on every tap and set the image accordingly.

@interface YourViewController ()
@property (nonatomic, strong) NSArray *images;
@property (nonatomic, assign) NSInteger currentImageIndex;
@end

@implementation YourViewController

- (void)viewDidLoad {

    // Here you fill your images array
    self.images = ...   

    //  Set currentImageIndex to 0 and display first image 
    self.currentImageIndex = 0;
    [self displayImageWithIndex:self.currentImageIndex];

    // Additional code, like your button target/action
    ...
}

- (void)myButtonWasTapped:(id)sender
{
    if(self.currentImageIndex + 1 < [self.images count]) {
        self.currentImageIndex++;
    } else {
        self.currentImageIndex = 0;
    }
    [self displayImageWithIndex: self.currentImageIndex];
}

- (void)displayImageWithIndex:(NSInteger)index {
   self.imageView.image = [self.images objectAtIndex:index];
}

@end

Please note: I have written this code in this text editor and have not tested it. Moreover, there might be a better approach to this, this is just what came to my mind...

With target action there are three ways of calling the action method. They are predefined and you cannot use it for custom data. The action method you are calling has to match the parameters defined in the selector, indicated with a :

Below is an example for the three possible ways of using target action, simplified and not compilable, but I think you will get the gist.

Version 1: no argument

action:@selector(action)
- (void)action 

Version 2: one argument, is always sender

action:@selector(action:)
- (void)action:(id)sender

Version 3: two arguments, first always sender, second always event

action:@selector(action:event:)
- (void)action:(id)sender forEvent:(UIEvent *)event

Please also read the Apple Developer Docs on this topic.

Thank you Martin for your answer. I know the answer you linked actually, but I got lost when trying to send the id userData.

Your idea of using an helper is definitely the way to go. However, when basing my code on your answer, I keep getting the warning of 'Undeclared selector 'myButtonWasTapped' '. Yet, I declare it in the way you pointed out. This is not a new warning to me as I received the same message in my previous attempt. Maybe I keep repeating the same mistake... By the way, where would you declare and initialize the imageView and show it in a subview? In the displayImageWithIndex method? Thanks again!

Hi again Martin, actually by deleting the :(id)sender after the - (void)myButtonWasTapped: it worked nicely. However, this is a typical situation where I have to spend some time to understand the reason it worked...any ideas? By the way, I realized where to put the UIImageView. Once again, thank you for your time and solution. It really helped me!

Martin, you have been very kind and your explanations are extremely clear. Now I have got it. Thanks once again!

Hey there, you are welcome, glad I could help :)