Trying to access property from another class Objective-c - ios

I have two classes, Class1 (UIViewController) and Class2 (NSObject). In Class2 I have a property, timerCount, that is increased by 1 every 4th second. I want to set that value to a label in Class1, but it only returns 0. But directly in the Class2 it returns the correct value.
Class2.h
#property (nonatomic) int timerCount;
Class2.m
#synthesize timerCount;
- (void)timerStart {
self.timerCount = 0;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:#selector(timerIncrement) userInfo:nil repeats:YES];
[timer fire];
}
- (void)timerIncrement {
self.timerCount = self.timerCount+1;
Class1 *cls1 = [[Class1 alloc] init];
[cls1 updateTimeLabel];
NSLog(#"%#", [NSString stringWithFormat:#"%i", self.timerCount]); //logs correct numbers
}
Class1.m
- (void)updateTimeLabel {
Class2 *cls2 = [[Class2 alloc] init];
NSLog(#"%#", [NSString stringWithFormat:#"%i", cls2.timerCount]); //logs 0 every 4 second
}
So my question is, what could be wrong?
UPDATE
Class2.m
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"completeTransaction...");
[self provideContentForProductIdentifier:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//initialize the timer and start it
cls1 = [[Class1 alloc] init];
self.timerCount = 0;
timer = [NSTimer scheduledTimerWithTimeInterval:4.0 target:self selector:#selector(timerIncrement) userInfo:nil repeats:YES];
[timer fire];
}
- (void)timerIncrement {
self.timerCount = self.timerCount-1;
[cls1 updateTimeLeftLabel];
NSLog(#"%#", [NSString stringWithFormat:#"IAP: %i", self.timerCount]);
}
Class1.m
- (void)viewDidLoad {
cls2 = [[Class2 alloc] init];
}
- (void)updateTimeLeftLabel
{
NSLog([NSString stringWithFormat:#"%i", cls2.timerCount]);
}

You're creating a new, temporary Class2 object in your updateTimeLabel method. You should be referencing the original Class2 object that is running the timer.

You should not create each time new instance. That is only reason you are receiving 0. Because each new instance point to new address.
Create only single instance and use it.

Related

Timer count throughout the game in Objective c

I am creating a game application in which I need to set timer of 2 minutes throughout the app screens in objective c.
I am creating it in viewDidLoad but it is creating a new instance every-time the view loads.
Here is the code which I am using :
#interface SomeViewController ()
{
int timerCounter;
NSTimer *timer;
}
#property (strong, nonatomic) IBOutlet UILabel *timerLbl;
#end
#implementation SomeViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self startCountdown];
}
- (void)startCountdown
{
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(countdownTimer:)
userInfo:nil
repeats:YES];
}
- (void)countdownTimer:(NSTimer *)timer
{
timerCounter--;
int minutes = timerCounter / 60;
int seconds = timerCounter % 60;
NSString *string = [NSString stringWithFormat:#"%02d", minutes];
NSString *string2 = [NSString stringWithFormat:#"%02d", seconds];
NSString *timeTotal = [string stringByAppendingString:#":"];
NSString *timeTotal2 = [timeTotal stringByAppendingString:string2];
_timerLbl.text = timeTotal2;
if (timerCounter <= 0) {
[timer invalidate];
}
}
You need to invalidate it whenever the VC deallocates
- (void)dealloc {
[timer invalidate];
}
//
The second VC may look like this
#import "ggViewController.h"
NSInteger timerCounter = 120; // declared global to hold the value
#interface ggViewController ()
{
NSTimer*timer;
}
#end
#implementation ggViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// instead of using selector use this inline callback
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:true block:^(NSTimer * timer) {
timerCounter--;
int minutes = timerCounter / 60;
int seconds = timerCounter % 60;
NSString *string = [NSString stringWithFormat:#"%02d", minutes];
NSString *string2 = [NSString stringWithFormat:#"%02d", seconds];
NSString *timeTotal = [string stringByAppendingString:#":"];
NSString *timeTotal2 = [timeTotal stringByAppendingString:string2];
_timerLbl.text = timeTotal2;
if (timerCounter <= 0) {
[timer invalidate];
}
}];
}
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:animated];
[timer invalidate];
}
- (IBAction)gg:(id)sender {
[self dismissViewControllerAnimated:true completion:nil];
}
#end

Persistent allocation of Heap Memory NSTimer

I discovered an issue with my sample project. I simply create a scheduledTimer that "animate" a label and then, when I reached the result I want, I invalidate the timer and I set an another one, this time as a "clock".
This is the code I use
//
// ViewController.m
//
//
//
//
//
#import "ViewController.h"
#define ANIMATION_INTERVAL 0.07 // in secondi
#define ANIMATION_DURATION 1 // in secondi
#interface ViewController ()
{
int contatore;
NSString *hour;
NSString *minute;
NSString *second;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
contatore = 0;
[self startTimeAnimation];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)startTimeAnimation
{
NSTimer * animationTimer = [NSTimer scheduledTimerWithTimeInterval:ANIMATION_INTERVAL target:self selector:#selector(timeout:) userInfo:nil repeats:YES];
}
-(void)timeout: (NSTimer *)timer
{
// Simulate of the Timer Duration with a counter
if (contatore < ceilf(ANIMATION_DURATION/ANIMATION_INTERVAL))
{
// Proceed with animation
contatore++;
int tempHour = arc4random_uniform(24);
int tempMinute = arc4random_uniform(60);
int tempSecond = arc4random_uniform(60);
if (tempHour < 10)
{
hour = [NSString stringWithFormat:#"0%d", tempHour];
}
else
{
hour = [NSString stringWithFormat:#"%d", tempHour];
}
if (tempMinute < 10)
{
minute = [NSString stringWithFormat:#"0%d", tempMinute];
}
else
{
minute = [NSString stringWithFormat:#"%d", tempMinute];
}
if (tempSecond < 10)
{
second = [NSString stringWithFormat:#"0%d", tempSecond];
}
else
{
second = [NSString stringWithFormat:#"%d", tempSecond];
}
_orarioLbl.text = [NSString stringWithFormat:#"%#:%#:%#", hour, minute, second];
}
else
{
// Stops animation
[timer invalidate];
[timer release];
contatore = 0;
[self setActualTime];
// Starts clock
NSTimer *clockTimer = [NSTimer timerWithTimeInterval:.5f target:self selector:#selector(updateClock) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:clockTimer forMode:NSRunLoopCommonModes];
}
}
-(void)updateClock
{
[self setActualTime];
}
-(void)setActualTime
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH"];
hour = [dateFormatter stringFromDate:[NSDate date]];
[dateFormatter setDateFormat:#"mm"];
minute = [dateFormatter stringFromDate:[NSDate date]];
[dateFormatter setDateFormat:#"ss"];
second = [dateFormatter stringFromDate:[NSDate date]];
_orarioLbl.text = [NSString stringWithFormat:#"%#:%#:%#", hour, minute, second];
[dateFormatter release];
}
#end
Since I start the "clock", memory still stays on 19/20 MB with constant persistent allocation. When the timer updates the minute value, persistent allocations increase as you can see in the gif! How is it possible? However, also 19MB of memory is too much for a simple clock, isn't it?
Profiling on Instruments, the new allocations are all about CoreGraphics!
EDIT I tested it on another device and the persistent allocations decreased. I don't know why, but I solved in this way. Thanks
NSTimer retains its target and that may lead to a retain cycle. Grab a weak reference to self and set that as the target:
__weak typeof(self) weakSelf = self;
NSTimer * animationTimer = [NSTimer scheduledTimerWithTimeInterval:ANIMATION_INTERVAL target:weakSelf selector:#selector(timeout:) userInfo:nil repeats:YES];
and
__weak typeof(self) weakSelf = self;
NSTimer *clockTimer = [NSTimer timerWithTimeInterval:.5f target:weakSelf selector:#selector(updateClock) userInfo:nil repeats:YES];
May I also recommend you create a property for the dateFormatter, as NSDateFormatters are expensive to create. And why are you releasing the dateFormatter? Are you not using ARC?

How to hide Text from UILabel in IOS

I'm trying to display a set of numbers on a UILabel sequentially.
For example: I have an array with 5 numbers and each time I want one number from the array to be displayed for 2 seconds on the screen then disappear and then the next number…
This is what i have done so far, but it is not quite what I want. The code below just displays the last number in the array for 2 seconds and then disappears.
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray* myArray = [NSMutableArray array];
for (int i=0; i<5; i++) {
NSNumber *temp;
temp = [myArray objectAtIndex:i];
[self displayNumber:temp];
[myLabel setHidden:NO];
}
}
-(void) displayNumber: (NSNumber *) myNumber{
myLabel.text = [NSString stringWithFormat:#"%#", myNumber];
NSTimer *myTimer;
myTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(hideLabel) userInfo:Nil repeats:NO];
}
-(void) hideLabel{
[myLabel setHidden:YES];
}
I thought about having 5 functions and each gets called sequentially after 2 seconds, but that is very inefficient.
Are there any other ways I can do this?
Change this method
Hope it will works for you what you want
1) Define
NSMutableArray* myArray , int repeatCount; and NSTimer *myTimer in .h file and set its property;
2)
-(void)viewDidLoad
{
[super viewDidLoad];
//This will initialize your timer
myTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(showLabel) userInfo:Nil repeats:NO];
//This will trigger your timer
[myTimer fire];
//Your timer will run in a loop
[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSDefaultRunLoopMode];
myArray = [NSMutableArray array];
}
-(void) displayNumber: (NSNumber *) myNumber{
myLabel.text = [NSString stringWithFormat:#"%#", myNumber];
}
-(void) showLabel{
if(repeatCount >= [myArray count])
{
repeatCount = 0;
}
NSNumber *temp = [myArray objectAtIndex:repeatCount];
repeatCount ++;
[self displayNumber:temp];
[myLabel setHidden:NO];
}
I think, that you can use timer with counter.
Create 3 properties:
#property (nonatomic, assign) int counter;
#property (nonatomic, strong) NSArray *array;
#property (nonatomic, strong) NSTimer *timer;
Set them in viewDidLoad: and start timer(with repetition):
- (void)viewDidLoad {
[super viewDidLoad];
_counter = 0;
_array = #[#0, #1, #2, #3, #4, #5];
_timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(nextLabel) userInfo:Nil repeats:YES];
}
Update label:
- (void)nextLabel{
if (_counter == [_array count]) {
//stop in the end of array
[_timer invalidate];
return;
}
[_label setText:[NSString stringWithFormat:#"%#", _array[_counter]]];
_counter++;
}
Pass the array with NSNumber instances to the below method
- (void)updateLabelWithArray:(NSMutableArray *)array
{
if ([array count] != 0)
{
myLabel.text = [NSString stringWithFormat:#"%#", [array firstObject]];
[array removeObjectAtIndex:0];
[self performSelector:#selector(updateLabelWithArray:)
withObject:array
afterDelay:2.0f];
}
}
This should do.
Try this:
// Initialize the timer when you want to change the first number
[NSTimer scheduledTimerWithTimeInterval:0.0 target:self selector:#selector(changeNumber:) userInfo:#{#"currentNumber" : [NSNumber numberWithInt:0]} repeats:NO];
-(void)changeNumber:(NSTimer *)timer
{
NSDictionary * dictionary = [timer userInfo];
int number = [(NSNumber *)[dictionary objectForKey:#"currentNumber"] integerValue];
if (number < [numbersArray count])
{
myLabel.text = [NSString stringWithFormat:#"%#", [numbersArray objectAtIndex:number]];
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(changeNumber:) userInfo:#{#"currentNumber" : [NSNumber numberWithInt:number + 1]} repeats:NO];
}
}
try this hope this helps u .. :)
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
myArray = [[NSMutableArray alloc]initWithObjects:[NSNumber numberWithInt:3],[NSNumber numberWithInt:5],[NSNumber numberWithInt:6],[NSNumber numberWithInt:7],[NSNumber numberWithInt:10], nil]; //your array contains any number you want
index = 0; //showing the numbers from 0th index to last indx
[self.myLabel setHidden:NO];
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(DisplayFortwoSec) userInfo:nil repeats:YES];//call the method reguraly for 2 sec
}
- (void)DisplayFortwoSec
{
[self.myLabel setHidden:YES];
if(index == ([myArray count] - 1))
index = 0;//other stuffs to come out of loop like invalidating the timer
[self.myLabel setHidden:NO];
NSNumber *num = [myArray objectAtIndex:index];
NSString *strNum = [num stringValue];
self.myLabel.text = strNum;
[self.myLabel setHidden:NO];
index ++;
}

Update UILabel continuously — Objective-c

I'm trying to display the count of a timer in a UILabel. The timer works fine but I'm not able to update the label. The NSTimer is set up like this in Class1.
- (void)startTimer {
int timerCount = 5;
timer = [NSTimer scheduledTimerWithTimeInterval:4.0
target:self
selector:#selector(timerDecrement)
userInfo:nil
repeats:YES];
[timer fire];
}
- (void)timerDecrement {
Class2 *cls2 = [[Class2 alloc] init];
timerCount = timerCount-1;
[cls2 updateTimeLeftLabel];
}
+ (int)getTimerCount {
return timerCount;
}
In Class2:
- (void)viewDidLoad {
if (timeLeftLabel == nil) {
timeLeftLabel = [[UILabel alloc] initWithFrame:CGRectMake(200, 70, 120, 30)];
timeLeftLabel.text = #"Time left";
[self.view addSubview:timeLeftLabel];
}
- (void)updateTimeLeftLabel {
NSLog(#"%#", [NSString stringWithFormat:#"%i",
[Class1 getTimerCount]]);
timeLeftLabel.text = [NSString stringWithFormat:#"Time left: %i",
[Class1 getTimerCount]];
}
The correct timer value is logged but the UILabel isn't updated at all. What's wrong?
Try to make timerCount as a #property of your class or static.
You create a new instance of the Class2 and do not present it. You should store instance of Class2 somewhere and work with it.
I needed to update count on my UIButton so i have done like this
-(void)viewDidLoad {
self.myLeagueTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateCountdown) userInfo:nil repeats: YES];
}
- (int)timeIndervalRemain {
NSDate *currentTime = [NSDate date];
return (TIME_INTERVAL - [currentTime timeIntervalSinceDate:self.startTime]);
}
-(void) updateCountdown {
if ([self timeIndervalRemain] > 0) {
self.title = [NSString stringWithFormat:#"%d", [self timeIndervalRemain]];
} else {
[self timeExpire];
}
}
-(void) timeExpire {
if (_myLeagueTimer) {
[_myLeagueTimer invalidate];
_myLeagueTimer = nil;
}
}
You can simply pass the time left to the method updating the UILabel as a parameter:
- (void)updateTimeLeftLabel:(NSInteger)timeLeft {
timeLeftLabel.text = [NSString stringWithFormat:#"Time left: %i",
timeLeft];
}
- (void)timerDecrement {
Class2 *cls2 = [[Class2 alloc] init];
timerCount = timerCount-1;
[cls2 updateTimeLeftLabel:timerCount];
}

iOS NSTimer firing twice

Hi I'm trying to use NSTimer to create a countdown which and view this using a label. the problem is the label goes down in two's and i don't know why. any ideas?
heres my code
- (void)viewDidLoad
{
NSLog(#"%#", self.chosenTime);
[self startGame];
[super viewDidLoad];
NSString *timeString = self.chosenTime;
self.timer = [timeString intValue];
self.countdown.text = timeString;
// Do any additional setup after loading the view.
}
- (void)startGame
{
[self introCountdown];
[self performSelector:#selector(goAnimation) withObject:nil afterDelay:3.0];
NSString *timeString = self.chosenTime;
self.timer = [timeString intValue];
[self performSelector:#selector(startCountdown) withObject:nil afterDelay:4.0];
}
- (void)startCountdown
{
//self.countdownTimer = [NSTimer timerWithTimeInterval:1 target:self selector:#selector(decrementTimer:) userInfo:nil repeats:YES];
self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.00 target:self selector:#selector(decrementTimer:) userInfo:nil repeats:YES];
}
- (void)decrementTimer:(NSTimer *)timer
{
if(self.timer > 0)
{
self.timer = self.timer - 1;
self.countdown.text = [NSString stringWithFormat:#"%d", self.timer];
}
else
{
[self.countdownTimer invalidate];
self.countdownTimer = nil;
}
}
This code seems to be correct. May be you are changing label's text from somewhere else?
Sorry for the misinterpretation, the code is correct, it seems a UI problem or handling label from somewhere else, attach your source with xib's if possible

Resources