Date-derived field not updating with core data change - ios

I have a view controller that implements UITextViewDelegate, UITextFieldDelegate, and NSFetchedResultsControllerDelegate. It is a UIViewController, not a table VC. Nor is there a table in it.
When I make a change to the Core Data store in another view controller, most text fields and text views in the first VC update However, I have another text field that shows the date and is derived from `NSDateFormatter, based on a date attribute in Core Data. It is hidden when nil and when the value is no longer nil, the code to unhide it is not working.
There isn't any code in the VC that says the text views and text fields that DO update specifically are delegates of anything. They just update naturally.
Perhaps the delegate was set in storyboard, but I don't remember and don't know a way to check what delegates are set in storyboard.
Is there a special date delegate? Or how would I get this text field derived from NSDateFormatter to update?
EDIT:
This is where the date is displayed in a method called updateInterface called within viewWillAppear
//Here is an example of a label that does update when data changes.
self.nameLabel.text = self.item.name; //this sets name...It updates when name is changed.
//Here is the data label that is not changing from hidden to not hidden.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE MMMM d, YYYY 'at' h:mma"];
NSString *date = [dateFormatter stringFromDate:self.item.date];
if (self.item.date!=nil) {
self.dateLabel.text =date;
else {
self.dateLabel.hidden = YES;
}

Related

iOS NSDate to Single Digits

I am working on an app and I have this code:
NSDateFormatter *clockFormat = [[NSDateFormatter alloc]init];
[clockFormat setDateFormat:#"hh:mm a"];
self.clockLabel.text = [clockFormat stringFromDate:[NSDate date]];
[self performSelector:#selector(updateClockLabel) withObject:self afterDelay:1.0];
I created a view with subviews to create a LCD type clock display and I want to hide the correct subviews corresponding to the clockLabel. I created arrays of each view (digit), now how do I tell the views that if the first h in hh:mm is 1, hide these subviews to make an LCD "1" in the view.
Simply, how do I access each digit of hh:mm?
You can use NSRange to get substrings. Use NSRangeMake(location,length). To get an NSString of the first character of self.clockLabel.text. You can say say
NSString *firstHourDigit = [self.clockLabel.text substringWithRange:NSRangeMake(0,1)];

IQKeyboardManager with UIDatePicker

I've implemented the IQKeyboardManager framework to make the keyboard handle easier. It works very fine, except for one thing :
There're some UItextField controls in my app which open a UIDatePicker in place of a default keyboard (e.g. number pad, decimal pad, ASCII capable, etc.).
Here's a code sample with the graphical result :
// Create the datePicker
UIDatePicker *birthdayDatePicker = [UIDatePicker new];
[birthdayDatePicker setDatePickerMode:UIDatePickerModeDate];
// Assign the datePicker to the textField
[myTextField setInputView:birthdayDatePicker];
My question is :
Is it possible to handle the action on the "OK" button to fill the field "Date de naissance" ?
EDIT :
For the ones who want to know how I solved my problem :
in my .h, I imported IQDropDownTextField.h :
#import "IQDropDownTextField.h"
in the .h, I changed the type of my UITextField to IQDropDownTextField :
#property (weak, nonatomic) IBOutlet IQDropDownTextField *myTextField;
select your field in Interface Builder or in your .xib, and show the Identity Inspector : change your field's class to IQDropDownTextField.
Note according to Mohd Iftekhar Qurashi comment : the two next points can be avoided with the following code :
// Set myTextField's dropDownMode to IQDropDownModeDatePicker
myTextField.dropDownMode = IQDropDownModeDatePicker;
// Create a dateFormatter
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:#"dd/MM/yyyy"];
// Assign the previously created dateFormatter to myTextField
myTextField.dateFormatter = df;
// Assign a minimum date and/or maximum date if you want
myTextField.minimumDate = [NSDate date];
myTextField.maximumDate = [NSDate date];
// That's all !
in the .m, I added the setCustomDoneTarget:action: method :
// Create the datePicker
UIDatePicker *birthdayDatePicker = [UIDatePicker new];
[birthdayDatePicker setDatePickerMode:UIDatePickerModeDate];
// Assign the datePicker to the textField
[myTextField setInputView:birthdayDatePicker];
// Just added this line
[myTextField setCustomDoneTarget:self action:#selector(doneAction:)];
in the .m, I added the doneAction: method :
- (void)doneAction:(UITextField *)textField
{
[myTextField setText:[DateHelper getStringFromDate:birthdayDatePicker.date format:#"dd/MM/yyyy" useGmt:NO]]; // getStringFromDate:format:useGmt: is a method to convert a NSDate to a NSString according to the date format I want
}
You can now add customised selector(please refer 'IQUIView+IQKeyboardToolbar.h') for previous/next/done to get notify. Note that custom selector doesn't affect the native functionality of previous/next/done, it's just used for callback purpose only. For detail documentation please refer 'IQUIView+IQKeyboardToolbar.h', for 'how to use?' please refer 'TextFieldViewController.m'.

Pass back data using [popviewcontroller], and reload data

http://imgur.com/2lAJmVd
In the picture provided above, shows three view controllers.
Let's call the view controllers A, B, and C in the order they're displayed.
View Controller A passes parsed jSON data by clicking on the table cell. This fills up the "total sales, discounts, etc." strings/labels inside of the View Controller B using a prepareForSegue method.
This data is based on a start time/end time and the default parameter when performing the segue gives information from 8 AM to 10 PM of the current day.
The parsing string looks like this
NSDate *currentDate = [NSDate date];
NSDateFormatter *dateformatter = [[NSDateFormatter alloc] init];
[dateformatter setDateFormat:#"YYYY-MM-dd"];
NSString *theDate = [dateformatter stringFromDate: currentDate];
NSString *salesStr = #"http://";
salesStr = [salesStr stringByAppendingString:host];
salesStr = [salesStr stringByAppendingString:#":8080/sales.php?password="];
salesStr = [salesStr stringByAppendingString:pass];
salesStr = [salesStr stringByAppendingString:#"&db="];
salesStr = [salesStr stringByAppendingString:db];
salesStr = [salesStr stringByAppendingString:#"&sdate="];
salesStr = [salesStr stringByAppendingString:theDate];
salesStr = [salesStr stringByAppendingString:#"%2008:00:00&edate="];
salesStr = [salesStr stringByAppendingString:theDate];
salesStr = [salesStr stringByAppendingString:#"%2022:00:00"];
Inside of the View Controller B, you can notice a button labeled "Start Time". This button initiates a push segue to View Controller C. In this new view controller, you are able to select a date and time and it is displayed in the UILabel above the date picker. The button below the date picker is an IBAction and uses
[self.navigationController popViewControllerAnimated:YES];
My question is: How am I able to select a date/time in View Controller C, press a button, and send that information located in the UILabel to View Controller B so it can be used to update the parsed information?
One way I could think of doing this is to have the button segue to View Controller B, and RE-PARSE the information based on the date/time selection, but that would just cause too much 'navigation controller stacking' and just doesn't seem efficient to me.
Any suggestions are appreciated.
Hacker's approach would work.
Apple's documentation suggests a slightly different technique. Define a simple protocol with a method that view controller C can use to communicate with view controller B.
Then give view controller C a delegate property that conforms to that protocol.
In your prepareForSegue method, set yourself as view controller C's delegate.
Then, in view controller C, when the user changes the date and clicks the button, invoke a delegate method to notify view controller B that the user changed the date value before popping yourself.
I would suggest adding a cancel button as well, so the user can discard their changes. In that case, you just would skip calling the delegate method before popping.
in the interface of your view controller C add a property
#property (nonatomic, strong) NSDate *selectedDate;
before pushing C from B do
[cViewController addObserver:self forKeyPath:#"selectedDate" options:0 context:NULL];
and implement
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
//do some stuff
}
in view controller B.
when selecting a new date do (in view controller V)
self.date = myPicker.date;
so view controller B gets notified when the new date is set
don't forget to remove the observer in implementation of B (e.g. viewWillAppear)...
[cViewController removeObserver: self....];

passing data between UIViewControllers from UIDatePicker

Let me begin to tell you that I am new to Objective C. I have just finished Big Nerd Ranch's book and i want to create a real simple and basic app to learn more.
My idea was to create an app that will calculate the weeks between 2 dates. I have created a class for that and tested it. That works.
As you can see below, I have created to views (programmatically), One with the dates and the other will become visible when you click on start or end date.
If you select a date and click on the button 'calculate weeks', you will go back to the first view.
No my big question is, how do I get this selected value back to my main screen? I have tried several possibilities and search the web for information, but I couldn't get is to work.
I know this should be real easy, but for me at this moment it isn't. :-)
I have created a NSMutableArray that contains the values "Start date" and "End date". My idea was to add the value of the UILabel from the SelectDateView to this array.
I have created a property In the inputview #property (readwrite, retain) NSMutableArray *datesArray; for that.
in the selectDateViewController i have created another property #property (nonatomic, assign) BITInputViewController *ivc; so I (in my opinion) can add a value to datesArray.
When I select a date this method is called, it works for the UILabel on SelectDateView, but doesn't do anything with the datesArray.
- (void)LabelChange:(id)sender{
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateStyle = NSDateFormatterMediumStyle;
dateLabel.text = [NSString stringWithFormat:#"%#",
[df stringFromDate:datePicker.date]];
[ivc.datesArray addObject:dateLabel.text];
if (ivc.datesArray) {
for (NSString *d in ivc.datesArray) {
NSLog(#"This is in datesArray %#",d);
}
}else NSLog(#"!ivc.datesArray");
}
When I test the app and select a date, I always see "!ivc.datesArray" in the log file.
I also do this check of ivc.datesArray in -(void)viewWillAppear:(BOOL)animated
and here I see the current date, as I set this date in - (void)viewDidLoad
with this dateLabel.text = [NSString stringWithFormat:#"%#",[df stringFromDate:[NSDate date]]];
(When I print out the array in the inputview, it does show start date and end date, but not the selected date. )
Hopefully someone can give me a few pointers on this.
declare a NSString* date above the #interface in your view1.m file and the create a method in tht first class it should be something like
-(void)passDate:(NSString *)dateString
{
date = [NSString stringWithFormat:#"%#",dateString];
}
and in your second class create object of first class like
View1 * vc = [[View1 alloc]init];
[vc passDate:df];
Hope it works. You have to declare NSString before the #interface and no property and synthesize.

IOS Setting Viewcontroller property bad access error

I am trying to set the property of a child view controller (DateViewController) from the parent and getting a bad access error the second time I do so. Here is the code. This is the DateViewController.h. The problem lies with the selectedDate property:
#import <UIKit/UIKit.h>
#protocol DateViewDelegate <NSObject>
-(void) dateViewControllerDismissed:(NSDate *)selectedDate;
#end
#interface DateViewController : UIViewController {
IBOutlet UIDatePicker *dateReceipt;
id myDelegate;
}
-(IBAction)btnDone;
#property(nonatomic,assign)NSDate *selectedDate;
#property(nonatomic,assign)id<DateViewDelegate> myDelegate;
#end
Inside DateViewController.m, I do synthesize selectedDate. Now in the parent view controller (ComdataIOSViewController.m) I set the selectedDate property of the DateViewController to the variable receiptDate which is declared as an NSDate * in the #interface section of ComdataIOSViewController.h. This is a snippet of ComdataIOSViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
receiptDate = [NSDate date];
}
-(IBAction)btnSetDate {
dlgDate=[[DateViewController alloc] initWithNibName:nil bundle:nil];
dlgDate.selectedDate = receiptDate;
dlgDate.myDelegate = self;
[self presentModalViewController:dlgDate animated:true];
[dlgDate release];
}
-(void) dateViewControllerDismissed:(NSDate *)selectedDate
{
NSDateFormatter *dateFormat = [[[NSDateFormatter alloc] init] autorelease];
[dateFormat setDateStyle:NSDateFormatterShortStyle];
receiptDate = selectedDate;
dateString = [dateFormat stringFromDate:receiptDate];
lblDate.text = dateString;
}
So the first time I click the set date button on the parent controller, the DateViewController appears, I pick the date from the datepicker control, and the controller is dismissed. In the parent view controller, dateViewControllerDismissed gets called and I set the receiptDate to the selectedDate parameter. The next time I click the date button, I get a bad access error where I set the DateViewController's selectedDate property to the receiptDate. I'm assuming this is some sort of memory issue that I'm not handling correctly. IOS programming is still new to me.
I have found several problems in your code which could lead your application to crash. Actually they are memory management problem.
Assigning autoreleased object to receiptDate:
receiptDate = [NSDate date];
when you will try to use this value later it will cause app crash because memory where receiptDate point could be already released. You could fix it by retaining the value:
receiptDate = [[NSDate date] retain];
and releasing in dealloc or anywhere you are changing it (I dont know how it is declared. It should be retain property).
You are assigning NSDate without retaining it:
receiptDate = selectedDate;
you could fix it by retaining:
receiptDate = [selectedDate retain];
I am sorry because I could not write all aspects of memory management in objective-C. It is better to use ARC if you don't know iOS memory managent well.
You could find a lot of useful information in this two guides from Apple: Advanced Memory Management Programming Guide and Memory Management Programming Guide for Core Foundation
Your property is never retained. What I would suggest to do would be to change the assign to retain in your property declaration. That'll solve your problem and you won't have to call retain everywhere you set selectedDate. The property will do that for you.
If you're not using ARC, don't forget to set the property to nil in your dealloc method, like so:
self.selectedDate = nil;
Note that I use self.selectedDate. It's important so that selectedDate is accessed as a property, not a variable.

Resources