I have one issue, if i adding event in calender through the app and if delete that added event from simuloter calendar delete button. Then it will also delete from app, is this possible?
Thanks
I am posting rough algorithm here to sync iCal events with the events stored in you app:
//model class for DB Events
#interface EventEntity
#property(strong) NSString *eventID;
#property(strong) NSString *eventText;
#end
NSMutableArray *dbEvents; //array of EventEntity objects
NSArray *iCalEvents; //array of events fetched from iCal
NSMutableArray *eventsToDelete = [NSMutableArray array]; //We will add events in this array, needed to be deleted from db.
for(EventEntity *entity in dbEvents) {
bool found = NO; //to keep track if this event has been found in iCal or not
for(EkEvent *event in iCalEvents) {
if([event.eventidentifier isEqualToString:entity.eventID]) {
found = YES; //event is present in Cal. Ignore and break
break;
}
}
if(!found) { //If not found, it means event has been deleted from iCal. Remove it from DB.
[eventsToDelete addObject:entity];
}
}
//Now delete items one by one from db
for(EventEntity *entity in eventsToDelete) {
//make query something like this: Delete event where EventID = entity.eventID
//after successful deletion, remove from dbEvents
[dbEvents removeObject:entity];
}
//refresh your UI for calendar/events if needed.
Hope it helps!
Related
I’ve created simple UITableView with couple of rows that is loading from Firebase.
On viewWillAppear I connect observer and populate the array with data.
The problem happens when view is already loaded but asynchronous Firebase callback is still wasn’t called - Table appears as blank.
The table refreshes after callback and looks like expected but the delay is still noticeable.
I’ve configured offline mode and expecting that observer’s handler should be called immidiately but it doesn’t.
What is the proper way to handle that?
Waiting bar looks like not the best option because it’s just 100ms or so and data is already on device and I have just 8 rows.
Is there any solution?
Thank you!
Observe code:
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
refHandle = [areasRef observeEventType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
[self.arrayOfAreas removeAllObjects];
for (FIRDataSnapshot* areaSnapshot in snapshot.children){
Area *area = [[Area alloc] init];
[area retrieveFromSnapshot:areaSnapshot];
[self.arrayOfAreas addObject:area];
} [self.tableView reloadData];
}]; }
viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
self.ref = [[FIRDatabase database] reference];
FIRUser *currentUser = [FIRAuth auth].currentUser;
areasRef = [[[_ref child:#"users"] child:currentUser.uid] child:#"areas"];
self.tableView.dataSource = self;
self.tableView.delegate = self;
self.tableView.tableFooterView = [[UIView alloc]init];
self.arrayOfAreas = [NSMutableArray new];
self.tableView.allowsMultipleSelectionDuringEditing = NO; }
After fresh install of your app,
Obviously there will be a delay to fetch the datas from firebase.
once you fetch all the data, you have to save it in your local DB.
From second time onwards, show the datas from your local DB and concurrently fetch the firebase DB also. (if you doesn't do update/delete in inner key values of the fetching path, firebase DB fetching query can be optimised based on the local data).
If you are saving the local DB datas to arrayOfAreas. you can change the observe block as follows
NSMutableArray *arrayTemp = [[NSMutableArray alloc]init];
for (FIRDataSnapshot* areaSnapshot in snapshot.children){
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Area" inManagedObjectContext:[CoreData sharedData].context];
Area *area = [[Area alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
[area retrieveFromSnapshot:areaSnapshot];
[arrayTemp addObject:area];
}
/**
if you are fetching all datas again
*/
self.arrayOfAreas = arrayTemp;
[self.tableView reloadData];
/**
if you are fetching only the datas that are newly added (datas that are not existing in local DB)
*/
[self.arrayOfAreas addObjectsFromArray: arrayTemp];
[self.tableView reloadData];
if you are using firebase offline feature, try below way. (it may not be a perfect solution)
invoke [FIRDatabase database].goOffline in viewDidLoad or app launch.
once the observer block executed, [FIRDatabase database].goOnline.
Your UITableview is getting loaded on viewDidLoad, as there would be no data in you array at initially your tableView is blank.
If you don't wish to load your tableView until the you retrieve data then you may assign your datasource and delegate after you finish fetching your records. (In your completion block of Firebase Method)
You can show loader till your data is retrieved.
The following code receives an array of events from EventKit for the selected day, then "pads" the existing calendar events with empty events to fill hourly slots from the entire day (9-5, for example).
The events coming from the iOS calendar are contained within a custom event container class that I created. The event class has the following properties:
// HDEvent.h
#interface HDEvent : NSObject
#property(nonatomic, copy) NSDate *startDate;
#property(nonatomic, copy) NSDate *endDate;
#property(nonatomic, strong) EKEvent *event;
#property(nonatomic, copy) NSString *eventIdentifier;
#property(nonatomic, copy) NSString *tempTitle;
#end
I am attempting to replace the empty events with any true events from the calendar, based on the start/end dates of the HDEvent object. The incoming array for the following method has the events (if any) from the device calendar.
- (NSArray *)addEmptyEventsWithEvents:(NSMutableArray *)events
ForDate:(NSDate *)date {
NSMutableOrderedSet *finalEvents = [[NSMutableOrderedSet alloc] init];
// this returns an array filled with the empty HDEvents
// for the expected date range.
NSArray *emptyEvents = [self getEventsTimeRangeFromDate:date];
for (HDEvent *emptyEvent in emptyEvents) {
HDEvent *eventToAdd;
for (HDEvent *event in events) {
NSLog(#"Event: %#", event.event.title);
if ([event.startDate isEqualToDate:emptyEvent.startDate] ||
[event.endDate isEqualToDate:emptyEvent.endDate])
{
eventToAdd = event;
} else {
eventToAdd = emptyEvent;
}
}
[finalEvents addObject:eventToAdd];
}
return [finalEvents array];
}
I am attempting to create an array with my events as illustrated in the pseudo-code below:
// Calendar Events
[
10:00-11:00 MEETING,
11:00-12:00 LUNCH
]
// Empty Placeholders
[
09:00-10:00 EMPTY,
10:00-11:00 EMPTY,
11:00-12:00 EMPTY,
12:00-01:00 EMPTY,
01:00-02:00 EMPTY,
02:00-03:00 EMPTY,
03:00-04:00 EMPTY,
04:00-05:00 EMPTY,
]
// Final desired result:
[
09:00-10:00 EMPTY,
10:00-11:00 MEETING,
11:00-12:00 LUNCH,
12:00-01:00 EMPTY,
01:00-02:00 EMPTY,
02:00-03:00 EMPTY,
03:00-04:00 EMPTY,
04:00-05:00 EMPTY,
]
[Problem]:
The problem is that the array returned only contains one event from the calendar (though I can see in the NSLog response that I have two events on that day)
If I swap the for loops around, then I get 9 events (again, only one from the calendar, and one duplicate empty event.)
Thank you #vikingosegundo.
I ended up implementing a custom comparison method in my class following the advice contained in this answer here: https://stackoverflow.com/a/877881/810360
I also extended it to be more flexible by utilizing the excellent DateTools by Matthew York found on GitHub: https://github.com/MatthewYork/DateTools
This was my final code:
-(BOOL)isEqualToEvent:(HDEvent*)event {
if (self == event) {
return YES;
}
if ([event.startDate isEqualToDate:self.startDate] &&
[event.endDate isEqualToDate:self.endDate]) {
return YES;
} else {
return NO;
}
}
-(BOOL)doesEventIntersectEvent:(HDEvent*)event {
DTTimePeriod *eventTimePeriod = [DTTimePeriod timePeriodWithStartDate:event.startDate endDate:event.endDate];
DTTimePeriod *selfTimePeriod = [DTTimePeriod timePeriodWithStartDate:self.startDate endDate:self.endDate];
if ([eventTimePeriod intersects:selfTimePeriod]) {
return YES;
} else {
return NO;
}
}
-(BOOL)doesEventContainEvent:(HDEvent*)event {
DTTimePeriod *eventTimePeriod = [DTTimePeriod timePeriodWithStartDate:event.startDate endDate:event.endDate];
DTTimePeriod *selfTimePeriod = [DTTimePeriod timePeriodWithStartDate:self.startDate endDate:self.endDate];
if ([eventTimePeriod contains:selfTimePeriod]) {
return YES;
} else {
return NO;
}
}
I have a Table View in Xcode that is being populated by information that the user of the application is saving to iCloud. So my problem here is that whenever the user does save their data the data that is saved is being added to the every bottom of the table view of data instead of at the top which is where I want it to be seen once it has been saved.The data that is being saved is being saved to an array which then populates the Table View, but I am not sure how to sort the array due to the fact new data is being added to it every so often. Here is the code for the array in which i am working with:
- (NSArray *)notes
{
if (_notes) {
return _notes;
}
_notes = [[[NSUbiquitousKeyValueStore defaultStore] arrayForKey:#"AVAILABLE_NOTES"] mutableCopy];
if (!_notes) _notes = [NSMutableArray array];
return _notes;
}
and the data is being saved by this action here:
- (IBAction)save:(id)sender {
// Notify the previouse view to save the changes locally
[[NSNotificationCenter defaultCenter] postNotificationName:#"New Note" object:self userInfo:[NSDictionary dictionaryWithObject:self.finalScore.text forKey:#"Note"]];
[self dismissViewControllerAnimated:YES completion:nil];
}
Thanks!
You can store an object to the array that includes a date/time (along with your note data) - you can then sort the array by that value to get them in created order or reverse created order.
The other option might be since items are always added at the end, simply read the array in reverse order when displaying in the table. This may be helpful:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html#//apple_ref/occ/instm/NSArray/reverseObjectEnumerator
In fact, look at all the methods on NSArray - some really good and useful stuff there.
Hope this helps.
I have an iOS app that pulls data from a server and persists it using CoreData. I have a UITableView that I am trying to populate with only select portions from a given core data attribute.
Before the table is populated I cycle through the data and pass what I want into a NSMutableArray. The problem is when I find an item I want it is not being added to the array.
I declare the array in my .h file like so...
#property (strong, nonatomic) NSMutableArray *theNewSource;
And Synthesize it in the .m file
#synthesize theNewSource = _theNewSource;
Here is the method...
-(NSMutableArray *)setDataSourceArray
{
for(int i = 0; i < rcount ; i++)
{
NSIndexPath *countingInteger = [NSIndexPath indexPathForItem:i inSection:0];
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:countingInteger];
NSString *action = [object valueForKey:#"theActionName"];
if (![action isEqual:#"Login"])
{
[_theNewSource addObject:action];
}
}
NSLog(#"the array is now %#",_theNewSource);
return _theNewSource;
}
I've set a breakpoint in the line [_theNewSource addObject:action]. I can see in the console that the variable action does have a value but it is never added to _theNewSource array... I'm sure this is Objective C 101 but I can't get it figured out. Please Help!
Have you even created your _theNewSource array? It seems like you haven't done the following:
_theNewSource = [[NSMutableArray alloc] init];
Make sure you are creating your instance before trying to use it.
You should use a predicate in the NSFetchedResultsController's fetchRequest directly:
[NSPredicate predicateWithFormat:#"theActionName != %#", #"Login"];
NSFetchResultsControllers are particularly useful for driving table views and collection views, so filtering their results to create a separate data source is a code smell.
Doing it this way means that you can use the NSFetchedResultsController directly as the data source for your table instead of using it to create a filtered array to act as the datasource.
I want that ,if the users taps a button, these tableCell should be added to a new tableView (where you can see your favorites).
I've one class Car where the content of the cars is synthesized:
#import "Car.h"
#implementation Car
#synthesize name;
#synthesize speed;
#synthesize selected;
#end
The CarsViewController contains a tableView where you can find each car:
#implementation CarsViewController {
NSArray *cars;
}
#synthesize tableView = _tableView;
- (void)viewDidLoad
{
Car *car1 = [Car new];
car1.name = #"A1";
car1.speed = #"200 km/h";
car1.selected = FALSE;
Car *car2 = [Car new];
car2.name = #"A2";
car2.speed = #"220 km/h";
car2.selected = FALSE;
cars = [NSArray arrayWithObjects:car1, car2, nil];
}
And finally the CarDetailViewController has the favorite-button.
And if you click on it the cell of these car should be added to a new ViewController (with TableView).
But what should I add to the method of CarDetailViewController?
- (IBAction)setFAV:(id)sender {
// don't know what to write here
}
Thanks in advance for all your answers.
UPDATE
So here is a little picture which shows how it should work.
In this method you need an array which hold all selected cars and u need to pass this array to newView controller there u use this array to show fav cars
Make your car array a NSMutableArray or create a new NSMutableArray with all your favourite cars and if the user clicks the button, add a new object to that array.
Then, this array should be the data source of your tableview and after adding a new object to the NSMutableArray do
[tableview reloadData];
Your Car class could have a BOOL isFavorite; and then on a selection in the first tableView you could set the isFavorite property for the car at the index selected to YES. Then, in your favorite table view, one option is to show only those cars in your list who have the isFavorite = YES.
There are many ways to do this, and since you haven't specified when or where you're going to be using your Favorites Table View, one solution that might work for you is to use NSUserDefaults.
When the user hits the favorite button (Assuming you've already created and initialized an array)
[favoritesArray addObject:Car1];
[[NSUserDefaults standardUserDefaults] setObject:favoritesArray forKey:#"favoriteCars"];
And then when you need to access this array to use as the data source for your Favorites TableView in another view controller:
NSMutableArray *array = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"favoriteCars"]];