I have the following code:
-(NSString *)tableView:(UITableView *)table titleForHeaderInSection:(NSInteger)section {
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
NSDateFormatter* dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *sectionName = [sectionInfo name];
NSLog(#"sectionName %#", sectionName);
NSString *convDate = [dateFormatter stringFromDate: (NSDate *)sectionName];
NSLog(#"convDate %#", convDate);
return [NSString stringWithFormat:#"%#", [sectionInfo name]];
}
I am basically needing to convert the titleforheaderinsection which is a string date like "2009-12-04 00:00:00 +1100" to a nicer looking shorter string. So I have tried converting it using something like dateFormatter setDateStyle, but when i output the NSLog to console i get the following:
2009-12-22 09:42:10.156 app[94614:207] sectionName 2009-12-04 00:00:00 +1100
2009-12-22 09:42:10.157 app[94614:207] convDate (null
Obviously the convDate is not getting anything, but [sectionInfo name] should be a string. I have parsed it into its own NSString variable, so why cant i implement the dateFormatter on it?
A bit more information: I parse the date amongst other things earlier on, with the code snippet being:
if ([currentElement isEqualToString: #"date"]) {
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init] ;
[dateFormatter setDateFormat:#"eee, dd MMM yyyy"];
NSDate *convDate = [dateFormatter dateFromString:string];
if (self.isComment){
[currentComment setDate: convDate];
}else if (self.isPost)
NSLog(#"convDate is %#", convDate);
[currentPost setDate: convDate];
Now, when I debug this, essentially the raw string is "Sat, 27 Nov 2009 17:16:00 -800" but when i look at the convDate it comes out to be "2009-11-27 00:00:00 +1100". Not sure why, but in any case, thats what gets stored. I would have thought it would match the style i mentioned, so if i change the dateFormatter format to any other type, it would stuff up and convDate become nil.
Looking back at my postController: I have some snippets of interest:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
[fetchRequest setEntity:[NSEntityDescription entityForName:#"Post" inManagedObjectContext: ApplicationController.sharedInstance.managedObjectContext]];
NSArray *sortDescriptors = nil;
NSString *sectionNameKeyPath = #"date";
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:#"(PostSite.name like '%#')", self.site.name]];
[fetchRequest setPredicate:pred];
sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc]
initWithKey:#"date" ascending:NO] ];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:
ApplicationController.sharedInstance.managedObjectContext
sectionNameKeyPath:sectionNameKeyPath cacheName:#"PostCache"];
}
return fetchedResultsController;
}
I am hoping to sort by date, and up in my code, in titleForHeaderInSection, format my string date to look more presentable.
Thanks guys
The reason you were getting unexpected behaviour is because during parsing you were setting the date format to
[dateFormatter setDateFormat:#"eee, dd MMM yyyy"];
which has no time information, which is why there was a time difference in the dates.
Also, during parsing you were setting convDate with
NSDate *convDate = [dateFormatter dateFromString:string];
which is storing an NSDate and crucially NSFetchResultsController is calling the description selector on convDate because it is not an NSString.
I'm not entirely sure why NSDateFormatter could not recognise the ISO date format.
The reason your code does not work is because
[sectionInfo name]
returns an NSString object, not an NSDate object, which is required by
[dateFormatter stringFromDate:];
You cannot simply cast an NSString to an NSDate.
Instead,
- (NSString *)tableView:(UITableView *)table titleForHeaderInSection:(NSInteger)section
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
NSString *sectionName = [sectionInfo name];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
NSString *convDate = [dateFormatter stringFromDate:[dateFormatter dateFromString:sectionName]];
[dateFormatter release];
return convDate;
}
Also, don't autorelease an object unless there is a specific reason to do so.
I found the solution by going to http://iosdevelopertips.com/cocoa/date-formatters-examples-take-2.html and using http://unicode.org/reports/tr35/#Date_Format_Patterns as a guide, I debugged my code until i ensured that the variable is matched with the incoming string
Related
My method receives a Dictionary named responseDict which contains keys, such as id, status, name, phoneNumber, date etc. in
responseDict[#"data"][#"value"][n]
(n for number)
If our code uses NSUserDefaults to access data:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
How can I change the date MySQL attribute 2017-05-12 10:00:00 to Dec 5, 2017 10 AM?
I tried the following, but it does not seem to change the defaults in the UILabel.
[defaults setInteger:[dictionary[#"id"] integerValue] forKey:#"ID"];
[defaults setObject:dictionary[#"status"] forKey:kNSUDoctorStatus];
[defaults setInteger:[dictionary[#"dur"] integerValue] forKey:#"duration"];
[defaults setObject:[NSString stringWithFormat:#"%# some",dictionary[#"date"]] forKey:#"date"];
[defaults synchronize];
Edit:
UILabel
The UILabel seems to have been added to the view by:
UILabel *vb = (UILabel *)[self.view viewWithTag:personMessageViewTag];
which was defined by:
#define personMessageViewTag 3001
Doctor Class
There is also a PersonDetailView class initialized:
PersonDetailView *personOnTheView;
And called in a method:
personOnTheView = [PersonDetailView sharedInstance];
personOnTheView.delegate = self;
[personOnTheView updateValues];
[self.view addSubview:personOnTheView];
Method:
Here is the code for [personOnTheView updateValues]
-(void)updateValues{
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSString *strImageUrl = [NSString stringWithFormat:#"%#%#",baseUrlForXXHDPIImage,[ud objectForKey:kOnGoingBookingPersonProfileImageKey]];
_doctorName.text = [ud objectForKey:kOnGoingBookingPersonNameKey];
NSString *at = [NSString stringWithFormat:#"%#",flStrForObj([Helper getLocalDate:[ud objectForKey:kOnGoingBookingPersonBookingDate]])];
_appoinmentTime.text = at;
float rating = [[ud objectForKey:kOnGoingBookingPersonRatingKey] floatValue];
_starRatingView.value = rating;
[_profilepic sd_setImageWithURL:[NSURL URLWithString:[Helper removeWhiteSpaceFromURL:strImageUrl]]
placeholderImage:[UIImage imageNamed:#"doctor_image_thumbnail"]
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL){
}];
}
Problem:
Everytime I change or modify:
[defaults setObject:dictionary[kPNPayloadAppoinmentTimeKey] forKey:kOnGoingBookingPersonBookingDate];
To:
[defaults setObject:[NSString stringWithFormat:#"%# some",dictionary[#"date"]] forKey:#"date"];
or just as simple as:
[defaults setObject:#"Something here" forKey:#"date"];
It displays blank.
Additional Information Edit:
[Helper getLocalDate] code:
+(NSString *)getLocalDate:(NSString *)gmtdate {
NSString *dateStr = gmtdate;
NSDateFormatter *dateFormatter1 = [[NSDateFormatter alloc] init];
[dateFormatter1 setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSDate *destinationDate = [dateFormatter1 dateFromString:dateStr];
NSDateFormatter *dateFormatters = [[NSDateFormatter alloc] init];
[dateFormatters setDateFormat:#"MMM d, yyyy HH a"];
dateStr = [dateFormatters stringFromDate: destinationDate];
// NSLog(#"DateString : %#", dateStr);
return dateStr;
}
With the help of this method you can get the date in local format if you having time zone in date string
-(NSDate*)convertDateToLocal:(NSString *)strDate
{
NSDateFormatter *localFormat = [[NSDateFormatter alloc] init];
[localFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss z"];
NSDate *localDate = [localFormat dateFromString:strDate];
return localDate;
}
Here are two public method for date conversion if you don't have time zone
1) Date from string,
+ (NSDate *)dateFromString:(NSString *)strSource inFormat:(NSString *)strTargetFormat
{
NSDateFormatter *dtfFormatter = [[NSDateFormatter alloc] init];
[dtfFormatter setDateFormat:strTargetFormat];
return [dtfFormatter dateFromString:strSource];
}
2) String from date,
+ (NSString *)stringFromDate:(NSDate *)dtSourceDate inFormat:(NSString *)strTargetFormat
{
NSDateFormatter *dtfFormatter = [[NSDateFormatter alloc] init];
[dtfFormatter setDateFormat:strTargetFormat];
if (dtSourceDate != nil)
return [dtfFormatter stringFromDate:dtSourceDate];
else
return #"";
}
Hope this helps.
i am working on an expense tracker kind of application.i am able to store and retrieve sorted data perfectly using coredata.
i am storing date.i am able to retrieve date in a sorted order.but i want to the date in the section header and related data in that table.
ex:
Dec 31st 2011 ---------> Section Header
xxxxxxx yyyyyy ----->cell with labels
Jan 1st 2012---------->Section Header
xxxxxxx yyyyyy ------>cell with labels.
i am able to receive the dates in a sorted order.but how to display them in a section header in a sorted order and how to declare the number of sections in tableView-noOfSections method?
//Code i used for retrieving data.
- (void)viewDidLoad
{
AppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"NewExpense" inManagedObjectContext:context];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc]init];
NSSortDescriptor *date = [[NSSortDescriptor alloc]initWithKey:#"date" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc]initWithObjects:date,nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setEntity:entityDesc];
NSError *error;
self.listOfExpenses = [[context executeFetchRequest:fetchRequest error:&error]retain] [fetchRequest release];
[super viewDidLoad];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;// as of now i have taken one.
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
[self.listOfExpenses count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//labels are created and added to the cell's subview.
NSManagedObject *records = nil;
records = [self.listOfExpenses objectAtIndex:indexPath.row];
self.firstLabel.text = [records valueForKey:#"category"];
NSString *dateString = [NSString stringWithFormat:#"%#",[records valueForKey:#"date"]];
NSString *dateWithInitialFormat = dateString;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss Z"];
NSDate *date = [dateFormatter dateFromString:dateWithInitialFormat];
[dateFormatter setDateFormat:#"dd-MM-yyyy"];
NSString *dateWithNewFormat = [dateFormatter stringFromDate:date];
self.secondLabel.text = dateWithNewFormat;
NSString *amountString = [NSString stringWithFormat:#"%#",[records valueForKey:#"amount"]];
self.thirdLabel.text = amountString;
totalAmount = totalAmount + [amountString doubleValue];
}
Date in the section header is a bit tricky, but there is very good sample code from Apple out there which I am using in one of my current apps successfully. Look at DateSectionTitles.
In short, you need to use a NSFetchedResultsController and define the sectionNameKeyPath with a separate property of your entity (the date itself won't do because it is accurate to the second). In numberOfSections you will have to return whatever the fetched results controller gives you, not 1 as above. numberOfRowsInSection will have to be adjusted as well, you get the idea.
Apple calculates a primitive date and reconstructs it when it has to format the string for the section header. All pretty straight forward. Just follow the sample code and you have solved this in no time.
You can use NSSortDescriptor:
NSFetchRequest *request = [[NSFetchRequest alloc] init];
...
NSSortDescriptor * sort = [[NSSortDescriptor alloc] initWithKey:sortingKey ascending:ascending];
NSArray * sortDescriptors = [NSArray arrayWithObject: sort];
[request setSortDescriptors:sortDescriptors];
as sortingKey you will pass in your case date.
See docs on NSSortDecsriptor here:
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSSortDescriptor_Class/Reference/Reference.html
I have a NSMutableArray with dictionaries, all of the dict's contain a NSDate is form of NSString with key 'Date'. I want to sort the NSDictionaries by the Dates. So for example i have the following state of the array:
Dict
Date
20.06.1996 23:30
Dict
Date
04.10.2011 19:00
Dict
Date
20.06.1956 23:39
And I want to sort it, so that it looks like this:
Dict
Date
20.06.1956 23:39
Dict
Date
20.06.1996 23:30
Dict
Date
04.10.2011 19:00
I have already experimented with NSSortDescriptor, but without success...
Update:
I have managed to sort the dates, but I came to this problem: In the dicts there is not only dates, also other objects, and what my code does is it only switches the date values between the dicts, instead of switching the complete dicts around. With this, the other values in the dicts get assigned a wrong date, which is very bad. Can anybody help me? Heres my code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"savedData.daf"];
NSMutableArray *d = [NSMutableArray arrayWithContentsOfFile:path];
for (int ii = 0; ii < [d count]; ii++) {
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
if (is24h) {
[dateFormatter setDateFormat:#"dd.MM.yyyy HH:mm"];
}
else {
[dateFormatter setDateFormat:#"dd.MM.yyyy hh:mm a"];
}
[dateFormatter setLocale:[NSLocale currentLocale]];
NSDate *dat = [dateFormatter dateFromString:[[d valueForKey:#"Date"] objectAtIndex:ii]];
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
NSDictionary *oldDict = (NSDictionary *)[d objectAtIndex:ii];
[newDict addEntriesFromDictionary:oldDict];
[newDict setObject:dat forKey:#"Date"];
[d replaceObjectAtIndex:ii withObject:newDict];
[newDict release];
}
NSSortDescriptor *sorter = [[NSSortDescriptor alloc] initWithKey:#"Date" ascending:YES];
NSArray *sorters = [[NSArray alloc] initWithObjects:sorter, nil];
[sorter release];
NSMutableArray *sorted = [NSMutableArray arrayWithArray:[d sortedArrayUsingDescriptors:sorters]];
[sorters release];
NSLog(#"%#",sorted);
for (int ii = 0; ii < [sorted count]; ii++) {
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
if (is24h) {
[dateFormatter setDateFormat:#"dd.MM.yyyy HH:mm"];
}
else {
[dateFormatter setDateFormat:#"dd.MM.yyyy hh:mm a"];
}
[dateFormatter setLocale:[NSLocale currentLocale]];
NSString *sr = [dateFormatter stringFromDate:[[sorted valueForKey:#"Date"] objectAtIndex:ii]];
NSMutableDictionary *newDict = [[NSMutableDictionary alloc] init];
NSDictionary *oldDict = (NSDictionary *)[d objectAtIndex:ii];
[newDict addEntriesFromDictionary:oldDict];
[newDict setObject:sr forKey:#"Date"];
[sorted replaceObjectAtIndex:ii withObject:newDict];
[newDict release];
}
NSLog(#"before: %#"
""
"after: %#",d,sorted);
[sorted writeToFile:path atomically:YES];
There are many ways to do this, one would be to use NSDate objects instead of NSStrings (or NSStrings formatted according to ISO 8601, so that the lexicographic sort would match the desired sorting). Then you could do:
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"Date"
ascending:YES];
[array sortUsingDescriptors:[NSArray arrayWithObject:descriptor]];
Or, if you can't (or don't want to) change your data, you can always sort using a block:
[array sortUsingComparator:^(id dict1, id dict2) {
NSDate *date1 = // create NSDate from dict1's Date;
NSDate *date2 = // create NSDate from dict2's Date;
return [date1 compare:date2];
}];
Of course this would probably be slower than the first approach since you'll usually end up creating more than n NSDate objects.
There are a couple of options, one is to put NSDate objects in the dictionary.
One problem with comparing the strings is that you can 't just do a string compare because the year is not in the most significant potion of the string.
So, you will need to write a comparison method to use with:
- (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr
or perhaps:
- (NSArray *)sortedArrayUsingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context
The comparator will need to handle the dd.mm.yyyy hh:mm string format.
Other options include adding another dictionary key with an NSDate representation and sorting on that.
I am running instruments and it keeps saying that there is a 100% leak on the NSString *date = [df2 stringFromDate:dt]; line. I look at examples from apple and they are basically doing the same thing. Can anyone tell me what I am doing wrong or if the instruments are wrong.
+(NSString *) shortDateToLongDateString:(NSString *) dtString
{
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd"];
NSDate *dt = [df dateFromString:dtString];
[df release];
NSDateFormatter *df2 = [[NSDateFormatter alloc] init];
[df2 setDateFormat:#"EEEE MMMM d, yyyy"];
NSString *date = [df2 stringFromDate:dt];
[df2 release];
return date;
}
I am calling the method as follows:
for (NSString * dt in uniqueDates)
{
NSString *longDate = [NSString stringWithString:[NSDateHelper shortDateToLongDateString:dt]];
//Do something with the result...
}
My guess is that the function is being executed in a secondary thread that doesn't have an active NSAutoreleasePool. If you look in the console log you'll probably find "just leaking" warnings printed (though without anything in the way of info on where the leak is).
Implement the method more or less like this:
+(NSString *) shortDateToLongDateString:(NSString *) dtString
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd"];
NSDate *dt = [df dateFromString:dtString];
[df release];
NSDateFormatter *df2 = [[NSDateFormatter alloc] init];
[df2 setDateFormat:#"EEEE MMMM d, yyyy"];
NSString *date = [df2 stringFromDate:dt];
[df2 release];
[date retain];
[pool drain];
return [date autorelease];
}
I have a NSArray, and I sort it by its object's "published" property in descending order, newest first:
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"published" ascending:YES];
NSArray *descps = [[NSArray alloc] initWithObjects:[sortDescriptor reversedSortDescriptor], nil];
[storiesLocal sortUsingDescriptors:descps];
[descps release];
[sortDescriptor release];
So now, I want to split this array up by each day, so that I can use it with a UITableView. In my example each date would be a tableview section header.
So if my example sorted array (storiesLocal) had dates like such:
2010-04-05 10:32:00
2010-04-05 06:20:12
2010-04-02 09:23:02
2010-04-02 03:20:34
2010-04-01 04:22:34
Then I would have tableview headers like "April 5", "April 2", "April 1". Therefore each would have 2, 2 and 1 row under each corresponding header
Essentially, my wanted outcome would be an NSDictionary. It's each key would be a date (2010-04-02), each value would be an NSArray of the correct objects to go with it. All of these should be sorted by date. Newest first.
I've gone through about 3 tries and failed every time, ending up deleting the code I wrote.
Edit: since an NSDictionary is an unordered list, it might be better to have an array of dictionaries, each dict including a key for the date and a key for the stories array, since order is very important.
This isn't tested, but try something like:
NSArray *descps as above.
NSDateFormatter *in_formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"YYYY-MM-dd HH:mm:ss"];
NSDateFormatter *out_formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MMMM d"];
NSString *todayStr =
[formatter release];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
for (ObjectType *obj in descps) {
NSDate *date = [in_formatter dateFromString:[obj published]];
NSString *day = [out_formatter stringFromDate:date];
NSArray *array = [dict valueForKey:day];
if (array == nil) {
array = [[NSMutableArray alloc] init];
[dict setValue:array forKey:day];
[array release];
}
[array addObject:obj];
}
[in_formatter release];
[out_formatter release];