I am trying to retrieve the updatedAt section of a parse object and displaying it as a label. I have created a date formatter yet when I convert it to a string it just becomes a null value. Here is the code:
- (void)viewDidLoad {
[super viewDidLoad];
PFQuery *BizarroTime = [PFQuery queryWithClassName:#"Bizarro"];
[BizarroTime getObjectInBackgroundWithId:#"MkoIkCBMdP" block:^(PFObject *Bizarro, NSError *error) {
NSDate *BizarroDate = Bizarro[#"updatedAt"];
NSDateFormatter *df = [NSDateFormatter new];
[df setDateFormat:#"MMMM dd 'at' HH:mm"];
self.BizarroUpdatedAt.text = [df stringFromDate:BizarroDate];
}];
}
Any help with this would be awesome! Thanks!
To make danh's message more concise for future answer-seekers, the updatedAt field of a Parse PFObject* object cannot be accessed as if it's a value in the object's dictionary, ex.:
object[#"updatedAt"];
But must instead be accessed using Parse's updatedAt method:
[object updatedAt];
You should check that the returned object is non-nil. If there is an object, the way to get it's updated date is via the PFObject method called updatedAt ...
[BizarroTime getObjectInBackgroundWithId:#"MkoIkCBMdP" block:^(PFObject *Bizarro, NSError *error) {
if (Bizarro) {
NSDate *BizarroDate = [Bizarro updatedAt];
// format as you have it
} else {
NSLog(#"%#", error);
}
}];
Related
I am trying to build an NSDictionary from an NSManagedObject. I was under the impression that you could do this with: NSMutableDictionary *myDict;
[myDict setObject:self.title forKey:#"title"];
}
Because a dictionary cannot hold nil values, I am testing for nil first. However, when I verify using a break that properties have values, when I build the dictionary it is nil. It shows as nil using a breakpoint and logs to console as NULL. Would appreciate someone confirming that the following is a valid way to create a dictionary and, if so, why the dictionary would be nil?
NSString *title = #"Test";
NSNumber *complete = #1;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy-MM-dd HH:mm:ss";
NSString *lasttouchedstr =[dateFormatter stringFromDate:[NSDate date]];
NSMutableDictionary *myDict;
if (self.title.length>=1) {
[myDict setObject:self.title forKey:#"title"];
}
if (![self.complete isKindOfClass:[NSNull class]]) {
[myDict setObject:self.complete forKey:#"complete"];
}
if (![self.lasttouched isKindOfClass:[NSNull class]]) {
[myDict setObject:lasttouchedstr forKey:#"lasttouchedstr"];
}
NSLog(#"myDict is:%#",myDict)//Logs as NULL
return myDict;
Thanks in advance for any suggestions.
NSMutableDictionary *myDict; declares the value but does not initialize it. You need
NSMutableDictionary *myDict = [[NSMutableDictionary alloc] init];
Secondly, managed objects will not be returning a value of NSNull for any of their attributes. You need to check for != nil instead. See here for a nice explanation of the differences between nulls and nils.
Hi I'm making a synchronise function that update database when receive JSON response from server. I want the import only take place if there are different data (new record or update existing record) (To increase performance) (Using coredata and magicalRecord)
Here is my JSON parser method
- (void)updateWithApiRepresentation:(NSDictionary *)json
{
self.title = json[#"Name"];
self.serverIdValue = [json[#"Id"] integerValue];
self.year = json[#"Year of Release"];
self.month = json[#"Month of Release"];
self.day = json[#"Day of Release"];
self.details = json[#"Description"];
self.coverImage = json[#"CoverImage"];
self.thumbnail = json[#"Thumbnail"];
self.price = json[#"Buy"];
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
[formatter setDateFormat:#"dd/MMMM/yyy"];
NSDate *date = [formatter dateFromString:[NSString stringWithFormat:#"%#/%#/%#",self.day,self.month,self.year]];
self.issueDate = date;
}
And my import method
+ (void)API_getStampsOnCompletion:(void(^)(BOOL success, NSError *error))completionBlock
{
[[ApiClient sharedInstance] getStampsOnSuccess:^(id responseJSON) {
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_context];
NSMutableArray *stamps = [[NSMutableArray alloc]init];
[responseJSON[#"root"] enumerateObjectsUsingBlock:^(id attributes, NSUInteger idx, BOOL *stop) {
Stamp *stamp = [[Stamp alloc]init];
[stamp setOrderingValue:idx];
[stamp updateWithApiRepresentation:attributes];
[stamps addObject:stamp];
}];
[Stamp MR_importFromArray:stamps inContext:localContext];
} onFailure:^(NSError *error) {
if (completionBlock) {
completionBlock(NO, error);
}
}];
}
I'm getting error
CoreData: error: Failed to call designated initializer on NSManagedObject class 'Stamp'
2016-08-02 23:52:20.216 SingPost[2078:80114] -[Stamp setOrdering:]: unrecognized selector sent to instance 0x78f35a30
I have checked my Json parser is working fine. The problem is with my import method. I don't know what wrong with the function. Any help is much appreciate. Thanks!
The error message clearly describes the exact problem. You do this:
Stamp *stamp = [[Stamp alloc]init];
But init is not the designated initializer for NSManagedObject unless you added init in your subclass (which you didn't mention doing). You must call the designated initializer, which is initWithEntity:insertIntoManagedObjectContext:. There's also a convenience factory method on NSEntityDescription called insertNewObjectForEntityForName:inManagedObjectContext:. Either of those will work, but calling init will not.
Okay. I am picking up this work from someone else and its hard to understand.
so lets say I am making an app that keeps track of visitors coming into a building.
What needs to determine is whether they are a current visitor or not, is the timestamp. If there is timeOut on parse is set to nil then they are still in the building. What logs the visitor out of the list is when the timestamp changes form nil to the current time.
I want a way to log all visitors out if they have forgotten to sign out.
with on button click, I should be able to log all visitors on a tableview list called current visitors. the button will look for all visitors in the parse class with the timeOut = nil, and will then create a current timestamp for all those nils, refreshing the table to show that they are all gone.
Here is what I have written so far. When the button is clicked, nothing happens.
- (IBAction)visitorLogOut:(UIButton *)sender {
if (![namesLabel.text isEqualToString:#"name"]){
PFQuery *query = [PFQuery queryWithClassName:#"VisitorTest"];
[query fromLocalDatastore];
[query whereKey:#"timeOut" equalTo:#"nil"];
[query findObjectsInBackgroundWithBlock:^(NSArray *visitors, NSError *error){
NSDateFormatter *dformat = [[NSDateFormatter alloc] init];
[dformat setDateFormat:#"dd/MM/yyyy HH:mm"];
NSDate *time = [NSDate date];
NSString *timeString = [dformat stringFromDate:time];
self.person[#"timeOut"] = timeString;
[self.person saveEventually];
[self.person unpinInBackground];
}
];}
}
Any help would be great. cheers!
Is this what you're looking for? First time around, it'll just show you the list of objects it received from the server. If that looks like what you want, you can then remove the return; and on next run it should set timeOut on all objects.
- (IBAction)visitorLogOut:(UIButton *)sender
{
PFQuery *query = [PFQuery queryWithClassName:#"VisitorTest"];
[query fromLocalDatastore];
[query whereKeyDoesNotExist:#"timeOut"];
[query findObjectsInBackgroundWithBlock:^(NSArray *visitors, NSError *error)
{
NSLog(#"received visitors: %#");
// remove this once you have confirmed that visitors contains exactly the users you want
return;
NSDateFormatter *dformat = [[NSDateFormatter alloc] init];
[dformat setDateFormat:#"dd/MM/yyyy HH:mm"];
NSDate *time = [NSDate date];
NSString *timeString = [dformat stringFromDate:time];
for (PFObject *visitor in visitors)
{
visitor[#"timeOut"] = timeString;
[visitor saveEventually];
}
}];
}
I have an NSMutableArray called self.objectArray, that contains custom objects. Each object holds an NSDictionary and two other string objects. Actually I need to work only with the dictionary. Every dictionary contains a key named keyDate which holds an NSString that look like this: MM/dd/yy HH:mm:ss.
I would like to sort the array based on their keyDate. The object with the oldest date should be the first object and so on. I've found some questions, that looked helpful and I could create the code that you can see below, but I get an error everytime I run it. As I think NSSortDescriptor won't be the right tool since my keys aren't key value compliant.
PNMessage 0x125c0590> valueForUndefinedKey:]: this class is not key value coding-compliant for the key keyDate.'
NSSortDescriptor *dateDescriptor = [NSSortDescriptor
sortDescriptorWithKey:#"keyDate"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:dateDescriptor];
NSArray *sortedEventArray = [self.objectArray
sortedArrayUsingDescriptors:sortDescriptors];
self.finallySorted = [sortedEventArray mutableCopy];
If it's possible I would do it with sort descriptor, however I think there should be some other options, but can't figure out its proper implementation.
So I can also catch every object's keyDate with a for loop, but don't know how can I sort them based on the value. I would really appreciate if somebody could show me the right way.
for(PNMessage *mg in self.objectArray)
{
NSLog(#" test log %#", mg.message[#"keyDate"]);
}
I already checked this answer:
How to sort an NSMutableArray with custom objects in it?
but the structure of my object is different.
My first code based on this question, but it doesn't worked.
How to sort an NSMutableArray with custom objects in it?
UPDATE: my try based on Kaan's answer (doesn't works yet)
static NSDateFormatter *formatter = nil;
if(!formatter) {
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM/dd/yy HH:mm:ss"];
}
NSArray *sortedArray = [self.object sortedArrayUsingComparator:^NSComparisonResult(PNMessage *obj1, PNMessage *obj2) {
NSString *date1String = obj1.message[#"keyDate"];
NSString *date2String = obj1.message[#"keyDate"];
NSDate *date1 = [formatter dateFromString:date1String];
NSDate *date2 = [formatter dateFromString:date2String];
if ( date1 < date2 ) {
return (NSComparisonResult)NSOrderedAscending;
} else if ( date1 > date2 ) {
return (NSComparisonResult)NSOrderedDescending;
}
return (NSComparisonResult)NSOrderedSame;
}];
I would consider using the sortedArrayUsingComparator method
Assuming your custom class is called PNMessage:
static NSDateFormatter *formatter = nil;
if(!formatter) {
formatter = [[NSDateFormatter alloc] init];
[formatter setFormat:#"MM/dd/yy HH:mm:ss"];
}
NSArray *sortedArray = [self.objectArray sortedArrayUsingComparator:^NSComparisonResult(PNMessage *obj1, PNMessage *obj2) {
NSString *date1String = obj1[#"keyDate"];
NSString *date2String = obj1[#"keyDate"];
NSDate *date1 = [formatter dateFromString:date1String];
NSDate *date2 = [formatter dateFromString:date2String];
return [date1 compare:date2];
}];
Tip: If you decide on following this, make sure you declare your NSDateFormatter instance as static outside of the sorting body, since allocating Formatters in iOS can be very expensive and cause serious performance penalties.
I am trying to search through a list of reminders in order to check if a reminder exists. There is an option in the method to save the value of whether or not the reminder exists. I am using a block, and within the block, when the reminder is found, the new value is assigned to the reminderExists variable, like it is supposed to. However, when I enter the save if statement, the value of reminderExists has changed from what it was assigned in the block. I am stumped with this issue, and I have tried many changes to diagnose the problem, to no avail. Thanks for any help!
- (BOOL)checkForReminderWithTitle:(NSString *)reminderTitle saveChanges:(BOOL)save {
NSNumber *currentGardenCurrentReminders = currentGarden.reminders;
__block NSNumber *reminderExists = [NSNumber numberWithBool:NO];
if (eventStore == nil)
{
eventStore = [[EKEventStore alloc] init];
[eventStore requestAccessToEntityType:EKEntityTypeReminder completion:^(BOOL granted, NSError *error) {
if (!granted)
NSLog(#"Access to store not granted");
}];
}
if (eventStore != nil) {
NSPredicate *predicate = [eventStore predicateForIncompleteRemindersWithDueDateStarting:[NSDate distantPast] ending:[NSDate distantFuture] calendars:[NSArray arrayWithObject:[eventStore defaultCalendarForNewReminders]]];
[eventStore fetchRemindersMatchingPredicate:predicate completion:^(NSArray *reminders) {
for (EKReminder *reminder in reminders) {
NSLog(#"%#", reminderTitle);
if ([reminder.title isEqualToString:reminderTitle]) {
reminderExists = [NSNumber numberWithBool:YES];
NSLog(#"reminder exists");
NSLog(#"after reminder exists is assigned to YES, value is %#", ([reminderExists boolValue]) ? #"True" : #"False");
if ([reminderExists boolValue]) NSLog(#"reminder exists variable works");
NSArray *alarms = reminder.alarms;
EKAlarm *alarm = [alarms objectAtIndex:0];
NSDateFormatter *nextReminderDateFormatter = [[NSDateFormatter alloc] init];
nextReminderDateFormatter.dateFormat = #"MM/dd/yyyy at hh:mm a";
NSString *nextReminderDateString = [nextReminderDateFormatter stringFromDate:alarm.absoluteDate];
NSLog(#"Next reminder is on %#", nextReminderDateString);
break;
}
}
}];
}
if (save && ([currentGardenCurrentReminders boolValue] != [reminderExists boolValue])) {
if ([reminderExists boolValue]) {
NSLog(#"within save, reminderexists == true");
} else NSLog(#"within save, reminderexists == false");
currentGarden.reminders = reminderExists;
[self.managedObjectContext save:nil];
}
return [reminderExists boolValue];
}
The call to fetchRemindersMatchingPredicate:completion: is asynchronous. This means that your if statement after this call is actually being done long before the call to fetchRemindersMatchingPredicate:completion: is complete.
You can't have a useful return value in a method that does asynchronous processing. You need to change your checkForReminderWithTitle:saveChanges: method to return void and instead have it pass a completion block that will be called when the call to fetchRemindersMatchingPredicate:completion: is done.
BTW - why is reminderExists an NSNumber pointer and not just a BOOL?
The call to [EKEventStore fetchRemindersMatchingPredicate:completion:] is asynchronous. So when you check the value of reminderExists below the completion block, the completion block may not have executed yet, and reminderExists may not yet have the correct value.
To fix the problem, put your check code in the end of the completion block. As #rmaddy correctly points out, this function can't return a value, since it relies on an async call.