Okay, I am building an app for iOS and I am having some trouble with getting the current time to display properly within a UILabel.
Here is the code in the ViewController.h file:
#interface ViewController : UIViewController <UIApplicationDelegate>
#property (strong, nonatomic) IBOutlet UILabel *timeLabelStandbyScreen;
-(void)updateLabel;
-(void)updateTime;
#end
#interface updateTime : NSDate
#end
I'm new to Obj-C and I was playing around with it to see if I could fix the problem. Everything is fine in this file it's the .m that has the problems.
ViewController.m:
#interface ViewController ()
#end
#implementation ViewController
-(void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self updateLabel];
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)updateTime
{
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"hh:mm"];
_timeLabelStandbyScreen.text = [dateFormat stringFromDate: [NSDate date]];
[self preformSelector:#selector(updateTime) withObject:self afterDelay:1.0];
}
#end
I'm sure the problem is really simple and I appreciate your help. Thanks!
By commenting out the preformSelector method and adding a NSTimer (like #rocir suggested) it correctly displayed the time.
Related
I am starting a watch development project. It will basically be starting and stopping several timers on the watch. The initial code works fine on the 42mm Simulator but not on the actual watch. That is, tapping on the Start button begins the WKInterfaceTimer label running. Nothing happens on the physical watch. However, I know the timer is working because if I check Enabled in the InterfaceBuilder the timer starts incrementing as soon as the app launches on the watch. Here is the code for watch app extension.h and .m. The outlet is connected properly in IB. Also, tapping on the Dispatch button enters the Dispatch IBAction and works correctly. I have also tried powering off and powering on the watch. That does not help.
I would really appreciate some help on this.
interface controller.h
/
/
/
/
/
/
#import <WatchKit/WatchKit.h>
#import <Foundation/Foundation.h>
#interface InterfaceController : WKInterfaceController
#property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceTimer *ElapsedTime;
#property (unsafe_unretained, nonatomic) IBOutlet WKInterfaceLabel *dispatchTime;
#property (weak, nonatomic) NSDate *startDate;
#end
/
/
/
interface controller.m
/
/
/
/
#import "InterfaceController.h"
#interface InterfaceController()
#end
#implementation InterfaceController
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
/
}
- (void)willActivate {
/
[super willActivate];
}
- (void)didDeactivate {
/
[super didDeactivate];
}
- (IBAction)Start {
self.startDate = [NSDate date];
[self.ElapsedTime setDate:self.startDate];
[self.ElapsedTime start];
}
- (IBAction)Stop {
[self.ElapsedTime stop];
}
- (IBAction)Dispatch {
NSDate *date =[NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterNoStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
NSString *dateString = [dateFormatter stringFromDate:date];
[self.dispatchTime setText:dateString];
}
#end
Still not sure why the WKInterfaceTimer object doesn't work. Instead, I used a standard NSTimer object and a standard NSDate object. The code works. Note: if you have another page-based storyboard scene that the first scene seques to, you have to add a custom WkInterfaceController object to the next scene and connect your outlets from the interface storyboard to it. Otherwise, the outlets won't connect because the file's owner isn't correct. Also, make sure that you add the custom WkInterfaceController to the watch kit extension target, not the iOS target.
//
// InterfaceController.h
// EMSTimers WatchKit 1 Extension
//
// Created by Nelson Capes on 12/18/15.
// Copyright © 2015 Nelson Capes. All rights reserved.
//
#import <WatchKit/WatchKit.h>
#import <Foundation/Foundation.h>
#interface InterfaceController : WKInterfaceController
#property (weak, nonatomic) IBOutlet WKInterfaceLabel *ElapsedTime;
#property (strong, nonatomic) IBOutlet WKInterfaceLabel *dispatchTime;
#property (strong, nonatomic) NSDate *startDate;
#property (strong, nonatomic) NSDate *dateStarted;
#property (strong, nonatomic) NSTimer *elaspsedTimer;
#end
//
// InterfaceController.m
// EMSTimers WatchKit 1 Extension
//
// Created by Nelson Capes on 12/18/15.
// Copyright © 2015 Nelson Capes. All rights reserved.
//
#import "InterfaceController.h"
#interface InterfaceController()
#end
#implementation InterfaceController
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
}
- (IBAction)Start {
NSDate *date =[NSDate date];
self.dateStarted = date;
NSTimeInterval timeInterval = 1.0;
self.elaspsedTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval target:self selector:#selector(calculateTimer:) userInfo:self.elaspsedTimer repeats:YES];
[self.elaspsedTimer fire];
}
- (IBAction)Stop {
[self.elaspsedTimer invalidate];
}
-(void)calculateTimer:(NSTimer *)theTimer
{
NSTimeInterval interval = [self.dateStarted timeIntervalSinceNow];
interval = (-1 * interval);
int time = round(interval);
div_t h = div(time, 3600); //seconds total, divided by 3600 equals
int hours = h.quot; // hours, divided by 60 equals
div_t m = div(h.rem, 60); // minutes
int minutes = m.quot;
int seconds = m.rem; // and remainder is seconds
NSString *intervalString = [NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
[self.ElapsedTime setText:intervalString];
}
- (void)willActivate {
// This method is called when watch view controller is about to be visible to user
[super willActivate];
}
- (void)didDeactivate {
// This method is called when watch view controller is no longer visible
[super didDeactivate];
}
#end
I'm having problems passing data between two view controllers.
I've seen two ways to do this.
One involves implementing prepareForSeque: in the segue's source view controller and another involves setting properties in the viewDidLoad: method of the segue's destination view controller.
e.g.-
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toEmailReservationViewController"]) {
FLSendEmailViewController *controller = (FLSendEmailViewController *)segue.destinationViewController;
if (!controller.startDateField.text) {
controller.startDateField.text = #"today";
}
}
}
and
- (void)viewDidLoad
{
[super viewDidLoad];
self.startDateField.text = ((FLViewController *)self.presentingViewController).startDate;
}
I've got these to work on simple apps using two UIViewController. However, I can't get them to work on an app that has a UITabViewController connected to some UINavigationViewController connected to custom subclasses of UIViewController. When I click the button to perform the push seque, I get to the view I want, but the startDateField.text doesn't have the text from the segue's source view controller.
Why are these methods of sharing data not working with the tab controller and navigation controller setup?
I noticed that in prepareForSegue: I can't set controller.startDateField.text; as shown when I try to set it and use NSLog to display it. Could this be the problem? Is it possible that the property controller.startDateField.text doesn't exist yet?
I'm trying to grab the date from a datePicker in an instance of FLViewController, store this date in the property NSString *startDate, and in an instance of FLSendEmailViewController set NSString *startDateField.text to the `NSString *startDate'.
Here are the UIViewController subclasses I created:
FLViewController.h
#import <UIKit/UIKit.h>
#import "FLSendEmailViewController.h"
// import frameworks to use ad
#import AddressBook;
#import AddressBookUI;
#interface FLViewController : UIViewController
#property (weak, nonatomic) IBOutlet UIScrollView *theScroller;
#property (weak, nonatomic) NSString *startDate;
#property (weak, nonatomic) NSString *stopDate;
- (IBAction)exitToReservations:(UIStoryboardSegue *)sender;
#end
FLViewController.m
#import "FLViewController.h"
#interface FLViewController ()
#property (weak, nonatomic) IBOutlet UIDatePicker *startReservationDatePicker;
#property (weak, nonatomic) IBOutlet UIDatePicker *stopReservationDatePicker;
#end
#implementation FLViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self.theScroller setScrollEnabled:YES];
[self.theScroller setContentSize:CGSizeMake(280, 1000)];
//setup reservationDatePicker
[self.startReservationDatePicker addTarget:self
action:#selector(startDatePickerChanged:)
forControlEvents:UIControlEventValueChanged];
[self.stopReservationDatePicker addTarget:self
action:#selector(stopDatePickerChanged:)
forControlEvents:UIControlEventValueChanged];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
// add method called when user changes start date
- (void)startDatePickerChanged:(UIDatePicker *)datePicker
{
NSDateFormatter *dateFortmatter = [[NSDateFormatter alloc] init];
[dateFortmatter setDateFormat:#"dd--MM-yyyy HH:mm"];
// get date using stringFromData: method and getter datePicker.date
self.startDate = [dateFortmatter stringFromDate:datePicker.date];
NSLog(#"The start date is %#", self.startDate);
}
// add method called when user changes stop date
- (void)stopDatePickerChanged:(UIDatePicker *)datePicker
{
NSDateFormatter *dateFortmatter = [[NSDateFormatter alloc] init];
[dateFortmatter setDateFormat:#"dd--MM-yyyy HH:mm"];
// get date using stringFromData: method and getter datePicker.date
self.stopDate= [dateFortmatter stringFromDate:datePicker.date];
NSLog(#"The stop date is %#", self.stopDate);
}
- (IBAction)exitToReservations:(UIStoryboardSegue *)sender {
// execute this code upon unwinding
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toEmailReservationViewController"]) {
FLSendEmailViewController *controller = (FLSendEmailViewController *)segue.destinationViewController;
if (!controller.startDateField.text) {
controller.startDateField.text = #"today";
NSLog(#"in vc startDate is null but set to %#",controller.startDateField.text );
}
}
}
#end
FLSendEmailViewController.h
#import <UIKit/UIKit.h>
#class FLViewController;
#interface FLSendEmailViewController : UIViewController
#property (retain, nonatomic) IBOutlet UITextField *startDateField;
#property (retain, nonatomic) IBOutlet UITextField *stopDateField;
#end
FLSendEmailViewController.m
#import "FLSendEmailViewController.h"
#import "FLViewController.h"
#interface FLSendEmailViewController ()
- (IBAction)sendEmail:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *numberOfDoggies;
#property (weak, nonatomic) IBOutlet UITextField *emailAddressField;
- (IBAction)hideKeyboard:(id)sender;
#end
#implementation FLSendEmailViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.startDateField.text = ((FLViewController *)self.presentingViewController).startDate;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)sendEmail:(id)sender {
NSString *emailString = [NSString stringWithFormat:#"I would like you to watch my %# doggies from %# to %#. Thank you.", self.numberOfDoggies.text, self.startDateField.text, self.stopDateField.text];
NSLog(#"%#",emailString);
}
- (IBAction)hideKeyboard:(id)sender {
[self.startDateField resignFirstResponder];
}
#end
Import the FLSendEmailViewController.h to the "InitialViewController.h"
Add this property to the FLSendEmailViewController.h
#property (nonatomic, strong) NSString *exportedData;
Add this to the FLSendEmailViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.startDateField.text = self.exportedData
}
4.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toEmailReservationViewController"]) {
FLSendEmailViewController *controller = (FLSendEmailViewController *)segue.destinationViewController;
if (!controller.startDateField.text) {
controller.exportedData = #"today";
}
}
}
This "sharing method" works in any case when from a controller go to another controller.
So, in case of a navigation controller, if you want push another viewController passing the data, you have just to set the trigger in the Storyboard (if you are using storyboard) from the button, and the new viewController.
So, you will not met troubles. Otherwise, you are committing other type of errors, and in this case, update your question.
I have an app here that asks for user input for 3 fields. After the 3 fields are entered, they are displayed in a view controller inside of a custom cell. You can add as many of these events as you like. You can then choose to click on an event cell to display the information in a new view controller about that specific event. For some reason, the details for the events I have entered are not showing up at all. I just get a blank controller screen. I can't seem to figure out why, but I thought I had the code correctly implemented in this controller. Does it have to do with my creation of a new Event object "theEvent"?
Here is some of my code (the full project will be linked below):
Full Project: Full Project Link Removed
FinalDetailViewController.h
#import <UIKit/UIKit.h>
#class Event;
#interface FinalDetailViewController : UITableViewController
#property (strong, nonatomic) id detailItem;
#property (strong, nonatomic) Event *event;
#property (weak, nonatomic) IBOutlet UILabel *detailLabel;
#property (weak, nonatomic) IBOutlet UILabel *locationLabel;
#property (weak, nonatomic) IBOutlet UILabel *dateTimeLabel;
#end
FinalDetailViewController.m
#import "FinalDetailViewController.h"
#import "Event.h"
#interface FinalDetailViewController ()
- (void)configureView;
#end
#implementation FinalDetailViewController
#pragma mark - Managing the detail item
- (void)configureView
{
Event *theEvent = self.event;
static NSDateFormatter *formatter = nil;
if (formatter == nil) {
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"CCCC, MMMM dd, yyyy hh:mm a"];
}
if (theEvent) {
self.detailLabel.text = theEvent.detail;
self.locationLabel.text = theEvent.location;
self.dateTimeLabel.text = [formatter stringFromDate:(NSDate *)theEvent.date];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self configureView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
It looks like you intended to make the FinalDetailViewController's table be a static table view (since you're making outlets to the labels, which you can only do in a static table). Change the table view to static cells, and it should work.
I have an Objective-C class that is a subclass of UIViewController. This isn't my main view, but it is accessed when a button is pushed from ViewController through segue in StoryBoard. They are both attached to a navigation controller so they switch around fine. However, I have a problem. In my "DisplayView.m" file (the second view), I make some calculations and want to set the text of a label. I know that there aren't any problems with the calculation portion of the code, because when I NSLog the string, it comes out fine. However, the label does not change. This is my setup for DisplayView scene in Storyboard:
Custom class of "DisplayView" set
Label that is linked to IBOutlet
Here's my imp file for DisplayView.m if that helps. Please let me know if you need any additional details. Things that I've tried:
Creating a new method to print the text
Logging the output that is supposed to show up, to the console (works perfect)
Trying a different label
Trying to use the label objects without #property
Trying to setText a non formatted string
None of these tests really worked, and I can't seem to find what the problem is. The new view simply loads without the label. However, if I change the label text in StoryBoard, it does show up. It just isn't showing up any of the values from my code.
DisplayView.m
#import "DisplayView.h"
#interface DisplayView ()
#end
#implementation DisplayView
#synthesize months,days,seconds;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)calc:(int)m with:(int)d andWith:(int)y {
NSString* bday = [NSString stringWithFormat:#"%i-%i-%i 00:00:00 +0000",m,d,y];
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:#"LL-dd-yyyy 00:00:00 +0000"];
NSDate *date1 = [formatter dateFromString:bday];
NSDate *date2 = [NSDate date];
NSTimeInterval secondsBetween = [date2 timeIntervalSinceDate:date1];
int numberOfDays = secondsBetween/86400;
[days setText:#"asdadas"];
}
#end
DisplayView.h
#import <UIKit/UIKit.h>
#interface DisplayView : UIViewController {
IBOutlet UILabel* months;
IBOutlet UILabel* days;
IBOutlet UILabel* seconds;
}
-(void)calc:(int)m with:(int)d andWith:(int)y;
#property UILabel* months;
#property UILabel* days;
#property UILabel* seconds;
#end
I'm having a problem getting an NSTimer to work, probably because I don't know how to properly use it (I've tried reading the apple documentation, it didn't help me much). I get a time off of a UIDatePicker and I want the app to call the method when that time is reached. Simple, no? So the code I have is below:
-(IBAction)SetButtonPress:(id)sender{
NSDate *date = [Picker date];
alarmTimer = [[AlarmTimer alloc] init];
[alarmTimer runTimer: Picker.date];
}
A few things now follow standards, but it still doesn't work. It still gives me a time 6 hours ahead, and when it hits that time, it doesn't do anything.
And the code for the RunTimer method of my alarmTimer class is as follows:
-(void)RunTimer: (NSDate *) date
{
NSRunLoop *theLoop = [NSRunLoop currentLoop];
[theLoop addTimer:timer forMode:NSDefaultRunLoopMode];
[timer initWithFireDate:date interval:0 target:self selector:#selector(Play) userInfo: nil repeats:NO];
}
A few things now follow standards, but it still doesn't work. It still gives me a time 6 hours ahead, and when it hits that time, it doesn't do anything.
And just in case it helps, here is the .h and .m files for the view controller:
.h:
//
// Assignment_1ViewController.h
// Assignment 1
//
// Created by Jack Schaible on 11-09-28.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AlarmTimer.h"
#interface Assignment_1ViewController : UIViewController {
UIButton *SetButton;
UIDatePicker *Picker;
UIButton *CancelButton;
NSString *time;
AlarmTimer *alarmTimer;
}
#property (nonatomic, retain) IBOutlet UIButton *SetButton;
#property (nonatomic, retain) IBOutlet UIDatePicker *Picker;
#property (nonatomic, retain) IBOutlet UIButton *CancelButton;
- (IBAction)SetButtonPress:(id)sender;
- (IBAction)CancelButtonPress:(id)sender;
#end
.m:
//
// Assignment_1ViewController.m
// Assignment 1
//
// Created by Jack Schaible on 11-09-28.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "Assignment_1ViewController.h"
#import "AlarmTimer.h"
#implementation Assignment_1ViewController
#synthesize Picker;
#synthesize CancelButton;
#synthesize SetButton;
- (void)dealloc
{
[SetButton release];
[Picker release];
[CancelButton release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[self setSetButton:nil];
[self setPicker:nil];
[self setCancelButton:nil];
[super viewDidUnload];
[alarmTimer release];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)SetButtonPress:(id)sender {
NSDateFormatter *ndf = [[NSDateFormatter alloc] init];
time = [ndf stringFromDate:self.Picker.date];
alarmTimer = [AlarmTimer alloc];
[alarmTimer init];
NSLog(#"Date is: %#", [ndf dateFromString:time]);
[alarmTimer RunTimer:[ndf dateFromString:time]];
}
- (IBAction)CancelButtonPress:(id)sender {
}
#end
And the code for the AlarmTimer class:
.h:
//
// Timer.h
// Assignment 1
//
// Created by Jack Schaible on 11-09-28.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
#interface AlarmTimer : NSObject {
NSString *time;
NSTimer *timer;
AVAudioPlayer *player;
}
-(void) RunTimer: (NSDate *)date;
-(void)Play;
-(void)CancelTimer;
#end
And finally, the .m:
//
// Timer.m
// Assignment 1
//
// Created by Jack Schaible on 11-09-28.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#import "AlarmTimer.h"
#implementation AlarmTimer
-(id) init
{
if(self == [super init])
{
timer = [NSTimer alloc];
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/Time.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error;
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
}
return self;
}
- (void) RunTimer: (NSDate *)date
{
[timer initWithFireDate:date interval:86400 target:self selector:#selector(Play) userInfo:nil repeats:NO];
NSLog(#"Date is: %#", date);
}
-(void) Play
{
[player play];
UIAlertView *aView = [[UIAlertView alloc] initWithTitle:#"Holy Chimes!" message:#"If you didn't hear that..." delegate:self cancelButtonTitle:#"Okay" otherButtonTitles:nil, nil];
[aView show];
}
-(void)CancelTimer
{
time = nil;
}
#end
Thanks a lot to anyone who can help!
Why do you use NSDateFormatter? try to do it like that:
alarmTimer = [AlarmTimer alloc];
[alarmTimer init];
NSLog(#"Date is: %#", self.Picker.date);
[alarmTimer RunTimer: self.Picker.date];
As a rule, do the +alloc and -init together: Foo *someFoo = [[Foo alloc] init];. Don't separate the calls as you've done with your timer and alarmTimer variables. The reason for this is that sometimes the initializer will return a different pointer than what you get from +alloc, and when that happens you want to be certain to store that new pointer. I don't know if NSTimer ever does that, but if so you'll have all kinds of trouble with your current code.
Don't try to reuse a timer. Once it fires, release it and create a new one when you need to.
What's all that craziness in -SetButtonPress:? You get a date from a date picker, convert it to a string, and then immediately convert that string back to a date... why?
You're using an interval of 24 hours (86400 seconds) for your timer. Are you under the mistaken impression that a timer with a long interval will wake up an app that's in the background? NSTimer relies on the run loop; when the run loop isn't running, the timer isn't working.
It'd be somewhat easier to help you if you'd stick to the usual Objective-C convention and name methods starting with lower-case characters, i.e. -runTimer: instead of -RunTimer:. The same rule applies to instance variables.