Matching images - objective-c

I`ve got a very unexpected problem which making me crazy. This is very simple type of memory game with 36 cards. In code below I making array with 36 objets (18 double objects). Everything works great when you choose card between 1-12. When you choose higher card, matching process can't recognize match. Why???
memory.m
for (int i = 0; i < [imagesArray count]; ++i)
{
int n = i;
[imagesArray exchangeObjectAtIndex:i withObjectAtIndex:n];
NSLog(#"index obrázku %i",i);
NSLog(#"index array %i",n);
}
// Set button images
for (int i=0; i<[buttonsArray count]; i++) {
NSLog(#"index button %i",i);
UIButton *singleButton = [buttonsArray objectAtIndex:i];
[singleButton setBackgroundImage:[UIImage imageNamed:TILE_BACKGROUND] forState:UIControlStateNormal];
[singleButton setBackgroundImage:[UIImage imageNamed:TILE_BACKGROUND] forState:UIControlStateHighlighted];
if ([[imagesArray objectAtIndex:i] integerValue] == 1) {
[singleButton setBackgroundImage:[UIImage imageNamed:TILE_IMAGE1] forState:UIControlStateDisabled];
NSLog(#"Karta 1 tag %i",i);
} else if ([[imagesArray objectAtIndex:i] integerValue] == 2) {
[singleButton setBackgroundImage:[UIImage imageNamed:TILE_IMAGE2] forState:UIControlStateDisabled];
NSLog(#"Karta 2 tag %i",i);
}
objects are from 1 to 18...
- (IBAction)tileClicked:(id)sender {
// Button is clicked
if (!matchingInPogress) {
UIButton *clickedButton = sender;
tilesOpened++;
NSLog(#"Počet otočených karet je %i",tilesOpened);
[clickedButton setEnabled:NO];
if (tilesOpened == 1) {
// Only one tiled opened, remeber tag for match
openTileIndex = clickedButton.tag;
} else {
// Second tile is opened, perform match
matchingInPogress = YES;
[self performSelector:#selector(matchTiles:) withObject:[NSNumber numberWithInt:clickedButton.tag] afterDelay:0.5];
tilesOpened = 0;
}
}
button control..
- (void)matchTiles:(NSNumber *)clickedTile {
// Match opened tiles
int clickedTileIndex = [clickedTile integerValue];
NSLog(#"Karta 1 tag %i",clickedTileIndex);
NSLog(#"Karta 2 tag %i",openTileIndex);
if ([imagesArray objectAtIndex:clickedTileIndex] != [imagesArray objectAtIndex:openTileIndex]) {
NSLog(#"Porovnává hodnoty v clickedTileIndex a openTileIndex");
// If tiles don't match set them to enabled state
UIButton *firstButton = [buttonsArray objectAtIndex:openTileIndex];
UIButton *secondButton = [buttonsArray objectAtIndex:clickedTileIndex];
NSLog(#"Nesouhlas tag je %i",openTileIndex);
NSLog(#"Nesouhlas tag je %i",clickedTileIndex);
[firstButton setEnabled:YES];
[secondButton setEnabled:YES];
} else {
NSLog(#"Match!");
UIButton *firstButton = [buttonsArray objectAtIndex:openTileIndex];
UIButton *secondButton = [buttonsArray objectAtIndex:clickedTileIndex];
NSLog(#"Souhlas tag je %i",openTileIndex);
NSLog(#"Souhlas tag je %i",clickedTileIndex);
[firstButton setHidden:YES];
[secondButton setHidden:YES];
}
matchingInPogress = NO;
}
and finaly matching process
Thanks!

Since arrays can only contain objects, you don't test them with != as that will only compare the value of the pointers and not the objects themselves. Very often, this works (even though you wouldn't expect it to) for some (usually low) values but quits working on others because UIKit objects often cache objects sand return the same object address, even for different instances.
You need to change this line in tileClicked:
if ([imagesArray objectAtIndex:clickedTileIndex] != [imagesArray objectAtIndex:openTileIndex]) {
to this:
if (![(UIImage *)[imagesArray objectAtIndex:clickedTileIndex] isEqual:
(UIImage *)[imagesArray objectAtIndex:openTileIndex]]) {

Related

Highlighting the button with sender tag

I have 7 buttons on my storyboard, I have associated a tag number to each of the button. And all the buttons are hooked up to a single IBAction.
In my action method I have a switch statement like switch ([sender tag])
which run the appropriate action according to the tag. This is all working.
But I want to add a functionality where selected button is highlight and rest of them in normal state.
You can create property with tags:
#property (nonatomic, strong) NSArray *tags;
Somewhere (for example, in viewDidLoad) initialize it with values used in storyboard:
tags = #[#1, #2, #3, #4, #5]
And select buttons using this tags
- (IBAction)buttonPressed:(UIButton *)sender {
for (int i = 0; i < tags.count; i++) {
UIButton *button = [self.view viewWithTag:tags[i]];
button.selected = (button.tag == sender.tag);
}
}
Or you can create IBOutlets for every 7 buttons and create array for it.
array = #[outlet1, ..., outlet7]
And select buttons using outlets
- (IBAction)buttonPressed:(UIButton *)sender {
for (int i = 0; i < array.count; i++) {
UIButton *button = array[i];
button.selected = (button.tag == sender.tag);
}
}
Hope this can give you some idea:
- (void)setupButtons {
for (int i = 0; i < 7; i++) {
CGFloat width = self.view.frame.size.width / 7;
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(i * width, 100, width, 30)];
[self.view addSubview:button];
button.tag = 1000 + i;
[button setTitle:[NSString stringWithFormat:#"%d", i] forState:UIControlStateNormal];
button.backgroundColor = [UIColor redColor];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected];
[button addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchDown];
if (i == 0) {
// default first button selected
button.selected = YES;
}
}
}
- (void)buttonClicked:(UIButton *)sender {
for (int i = 0; i < 7; i++) {
UIButton *button = [self.view viewWithTag:(1000+i)];
button.selected = (button.tag == sender.tag);
}
}

UIPageControl is not with UIImageView in IOS7

In my efforts to upgrade my application to support IOS7 I found out that UIPageControl doesn't support the UIImageView. They have changed it.
I'm subclassing the UIPageControl in order to put custom circles instead the regular ones (attached an example)
My class is:
- (id)initWithFrame:(CGRect)frame
{
// if the super init was successfull the overide begins.
if ((self = [super initWithFrame:frame]))
{
// allocate two bakground images, one as the active page and the other as the inactive
activeImage = [UIImage imageNamed:#"active_page_image.png"];
inactiveImage = [UIImage imageNamed:#"inactive_page_image.png"];
}
return self;
}
// Update the background images to be placed at the right position
-(void) updateDots
{
for (int i = 0; i < [self.subviews count]; i++)
{
UIImageView* dot = [self.subviews objectAtIndex:i];
if (i == self.currentPage) dot.image = activeImage;
else dot.image = inactiveImage;
}
}
// overide the setCurrentPage
-(void) setCurrentPage:(NSInteger)page
{
[super setCurrentPage:page];
[self updateDots];
}
Now in the IOS7 I got the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView setImage:]: unrecognized selector sent to instance 0xe02ef00'
and after investigating I understood that the following code cause the error:
UIImageView* dot = [self.subviews objectAtIndex:i];
if (i == self.currentPage) dot.image = activeImage;
else dot.image = inactiveImage;
I checked the subviews and saw that it is UIView instead of UIImageView. probably Apple changed something.
Any idea how to fix it?
It looks like they changed the subviews to standard UIViews. I managed to work around it by doing this:
for (int i = 0; i < [self.subviews count]; i++)
{
UIView* dotView = [self.subviews objectAtIndex:i];
UIImageView* dot = nil;
for (UIView* subview in dotView.subviews)
{
if ([subview isKindOfClass:[UIImageView class]])
{
dot = (UIImageView*)subview;
break;
}
}
if (dot == nil)
{
dot = [[UIImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, dotView.frame.size.width, dotView.frame.size.height)];
[dotView addSubview:dot];
}
if (i == self.currentPage)
{
if(self.activeImage)
dot.image = activeImage;
}
else
{
if (self.inactiveImage)
dot.image = inactiveImage;
}
}
maybe dot isn't kind of UIImageView, so try like this
UIImageView* dot = [self.subviews objectAtIndex:i];
if ([dot isKindOfClass:[UIImageView class]]) {
if (i == self.currentPage)
dot.image = activeImage;
else
dot.image = inactiveImage;
}
I've got a bit cleaner solution:
for (int i = 0; i < [self.subviews count]; i++) {
UIView *dotView = [self.subviews objectAtIndex:i];
if ([dotView isKindOfClass:[UIImageView class]]) {
UIImageView* dot = (UIImageView*)dotView;
dot.frame = CGRectMake(dot.frame.origin.x, dot.frame.origin.y, _activeImage.size.width, _activeImage.size.height);
if (i == self.currentPage)
dot.image = _activeImage;
else
dot.image = _inactiveImage;
}
else {
dotView.frame = CGRectMake(dotView.frame.origin.x, dotView.frame.origin.y, _activeImage.size.width, _activeImage.size.height);
if (i == self.currentPage)
[dotView setBackgroundColor:[UIColor colorWithPatternImage:_activeImage]];
else
[dotView setBackgroundColor:[UIColor colorWithPatternImage:_inactiveImage]];
}
}
The idea is instead of adding subview to UIView for iOS7 just set UIView background image.
Just a little refactor for devgeek's solution to make it a bit more compact
for (int i = 0; i < [self.subviews count]; i++) {
UIImage *customDotImage = (i == self.currentPage) ? _activeDot : _inactiveDot;
UIView *dotView = [self.subviews objectAtIndex:i];
dotView.frame = CGRectMake(dotView.frame.origin.x, dotView.frame.origin.y, customDotImage.size.width, customDotImage.size.height);
if ([dotView isKindOfClass:[UIImageView class]]) { // in iOS 6, UIPageControl contains UIImageViews
((UIImageView *)dotView).image = customDotImage;
}
else { // in iOS 7, UIPageControl contains normal UIViews
dotView.backgroundColor = [UIColor colorWithPatternImage:customDotImage];
}
}
Just override layoutSubviews in your subclass of UIPageControl
- (void) layoutSubviews
{
[super layoutSubviews];
for (UIView* dot in self.subviews)
{
CGRect f = dot.frame;
//sets all the dots to be 5x5
f.size = CGSizeMake(5, 5);
//need to reposition vertically as the dots get repositioned when selected
f.origin.y = CGRectGetMidY(self.bounds) - CGRectGetHeight(f)/2;
dot.frame = f;
//update the cornerRadius to be sure that they are perfect circles
dot.layer.cornerRadius = CGRectGetWidth(f)/2;
}
}

Removing tagged object from ScrollView

I have a lot of images in a scrollView, all the same, one after another, and a delete button as a subview of each. I assign a tag in this way
1) img.tag = i;
2) int z;
z = i+1;
buttonDelete.tag = z;
and i is a for loop. when I press the button this code is executed:
-(IBAction)deleteMessage:(id)sender
{
UIButton *button = (UIButton*) sender;
NSLog(#"Clicked button %d", button.tag); 
UIImageView *image = (UIImageView*) sender;
NSLog(#"Clicked button %d", image.tag);
int n;
n = button.tag;
for (UIImageView *img in imageArray)
{
if (img.tag == n)
{
[img removeFromSuperview];
NSLog(#"The value of integer num is %i", img.tag);
NSLog(#"The value of integer num is %i", n);
}
}
}
According to the NSLog, the first four buttons correspond exactly to their tag, and to the image tag. The corresponding image is deleted. These four images all fit in the fist view of the scroll view. If there are more images though, and I need to scroll down, the tags don't increase anymore. Instead they restart from tag 1. So 1,2,3,4,1,2,3,4... and 1,2,3,4 can be seen in the same "page" of the scroll view. How can this be??
EDIT:
I also tried this:
-(IBAction)deleteMessage:(id)sender
{
UIButton *button = (UIButton*) sender;
NSLog(#"Clicked button %d", button.tag);
UIImageView *image = (UIImageView*) sender;
NSLog(#"Clicked button %d", image.tag);
int n;
n = button.tag;
for (UIImageView *img in imageArray)
{
if ([img isKindOfClass:[UIImageView class]] && img.tag == n) {
[img removeFromSuperview];
}
}
}
but gives the same result

cocoa:Multiple buttons to set the picture,Tab effect

There are several buttons,Click on one of,Change the picture of this button,Other button to set another picture。The following code where there is an error?
NSButton *button = (NSButton *)sender;
NSInteger tag = button.tag;
[button setImage:[NSImage imageNamed:#"menuBtnHover.png"]];
for (int i = 5; i <= 8; i++) {
if (tag != i) {
button =[(NSButton *)[self contentView] viewWithTag:i];
[button setImage:[NSImage imageNamed:#"menuBtn.png"]];
}
}
Add test,button = null
NSLog(#"button tag: %ld %d %#", tag,i ,button);
use this code
NSButton *button = (NSButton *)sender;
NSInteger tag = button.tag;
[button setImage:[NSImage imageNamed:#"menuBtnHover.png"]];
for (int i = 5; i <= 8; i++) {
if (tag != i) { button =[(NSButton *)[self contentView] viewWithTag:i];
if(button)[button setImage:[NSImage imageNamed:#"menuBtn.png"]];}
}

UISegmentedControl with custom color: separator line bug

Its easy change the color of UISegmentedControl. I found various solution like this, this site and the best this solution. But none was what I want.
I tried create a simple thing and it work very easy, this was my code: (I am using the iOS 4.2, not the 5.0 and xcode 4.0.2)
id segment[3];
UISegmentedControl *segmentedControl;
- (id)init
{
NSArray *itens = [NSArray arrayWithObjects: #"Option 1", #"Option 2", #"Option 3", nil];
segmentedControl = [[UISegmentedControl alloc] initWithItems:itens];
[segmentedControl setFrame:CGRectMake(0, 0, 500, 30)];
[segmentedControl setSegmentedControlStyle:UISegmentedControlStyleBar];
[segmentedControl addTarget:self
action:#selector(segmentedControl:)
forControlEvents:UIControlEventAllEvents];
switch (type) {
case type1: [segmentedControl setSelectedSegmentIndex:0]; break;
case type2: [segmentedControl setSelectedSegmentIndex:1]; break;
case type3: [segmentedControl setSelectedSegmentIndex:2]; break;
}
for (int i=0; i<3; i++) {
//The most important trick to work, have to retain the subviews
segment[i] = [[[segmentedControl subviews] objectAtIndex:i] retain];
}
[self changeColor];
[self addSubview:segmentedControl];
return self;
}
- (void)segmentedControl:(id)sender
{
//do some thing
[self changeColor];
}
- (void)changeColor{
for (int i=0; i<3; i++) {
[segment[i] setTintColor:[UIColor lightGrayColor]];
}
int select = segmentedControl.selectedSegmentIndex;
[segment[select] setTintColor:[UIColor blueColor]];
}
So it create this:
Very good, then I click in Option 2
Wow, this is exacly what I want, so click in Option 3
Now the problem, this stupid blue line (marked in red square) between Option 1 and Option 2. If I click in Option 1 again, I will have:
Than the blue line appear again. This mean that every left side on old clicked segment (but not with the first) will have this blue line. If I go from right to left it not happens.
I have no idea how to solve this. How can I access this line and change your color? Or I will have to use other codes. Maybe they will have the same problem...
I Think there is a lot easier solution.
Just clean the pointers..
for (int i=0; i<[self.segmentedControll.subviews count]; i++)
{
[[self.segmentedControll.subviews objectAtIndex:i] setTintColor:nil];
if (![[self.segmentedControll.subviews objectAtIndex:i]isSelected])
{
UIColor *tintcolor=[UIColor blackColor];
[[self.segmentedControll.subviews objectAtIndex:i] setTintColor:tintcolor];
}
else
{
UIColor *tintcolor=[UIColor blueColor];
[[self.segmentedControll.subviews objectAtIndex:i] setTintColor:tintcolor];
}
}
Wow... When we write were in stackoverflow, we can calm down and think better. I write the answer in my ow question:
If I go from right to left it not happens.
This is the solution! What I have to do? Simulate this.
BOOL inside = FALSE;
- (void)changeColor{
int old = segmentedControl.selectedSegmentIndex;
for (int i=0; i<3; i++) {
[segment[i] setTintColor:[UIColor lightGrayColor]];
}
/**/inside = TRUE;
/**/for (int i=3; i>0; i--) {
/**/ //When I do this, it call "segmentedControl:"
/**/ [segmentedControl setSelectedSegmentIndex:i];
/**/}
/**/int select = old;
[segment[select] setTintColor:[UIColor blueColor]];
[segmentedControl setSelectedSegmentIndex:select];
/**/inside = FALSE;
}
- (void)segmentedControl:(id)sender
{
/**/if (inside==TRUE) return; //Ignore this calls.
//do some thing
[self changeColor];
}