I subclassed UIView in order to draw a line that changes position every second. I am using NSTimer to call setNeedsDisplay in order to update the view but the results are not correct. It is drawing old and new lines. Here is my LineView.h/m code:
LineView.h:
#interface LineView : UIView
#property(nonatomic, assign) int length;
#end
LineView.m:
#import "LineView.h"
#implementation LineView
- (void)setLength:(int)length {
_length = length;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
UIBezierPath *line = [UIBezierPath bezierPath];
[line moveToPoint:CGPointMake(10, 10)];
[line addLineToPoint:CGPointMake(100, 100+_length)];
line.lineWidth = 10;
[[UIColor blueColor] setStroke];
[line stroke];
}
#end
In my ViewController.m file, in viewDidLoad, I init lineView and start the timer:
- (void)viewDidLoad {
[super viewDidLoad];
_length = 100;
_lineView = [[LineView alloc]initWithFrame:self.view.bounds];
_lineView.length = _length;
[self.view addSubview:_lineView];
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:true];
}
- (void)updateTime:(NSTimer*)timer {
_length += 20;
self.lineView.length = _length;
}
I want to do this all programmatically and not use storyboards or xibs. If I subclass the view in storyboard and create an outlet to it, then the view is updated correctly but I want to avoid touching the storyboard.
_lineView.opaque = NO;
_lineView.backgroundColor = [UIColor blackColor];
try this. I have run your project with this it doing good.
Related
This question is about the exercise 6.9 of iOS Programming 4th Edition.
I have a class that can draw concentric circles and respond to touches by changing its color randomly.
Here is the implementation of the view:
#implementation LTHypnosisView
- (instancetype) initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self){
self.backgroundColor = [UIColor clearColor];
self.circleColor = [UIColor lightGrayColor];
}
return self;
}
- (void)drawRect:(CGRect)rect {
//Draw the circles
}
- (void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
float red = (arc4random() % 100) /100.0;
float green = (arc4random() % 100) /100.0;
float blue = (arc4random() % 100) /100.0;
UIColor *randomColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
self.circleColor = randomColor;
}
- (void) setCircleColor:(UIColor *)circleColor{
_circleColor = circleColor;
[self setNeedsDisplay];
}
#end
Here is the implementation of the viewController:
#implementation LTHypnosisViewController
- (void) viewDidLoad{
CGRect screenRect = self.view.bounds;
LTHypnosisView *mainView = [[LTHypnosisView alloc] initWithFrame:screenRect];
[self addSubview:mainView]
NSArray *items = #[#"Red",#"Green",#"Blue"];
UISegmentedControl *segControl = [[UISegmentedControl alloc] initWithItems:items];
[segControl addTarget:self
action:#selector(change:)
forControlEvents:UIControlEventValueChanged];
segControl.frame = CGRectMake(10, 50, self.view.bounds.size.width-20, 60);
segControl.selectedSegmentIndex = 0;
segControl.backgroundColor = [UIColor whiteColor];
[self.view addSubview:segControl];
}
- (void) change:(UISegmentedControl*)sender{
switch (sender.selectedSegmentIndex) {
//How should I write here??
}
}
#end
I want to change the color of the concentric circles with the UISegmentedControl. Consequently I need a method within the viewController to change the _circleColor property of the LTHypnosisView instance. How can I do that?
A simple way, I'd make LTHypnosisView *mainView a property of the view controller, make setCircleColor public, and then in change: method call [self.mainView setCircleColor:myColor];
You could also do something more involved, like define a protocol on LTHypnosisView and set the view controller as the datasource. Whenever the change: method is called, call something like [mainView updateColor] and within updateColor have it read the color from it's datasource.
I would like to move red circle (as shown in following image) slowly (may be with animation) when user swipes the app intro (PageViewController). I also want to add some animations so I'm trying to use IFTTT/JazzHands framework. But it's difficult for me to understand currently. Is there any easy way to use animation in PageViewController? Or are there any tutorials that uses IFTTT/JazzHands framework? Could anybody help me, please?
Try this if its is ok vote for me
#interface homeViewController ()<UIScrollViewDelegate>
#property (weak, nonatomic) IBOutlet UIScrollView *scrollViewSlider;
#end
#implementation homeViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationController.navigationBarHidden=true;
[NSTimer scheduledTimerWithTimeInterval:4 target:self
selector:#selector(scrollingTimer) userInfo:nil repeats:YES];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
-(void)viewDidLayoutSubviews
{
UIImage *imageOne = [UIImage imageNamed:#"download.jpeg"];
UIImage *imageTwo = [UIImage imageNamed:#"download2.jpeg"];
UIImage *imageThree = [UIImage imageNamed:#"download3.jpeg"];
UIImage *imageFour = [UIImage imageNamed:#"download4.jpeg"];
NSArray *imageArray = [NSArray arrayWithObjects:imageOne,
imageTwo, imageThree, imageFour, nil];
for (int i = 0; i <= 3; i++) {
UIImageView *imgView = [[UIImageView alloc]init];
imgView.contentMode = UIViewContentModeScaleToFill;
imgView.alpha = 0.5f;
imgView.frame = CGRectMake(i * self.scrollViewSlider.bounds.size.width,
0, self.scrollViewSlider.bounds.size.width,
self.scrollViewSlider.bounds.size.height);
[imgView setImage:imageArray[i]];
[self.scrollViewSlider addSubview:imgView];
self.scrollViewSlider.pagingEnabled = true;
[self.scrollViewSlider setContentSize:CGSizeMake(imageArray.count *
self.scrollViewSlider.bounds.size.width,
self.scrollViewSlider.bounds.size.height-20)];
}
}
-(void) scrollingTimer
{
CGPoint frame = self.scrollViewSlider.contentOffset;
[UIView animateWithDuration:3.0f animations:^(void) {
if (frame.x != 3 * self.scrollViewSlider.frame.size.width)
[self.scrollViewSlider setContentOffset:CGPointMake(frame.x +
self.scrollViewSlider.frame.size.width, 0)];
else
[self.scrollViewSlider setContentOffset:CGPointMake(0, 0)];
}];
}
Try this code without any Third party Class
just add QuartzCore framwork from library
#import <QuartzCore/QuartzCore.h>
- (CAAnimation*)movedown;
{
CABasicAnimation *animation = [CABasicAnimation animation];
animation.keyPath = #"position.y";
animation.fromValue = #600;
animation.toValue = #50;
animation.duration = 0.25;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[subView.layer addAnimation:animation forKey:#"basic"];
subView.layer.position = CGPointMake(0,-20);
return animation;
}
pls replace your animation view in-place of subview.
I have couple of UIButtons on the screen. If a pinch gesture occurs, I want to decrease the size of the buttons (Like a zoom-out effect) and add more buttons. How would I implement it?
I am typing this directly on StackOverflow, so there may be typos.
These features are left as an exercise for the OP:
Cumulatively scaling down with successive pinches. You must have another private property to hold the current scale value.
Adding new buttons after the zooming out effect.
Code:
#interface MyViewController : UIViewController
#property(nonatomic, strong) NSMutableArray* buttons;
- (void)pinched:(UIPinchGestureRecognizer*)gesture;
#end
#implementation MyViewController
- (void)loadView {
[super loadView];
self.buttons = [NSMutableArray array];
for (NSUInteger i = 0; i < 3; i++) {
UIButton* button = [[UIButton alloc] initWithFrame:CGRectMake(
0.0f,
(44.0f + 10.0f) * (CGFloat)i,
100.0f,
44.0f
)];
button.backgroundColor = [UIColor blueColor];
[self.view addSubview:button];
[self.buttons addObject:button];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
UIPinchGestureRecognizer* pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinched:)];
[self.view addGestureRecognizer:pinch];
}
- (void)pinched:(UIPinchGestureRecognizer*)gesture {
if (gesture.scale > 1.0) {
return;
}
for (UIButton* button in self.buttons) {
[UIView
animateWithDuration:1.0
animations:^void() {
button.transform = CGAffineTransformMakeScale(0.5, 0.5);
}
];
}
}
#end
I've been experiencing some difficulties with particle effects. Originally I posted a question about how the particle effects in my app were different when on an ios6 device.
Particle system looks different on iOS 6 and ios7
I Originally designed the app on an ios7 device and got the particles looking like I wanted, but on the ios6 device the particles were smaller and displaced.
I was told it was problem between ios6 and ios7 and that changing the media timing could fix it.
Ive tried everything, but nothing has worked.
Eventually I tried just creating a separate app and pasted in the code from this tutorial - http://weblog.invasivecode.com/post/45058779586/caemitterlayer-and-the-ios-particle-system-lets in the view did load. The particles work as they should, but when I put the same code into my current apps viewDidLoad. The particles were all over the place and not doing what they should be.
I'm wandering if there is something in my current app that Im missing, that is upsetting the particles. Can anyone suggest things to look for?
Originally the particle effects were subclassed and being called after adding a subview to my main view.
Here is my view controller .h code (I've taken out some irrelevant control object properties and outlets)
#interface HHViewController : UIViewController < HHScoreViewdelegate>
{
IBOutlet UIButton* btnStart;
IBOutlet UIButton* btnStop;
IBOutlet UIButton* btnMore;
IBOutlet UIButton* btnHelp;
IBOutlet UIButton* btnTessilaCoil;
IBOutlet UIImageView* imgAnimatedTessila;
IBOutlet UIImageView* imgBubble;
IBOutlet UIImageView* imgSteam;
IBOutlet UIImageView* imgMachineLightsTop;
IBOutlet UIImageView* imgBackground;
NSTimer* StopSignTimer;
NSTimer* timer;
NSTimer* lightMachineTimer;
NSTimer* ComputerLightsTimer;
CGFloat AnimationDelay;
AVAudioPlayer* audioPlayer;
AVAudioPlayer* audioPlayer2; //Used for game end audio, so that it doesnt interupt last letter/number audio
int pageValue;
IBOutlet UIButton* btnSetting;
IBOutlet UIButton* btnIAP;
IBOutlet UIButton* btnNext;
IBOutlet UIButton* btnForward;
IBOutlet UIImageView* imgLightMachine;
IBOutlet UIImageView* imgComputerLights;
NSString* strletterName;
HHScoreView * scoreSelection;
More * MorePanelView;
InAppPurchase * InAppPurchaseView;
NSMutableArray* ButtonBackgroundImages;
NSMutableArray* AlphabetBubbles;
NSMutableArray* SavedBubblePositions;
NSTimer* bubbleBlinkingTimer;
int wrongbubbleTapCount;
IBOutlet UIImageView* imgAlphabetDisplay;
IBOutlet UILabel* lblNextOneToPop;
// Code from Particle Tutorial
CAEmitterLayer *_myEmitter;
CAEmitterCell *_myCell;
// End code form Particle Tutorial
}
// Code from Particle Tutorial
#property(nonatomic, retain) CAEmitterLayer *_myEmitter;
#property(nonatomic, retain) CAEmitterCell *_myCell;
// End code form Particle Tutorial
#property(nonatomic,strong) UILabel* lblNextOneToPop;
#property(nonatomic,strong) NSTimer* SteamTimer;
#property(nonatomic,strong) NSTimer* StopSignTimer;
#property(nonatomic,strong) NSTimer* timer;
#property(nonatomic,strong) NSTimer* lightMachineTimer;
#property(nonatomic,strong) NSTimer* ComputerLightsTimer;
#property(nonatomic,retain)IBOutlet UIButton* btnStart;
#property(nonatomic,retain)IBOutlet UIButton* btnStop;
#property(nonatomic,retain)IBOutlet UIButton* btnMore;
#property(nonatomic,retain)IBOutlet UIButton* btnHelp;
#property(nonatomic,retain)IBOutlet UIButton* btnSetting;
#property(nonatomic,retain)IBOutlet UIButton* btnTessilaCoil;
#property(nonatomic,retain)IBOutlet UIImageView* imgAnimatedTessila;
#property(nonatomic,retain)IBOutlet UIImageView* imgSteam;
#property(nonatomic,retain)IBOutlet UIImageView* imgMachineLightsTop;
#property(nonatomic,retain)IBOutlet UIImageView* imgBackground;
#property(nonatomic,retain)IBOutlet UIScrollView* scScrollView;
#property(nonatomic,retain)IBOutlet IBOutlet UIButton* btnNext;
#property(nonatomic,retain)IBOutlet IBOutlet UIButton* btnForward;
#property(nonatomic,retain)IBOutlet UIImageView* imgLightMachine;
#property(nonatomic,retain)IBOutlet UIImageView* imgComputerLights;
#property(nonatomic,retain)NSString* strletterName;
#property(assign)int allLettersEventCount;
#property(nonatomic,retain) NSArray* ButtonBackgroundImages;
#property Boolean StopButtonClicked;
#property Boolean BubbleAOnscreen;
#property (nonatomic,assign) BOOL cancelAll;
#property int pageValue;
#property int positionRotation;
-(IBAction)tapPiece:(UITapGestureRecognizer *)recognizer;
-(IBAction)actionStartSign:(id)sender;
-(IBAction)actionStopSign:(id)sender;
-(IBAction)actionMoreSign:(id)sender;
-(IBAction)actionHelpSign:(id)sender;
-(IBAction)actionTessilaCoil:(id)sender;
-(IBAction)actionbtnHelp:(id)sender;
-(IBAction)actionbtnSetting:(id)sender;
-(IBAction)actionbtnIAP:(id)sender;
+(HHViewController*)sharedManager;
- (IBAction)purchaseItem:(id)sender;
#property (strong, nonatomic) InAppPurchase *purchaseController;
#end
Here is the code from my viewcontroller .m where I added the code from the tutorial.
#interface HHViewController ()
{
}
#end
#implementation HHViewController
static int OrderingSequence = 0;
#synthesize _myEmitter, _myCell;
/*
TeslarGlowEffect* ShowGlow;
SteamEffect* ShowSteam;
BubbleBurst* PopBubble;
*/
//TeslarTimerSparks* TeslarTimer;
- (void)viewDidLoad
{
[super viewDidLoad];
CFTimeInterval currentTime = [self.view.layer convertTime:CACurrentMediaTime() fromLayer:nil];
NSLog(#"Current media Timing = %f", currentTime);
// Code from tutorial
CAEmitterLayer *emitterLayer = [CAEmitterLayer layer]; // 1
emitterLayer.emitterPosition = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.origin.y); // 2
emitterLayer.emitterZPosition = 10; // 3
emitterLayer.emitterSize = CGSizeMake(self.view.bounds.size.width, 0); // 4
emitterLayer.emitterShape = kCAEmitterLayerSphere; // 5
CAEmitterCell *emitterCell = [CAEmitterCell emitterCell]; // 6
emitterCell.scale = 0.1; // 7
emitterCell.scaleRange = 0.2; // 8
emitterCell.emissionRange = (CGFloat)M_PI_2; // 9
emitterCell.lifetime = 5.0; // 10
emitterCell.birthRate = 10; // 11
emitterCell.velocity = 200; // 12
emitterCell.velocityRange = 50; // 13
emitterCell.yAcceleration = 250; // 14
emitterCell.contents = (id)[[UIImage imageNamed:#"Steam1.png"] CGImage]; // 15
emitterLayer.emitterCells = [NSArray arrayWithObject:emitterCell]; // 16
[self.view.layer addSublayer:emitterLayer]; // 17
//end code from tutorial
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appWillEnterForegroundNotification:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(appWillEnterBackgroundNotification:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[btnStart addTarget:self action:#selector(actionStartSign:) forControlEvents:UIControlEventTouchUpInside];
//NSLog(#"OrderingSequence = %d",OrderingSequence );
imgAnimatedTessila.image = [UIImage imageNamed:KTESSILAIMAGE];
self.alphebetindex = 0;
wrongbubbleTapCount = 0;
//// Load a bunch of arrays used in the game.
[btnHelp addTarget:self action:#selector(actionbtnHelp:) forControlEvents:UIControlEventTouchUpInside];
[btnSetting addTarget:self action:#selector(actionbtnSetting:) forControlEvents:UIControlEventTouchUpInside];
NSString* strFirstTimeloaded = [[NSUserDefaults standardUserDefaults]valueForKey:#"FirstTime"];
if(strFirstTimeloaded == nil)
{
// Show preference page if first time used.
[[NSUserDefaults standardUserDefaults]setValue:#"English" forKey:#"Language"];
LanguagesSelectView* selection = [[LanguagesSelectView alloc]initWithFrame:CGRectMake(0, 0, 1024, 748)];
[self.view addSubview:selection];
[[NSUserDefaults standardUserDefaults]setValue:#"FirstTime" forKey:#"FirstTime"];
}
positionRotation = 0;
self.strletterName = #"29";
self.allLettersEventCount = 0;
[[NSUserDefaults standardUserDefaults] setValue:#"One" forKey:#"Mode"];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(enableSetting) name:#"EnableSetting" object:nil];
//[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(LetterTapped:) name:#"LetterTapped" object:nil];
btnStop.hidden = YES;
btnNext.hidden = YES;
btnForward.hidden = YES;
[self addGestureRecognizersToView];
//Create timer for release of steam from bubble machine
SteamTimer = [NSTimer scheduledTimerWithTimeInterval:5.2 target:self selector:#selector(ShowSteamEffect) userInfo:nil repeats:YES];
//Set Font for lblNextOneToPop
[lblNextOneToPop setFont:[UIFont fontWithName:#"SF Slapstick Comic" size:110]];
lblNextOneToPop.hidden = YES;
}
Here is one of my particle effects that was working on my ios7 iPad, but on the ios6 iPad, the effect looked totally different.
It was after long hrs trying to figure out why the ios7 and ios6 looked different that I tried the exercise of putting the tutorial code into a new app and then it into my own app. In my app the particles are totally different, but as they should be in the new app.
With respect to #matt's comments below. I know there must be something going on with my app, but I can't see it. I've looked all over the web and all through my code and I think I'm missing something.
All I want are three particles effects that appear at specific locations regardless of iOS version. One of them on user touch. The effect below is just one of them. I've tried the CAmediaTiming thing, but that didn't work.
SteamEffect.h
#import <UIKit/UIKit.h>
#interface SteamEffect : UIView
#end
The steamEffect.m looks like this.
#import "SteamEffect.h"
#implementation SteamEffect
{
CAEmitterLayer* SteamEmitter;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
SteamEmitter = (CAEmitterLayer*) self.layer;
//SteamEmitter.emitterPosition= CGPointMake(0, 0);
//SteamEmitter.emitterSize = CGSizeMake(10,10);
CAEmitterCell* Steam = [CAEmitterCell emitterCell];
Steam.birthRate = 50.0f;
Steam.spin = .6f;
Steam.lifetime = 1.7f;
Steam.alphaRange = 0.2f;
Steam.alphaSpeed = 0.2f;
Steam.contents = (id)[[UIImage imageNamed:#"Steam1.png"]CGImage];
Steam.velocity = 30;
Steam.velocityRange = 50.0f;
Steam.emissionLongitude = -60.0f;
Steam.emissionRange = M_1_PI;
Steam.scale = .2f;
Steam.scaleSpeed = .5f;
Steam.yAcceleration = -200.0f;
//SteamEmitter.renderMode = kCAEmitterLayerBackToFront;//kCAEmitterLayerAdditive;
//SteamEmitter.emitterShape = kCAEmitterLayerCircle;
SteamEmitter.emitterCells = #[Steam];
SteamEmitter.emitterPosition = CGPointMake(815, 445);
//Check System Version
NSArray *vComp = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
if ([[vComp objectAtIndex:0] intValue] == 7) {
// iOS-6 code
SteamEmitter.beginTime = CACurrentMediaTime();
}
}
return self;
}
-(void)didMoveToSuperview
{
//1
[super didMoveToSuperview];
if (self.superview==nil) return;
[self performSelector:#selector(disableEmitterCell) withObject:nil afterDelay:0.5];
}
-(void)disableEmitterCell
{
[SteamEmitter setValue:#0 forKeyPath:#"birthRate"];
}
+ (Class) layerClass
{
//tell UIView to use the CAEmitterLayer root class
return [CAEmitterLayer class];
}
- (void) setEmitterPosition:(CGPoint)pos
{
SteamEmitter.emitterPosition = pos;
}
- (void) toggleOn:(bool)on
{
//SteamEmitter.birthRate = on? 300 : 0;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
I called the above from my viewcontroller .m using the following. There is also a timer in the viewDidLoad above that calls this every 5 sec. Although that is probably not the way to do it. Probably better to add the view and start it emitting every 5 sec rather than adding a new view each time, but thats a different issue.
- (void)ShowSteamEffect
{
//Check System Version because NSAttributedString only works in ios6 and above.
NSArray *vComp = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:#"."];
//Create view for Steam particle effect.
//CGRect SteamFrame = CGRectMake(790, 380, 100, 100); //ORIGINAL
CGRect SteamFrame = CGRectMake(0, 0, 0, 0); //(815, 455, 100, 100)
//Show Steam effect
ShowSteam = [[SteamEffect alloc]initWithFrame:SteamFrame];
ShowSteam.hidden = NO;
[self.view insertSubview:ShowSteam aboveSubview:imgComputerLights];
}
I managed to get a UIView in greyscale by adding the following view on top:
#interface GreyscaleAllView : UIView
#property (nonatomic, retain) UIView *underlyingView;
#end
#implementation GreyscaleAllView
#synthesize underlyingView;
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// draw the image
[self.underlyingView.layer renderInContext:context];
// set the blend mode and draw rectangle on top of image
CGContextSetBlendMode(context, kCGBlendModeColor);
CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, rect);
[super drawRect:rect];
}
#end
It works, but the content doesn't get updated unless i manually call setNeedsDisplay. (I can press a UIButton and the action fires, but nothing changes in appearance) So for it to behave like expected I call setNeedsDisplay 60 times each second. What am I doing wrong?
UPDATE:
The viewcontroller inits the overlayview with this:
- (void)viewDidLoad
{
[super viewDidLoad];
GreyscaleAllView *grey = [[[GreyscaleAllView alloc] initWithFrame:self.view.frame] autorelease];
grey.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
grey.userInteractionEnabled = NO;
[self.view addSubview:grey];
}
I've added this for the underlaying views to redraw:
#implementation GreyscaleAllView
- (void)setup {
self.userInteractionEnabled = FALSE;
self.contentMode = UIViewContentModeRedraw;
[self redrawAfter:1.0 / 60.0 repeat:YES];
}
- (void)redrawAfter:(NSTimeInterval)time repeat:(BOOL)repeat {
if(repeat) {
// NOTE: retains self - should use a proxy when finished
[NSTimer scheduledTimerWithTimeInterval:time target:self selector:#selector(setNeedsDisplay) userInfo:nil repeats:YES];
}
[self setNeedsDisplay];
}
What you really want is for the subview to only be told to redraw when the parent view redraws, in which case you can override -setNeedsDisplay in the parent view and make it call -setNeedsDisplay on the GreyscaleAllView. This requires subclassing UIView for your UIViewController's view property.
i.e. implement loadView in the controller, and set
self.view = [[CustomView alloc] initWithFrame:frame];
where CustomView overrides setNeedsDisplay as described above:
#implementation CustomView
- (void)setNeedsDisplay
{
[grayView setNeedsDisplay]; // grayView is a pointer to your GreyscaleAllView
[super setNeedsDisplay];
}
#end
For completeness, you should also do the same for -setNeedsDisplayInRect: