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
Caleb Kleveter
Treehouse Moderator 37,862 PointsUIImageViews won't animate in an image based animation. [Solved]
I have 8 UIImageViews that were created in the storyboard that I am trying to animate with an image based animation.
viewController.h
#import <UIKit/UIKit.h>
@class RandomImages;
@interface ViewController : UIViewController
// Outlets foe the dice
@property (weak, nonatomic) IBOutlet UIImageView *dieImage0;
@property (weak, nonatomic) IBOutlet UIImageView *dieImage1;
@property (weak, nonatomic) IBOutlet UIImageView *dieImage2;
@property (weak, nonatomic) IBOutlet UIImageView *dieImage3;
@property (weak, nonatomic) IBOutlet UIImageView *dieImage4;
@property (weak, nonatomic) IBOutlet UIImageView *dieImage5;
@property (weak, nonatomic) IBOutlet UIImageView *dieImage6;
@property (weak, nonatomic) IBOutlet UIImageView *dieImage7;
@property (weak, nonatomic) IBOutlet UIButton *MenuButton;
@property (weak, nonatomic) IBOutlet UIButton *rollTargetButton;
@property (strong, nonatomic) RandomImages *randomImages;
@property (strong, nonatomic) NSArray *diceOutletArray;
- (void) rollDice;
@end
viewController.m
import "ViewController.h"
#import "RandomImages.h"
@interface ViewController ()
@end
@implementation ViewController
@synthesize dieImage0;
@synthesize dieImage1;
@synthesize dieImage2;
@synthesize dieImage3;
@synthesize dieImage4;
@synthesize dieImage5;
@synthesize dieImage6;
@synthesize dieImage7;
@synthesize diceOutletArray;
@synthesize rollTargetButton;
- (void)viewDidLoad {
[super viewDidLoad];
self.randomImages = [[RandomImages alloc] init];
self.rollTargetButton.hidden = YES;
self.diceOutletArray = [[NSArray alloc] initWithObjects:self.dieImage0, self.dieImage1, self.dieImage2, self.dieImage3, self.dieImage4, self.dieImage5, self.dieImage6, self.dieImage7, nil];
// Animation for rolling dice
for (UIImageView *numberImage in self.diceOutletArray) {
numberImage.animationImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"dicy-die5"],
[UIImage imageNamed:@"dicy-die6"],
[UIImage imageNamed:@"dicy-die1"],
[UIImage imageNamed:@"dicy-die4"],
[UIImage imageNamed:@"dicy-die3"],
[UIImage imageNamed:@"dicy-die5"],
[UIImage imageNamed:@"dicy-die2"],
[UIImage imageNamed:@"dicy-die1"],
[UIImage imageNamed:@"dicy-die6"],
[UIImage imageNamed:@"dicy-die3"],
[UIImage imageNamed:@"dicy-die5"],
[UIImage imageNamed:@"dicy-die2"],
[UIImage imageNamed:@"dicy-die3"], nil];
numberImage.animationDuration = 1.0f;
numberImage.animationRepeatCount = 1;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void) rollDice{
self.diceOutletArray = [[NSArray alloc] initWithObjects:self.dieImage0, self.dieImage1, self.dieImage2, self.dieImage3, self.dieImage4, self.dieImage5, self.dieImage6, self.dieImage7, nil];
// Randomly set the image of the dice
for (UIImageView *numberImage in self.diceOutletArray) {
// async and sync
dispatch_sync(dispatch_get_main_queue(), ^{
numberImage.image = [self.randomImages randomNumber];
[numberImage startAnimating];
if ([numberImage isAnimating]) {
NSLog(@"Yep, I'm animating");
}
});
}
}
/* Motion functions *****************************************************************************************/
- (void) motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
}
- (void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake) {
[self rollDice];
NSLog(@"There was a bump!: Line 85");
}
NSLog(@"Motion Ended: Line 87");
}
- (void) motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
}
/* Roll Button **********************************************************************************************/
- (IBAction)rollDiceButton {
[self rollDice];
NSLog(@"Ouch! Somebody poked me!: Line 97");
}
/* Segues **************************************************************************************************/
@end
For some reason the animation doesn't work.
Note: I have done this in Swift, and I do have another class for the dice image randomization, if you don't find a bug in here then I can give you that code.
14 Answers
Gabe Nadel
Treehouse Guest TeacherI believe you need to call:
[dieImages startAnimating];
To actually start the animation. I'd place that at the end of your For-In loop.
Caleb Kleveter
Treehouse Moderator 37,862 PointsI get the error "use of undeclared identifier 'dieImages'". I have done this in Swift before, and this is what the code for the animation was:
override func viewDidLoad() {
super.viewDidLoad()
let dieImages = [dieImage0, dieImage1, dieImage2, dieImage3, dieImage4, dieImage5, dieImage6, dieImage7]
for die in dieImages {
die.animationImages = [
UIImage(named: "dicey-die2")!,
UIImage(named: "dicey-die6")!,
UIImage(named: "dicey-die1")!,
UIImage(named: "dicey-die4")!,
UIImage(named: "dicey-die3")!,
UIImage(named: "dicey-die5")!,
UIImage(named: "dicey-die3")!,
UIImage(named: "dicey-die1")!,
UIImage(named: "dicey-die6")!,
UIImage(named: "dicey-die3")!,
UIImage(named: "dicey-die5")!,
UIImage(named: "dicey-die2")!,
UIImage(named: "dicey-die3")!
]
die.animationRepeatCount = 1
die.animationDuration = 1.0
}
}
* Motion functions *****************************************************************************************/
override func motionBegan(motion: UIEventSubtype, withEvent event: UIEvent) {
}
override func motionEnded(motion: UIEventSubtype, withEvent event: UIEvent) {
let dieImages = [dieImage0, dieImage1, dieImage2, dieImage3, dieImage4, dieImage5, dieImage6, dieImage7]
for dieImage in dieImages {
dieImage.image = randomImages.randomDice()
dieImage.startAnimating()
}
}
override func motionCancelled(motion: UIEventSubtype, withEvent event: UIEvent) {
}
One person gave the comment in my SO post "Try making sure it's run on the main thread. Dispatch_async get_main_que"
Caleb Kleveter
Treehouse Moderator 37,862 PointsI put this if block in my for loop and it printed to the console 8 times:
if ([numberImage isAnimating]) {
NSLog(@"Yep, I'm animating");
}
Gabe Nadel
Treehouse Guest TeacherYes, like I said in my original post, did you insert the line shown below? You need to actually start the animation.
I think your for-in loop should read:
for (UIImageView *numberImage in self.diceOutletArray) {
numberImage.animationImages = [[NSArray alloc] initWithObjects:
[UIImage imageNamed:@"dicy-die5"],
[UIImage imageNamed:@"dicy-die6"],
[UIImage imageNamed:@"dicy-die1"],
[UIImage imageNamed:@"dicy-die4"],
[UIImage imageNamed:@"dicy-die3"],
[UIImage imageNamed:@"dicy-die5"],
[UIImage imageNamed:@"dicy-die2"],
[UIImage imageNamed:@"dicy-die1"],
[UIImage imageNamed:@"dicy-die6"],
[UIImage imageNamed:@"dicy-die3"],
[UIImage imageNamed:@"dicy-die5"],
[UIImage imageNamed:@"dicy-die2"],
[UIImage imageNamed:@"dicy-die3"], nil];
numberImage.animationDuration = 1.0f;
numberImage.animationRepeatCount = 1;
[numberImage startAnimating]; //THIS IS THE LINE TO ADD
}
Caleb Kleveter
Treehouse Moderator 37,862 PointsAs I suspected, the animation doesn't work, and neither the random images. I am trying to base it a little off this video: https://teamtreehouse.com/library/build-a-simple-iphone-app/animate-this/image-based-animation-2
Gabe Nadel
Treehouse Guest TeacherSo, did my above solution not work, or you didn't try it?
Caleb Kleveter
Treehouse Moderator 37,862 PointsI tried adding [numberImage startAnimating]; were you wanted me to and that didn't to do it, so I tried getting rid of it in the rollDice method, and leaving it in the for-loop and that didn't work either. I did this test again after I remembered I changed dispatch_sync to dispatch_async, and changed it back, random images still show up, just no animation. Does it have to do with the UIImageViews being created in the storyboard?
Gabe Nadel
Treehouse Guest TeacherAh, well you want UI updates and Animations to be done from the main thread. So I wouldn't trigger that from dispatch_synch...unless you later force it back to the main thread. You can read up on this issue in more detail in places like stackoverflow.
Caleb Kleveter
Treehouse Moderator 37,862 PointsWhat does this code mean?
dispatch_async(dispatch_get_main_queue(), ^{});
Gabe Nadel
Treehouse Guest TeacherAh, yes, sorry, I didn't see that line. Guess you were one step ahead of me.
I think this line might be overriding your animationImages:
dispatch_sync(dispatch_get_main_queue(), ^{
numberImage.image = [self.randomImages randomNumber]; /// try removing this line and see what happens...
[numberImage startAnimating];
Caleb Kleveter
Treehouse Moderator 37,862 PointsAfter commenting that line out nothing happens. No animation, no random image.
Gabe Nadel
Treehouse Guest Teacherand if you place a breakpoint there, what are the values for:
numberImage.image
and
numberImage.animationImages
Caleb Kleveter
Treehouse Moderator 37,862 PointsDo you this?
self = (ViewController *) 0x7fce72c70f40
numberImage = (UIImageView *) 0x7fce72c7b220
Gabe Nadel
Treehouse Guest Teachersorry, I don't understand what you are asking.
Caleb Kleveter
Treehouse Moderator 37,862 PointsWhat do you mean by the values of numberImage.image and numberImage.animationImages?
Gabe Nadel
Treehouse Guest TeacherThe instance numberImage has the property image and animationImage. If you inspect the instance at that point in the code, what are the values for those? (let's make sure those values are what we think they are)
Caleb Kleveter
Treehouse Moderator 37,862 PointsAre these the values?
self = (ViewController *) 0x7fe8285d7390
numberImage = (UIImageView *) 0x7fe8285e6660
Gabe Nadel
Treehouse Guest TeacherThose are the memory addresses, you want the values found at those addresses (This all relates to pointers, etc...)
There are a few ways to get the info you want, but here are some links you may find helpful:
https://developer.apple.com/library/ios/recipes/xcode_help-debugger/articles/viewing_memory.html
Caleb Kleveter
Treehouse Moderator 37,862 PointsWhat do I do with this information?
Gabe Nadel
Treehouse Guest TeacherI'd review it and try it out in your project, you might also want to re-watch some of the videos on pointers and memory. Aside form this project, you need to be comfortable at inspecting VALUES of your variables while debugging - you can really never get "too good" at debugging.
Caleb Kleveter
Treehouse Moderator 37,862 PointsI did notice this:
numberImage = (UIImageView *) 0x7f946847e950
UIView
_storage = (UIImage *) 0x7f946847fde0
_templateSettingsAreInvalid = (bool) false
_edgeInsetsForEffectsAreValid = (bool) false
__animatesContents = (bool) false <===============
What does that mean?
Caleb Kleveter
Treehouse Moderator 37,862 PointsI'm afraid my head is going to come off it is spinning so fast. I do have a couple things to say not concerning this topic.
In the Swift project files for the Stickies app there is an error on line 16, in Sticky.swift
Cannot invoke 'animationWithDuration' with an argument of list type '(Double, delay: Double, options: NSArray, animations: () -> Void, completion: nil)'
@IBAction func mute() {
UIView.animateWithDuration(1.0, delay: 0.0, options: [], animations: <=== error
{ () -> Void in
self.alpha = 0.25
}, completion: nil)
}
I posted a question on the forum, and Brayden Kness said to replace options: [] with options: UIViewAnimationOptions.CurveLinear
Also, how do I change the alpha value of an image on a button when the button is pressed? In reference to this question on Stack Overflow.
Caleb Kleveter
Treehouse Moderator 37,862 PointsI finally got my answer on this SO post. problem solved!
Caleb Kleveter
Treehouse Moderator 37,862 PointsCaleb Kleveter
Treehouse Moderator 37,862 PointsI made some changes to my
viewController.min the animation for loop, and the rollDice method.