You could make it work by using a container view to hold the buttons.
-(void)viewDidAppear:(BOOL)animated
{
_viewContents = [model getRequestedView]; //this retrieves an array of UIButtons(24 of them) whose frames and background colors have already been initialized to fit within the TileView.
for(int i = 0; i < [_viewContents count]; i++){
UIView *container = [[UIView alloc] initWithFrame:[[_viewContents objectAtIndex:screenViewIndex] frame]];
container.tag = i;
UIButton *frontOfCardView = [[UIButton alloc] initWithFrame:container.bounds];
frontOfCardView.backgroundColor = [UIColor colorWithPatternImage:_frontOfCardImage];
frontOfCardView.tag = i;
[container addSubview:frontOfCardView];
[frontOfCardView addTarget:self action:@selector(frontOfCardPushed:) forControlEvents:UIControlEventTouchUpInside];
[tileView addSubview:container];
}
}
-(IBAction)frontOfCardPushed:(UIButton *)sender
{
UIView *container = [tileView viewWithTag:sender.tag];
UIView *viewToShow = [_viewContents objectAtIndex:index];
viewToShow.frame = sender.frame;
[UIView transitionWithView:container
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[sender removeFromSuperView];
[container addSubview:viewToShow];
}
completion:nil];
}
I haven't tested it but it should work. Anyway, this is not very clean/pretty code. But, I understand it's only for learning purpose.
Let me know if it still doesn't work.
EDIT :
I made a simple project with a single view controller as an example. I think that the way you keep track of all your views/buttons is useless. In this case the model is only a background color and all you want to do is to reveal/hide it, so once you assign the color to a button, all it has to know is to switch states, so you don't even need tags.(In other cases the controller would need to identify which button that received an event in order to ask the model what content it needs)
#import "ViewController.h"
@interface ViewController ()
@property (nonatomic, strong) NSArray *colors;
@property (nonatomic, strong) UIView *tileView;
@end
@implementation ViewController
#pragma mark -
#pragma Getters and setters
// I'm assuming the tileView is just a simple view to wrap all the buttons
// PS : propertys should always start with a lowercase letter
-(UIView *)tileView
{
if (!_tileView) {
_tileView = [[UIView alloc] initWithFrame:self.view.bounds];
_tileView.backgroundColor = [UIColor greenColor];
}
return _tileView;
}
// The model: just an array of colors, you can generate it or use other complicated stuff
-(NSArray *)colors
{
if (!_colors) {
_colors = @[[UIColor blackColor], [UIColor redColor], [UIColor grayColor], [UIColor yellowColor],
[UIColor whiteColor], [UIColor blueColor], [UIColor orangeColor], [UIColor darkGrayColor],
[UIColor lightGrayColor], [UIColor cyanColor], [UIColor brownColor], [UIColor magentaColor],
[UIColor blackColor], [UIColor redColor], [UIColor grayColor], [UIColor yellowColor],
[UIColor whiteColor], [UIColor blueColor], [UIColor orangeColor], [UIColor darkGrayColor],
[UIColor lightGrayColor], [UIColor cyanColor], [UIColor brownColor], [UIColor magentaColor]];
}
return _colors;
}
#pragma mark -
#pragma mark Helper methods
#define ROWS 6
#define COLUMNS 4
#define CARD_HEIGHT 60.0f
#define CARD_WIDTH 40.0f
// Gets the width that each card can use based on the chose number of columns
-(CGFloat)horizontalStep
{
return self.tileView.frame.size.width / COLUMNS;
}
// Gets the height that each card can use based on the chose number of columns
-(CGFloat)verticalStep
{
return self.tileView.frame.size.height / ROWS;
}
// Calculates the center for the card frame (return (0,0) if the index is out of bounds)
-(CGPoint)centerForCardAtIndex:(NSUInteger)index
{
CGFloat x = 0.0f, y = 0.0f;
if (index < [self.colors count]) {
x = [self horizontalStep] * 0.5f + (index % COLUMNS) * [self horizontalStep];
y = [self verticalStep] * 0.5f + (index / COLUMNS) * [self verticalStep];
}
return CGPointMake(x, y);
}
// Gets the frame for the card at index
-(CGRect)frameForCardAtIndex:(NSUInteger)index
{
CGPoint center = [self centerForCardAtIndex:index];
CGPoint origin = CGPointMake(center.x - CARD_WIDTH * 0.5f, center.y - CARD_HEIGHT * 0.5f);
return CGRectMake(origin.x, origin.y, CARD_WIDTH, CARD_HEIGHT);
}
-(void)layoutCards
{
// Add tileView to the controller's view
[self.view addSubview:self.tileView];
// Create the card buttons and add them to the tile view
for (int i = 0; i < [self.colors count]; i++) {
UIButton *card = [UIButton buttonWithType:UIButtonTypeCustom];
card.frame = [self frameForCardAtIndex:i];
// The only use of the model IN THIS CASE
card.backgroundColor = self.colors[i];
[card setImage:[UIImage imageNamed:@"back_of_tile.png"]
forState:UIControlStateNormal];
[card addTarget:self
action:@selector(cardPressed:)
forControlEvents:UIControlEventTouchUpInside];
[self.tileView addSubview:card];
}
}
-(void)cardPressed:(UIButton *)card
{
[UIView transitionWithView:card
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
card.selected = !card.selected;
if (!card.selected) {
[card setImage:[UIImage imageNamed:@"back_of_tile.png"]
forState:UIControlStateNormal];
} else {
[card setImage:nil
forState:UIControlStateNormal];
}
}
completion:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self layoutCards];
}