When I create an event:
EKEvent *newEvent = [EKEvent eventWithEventStore:self.store];
newEvent.title = title;
newEvent.startDate = startDate;
newEvent.endDate = finishDate;
newEvent.location = location;
EKAlarm *alarm = [EKAlarm alarmWithRelativeOffset:hoursOffSet * 60 * 60];
[newEvent addAlarm:alarm];
newEvent.calendar = cal;
BOOL eventSaved = [self.store saveEvent:newEvent span:EKSpanFutureEvents commit:YES error:error];
NSLog(#"identifier %#",newEvent.eventIdentifier);
if (!eventSaved) {
if(!cal)
{
*error = [NSError errorWithDomain:#"ASTEventStore" code:CALENDAR_NOT_FOUND_CODE_ERROR userInfo:NULL];
}
NSLog(#"Event didn't save in calendar %#",errorSavingInCalendar);
}
It usually works right, but I have discovered that sometimes it's saving the event and it doesn't get any error, but I can't see the event in the calendar App, actually I can't see the calendar created neither.
When I save the event in the device I always get its id in the Organizer-> Console in this way:
: identifier /The same id than the newEvent.eventIdentifier/
Do you know what does that warning means?
////Update
Well, I noticed that when the app save the EKEvent and the warning message is shown, another message is shown too:
: 2014-08-12 10:32:28.153|17|0x178e6d500: Region monitoring not available or enabled. Trigger ignored!
I tried too google it, but I didn't find out anything.
Any ideas?
Thanks :)
Well I think I found the solution, the problem was when I was creating the calendar I was getting the source in a wrong way: (from: how do I create a new EKCalendar on iOS device?)
// find local source for example
EKSource *localSource = nil;
for (EKSource *source in self.store.sources)
{
if (source.sourceType == EKSourceTypeLocal) // or another source type that supports
{
localSource = source;
break;
}
}
if (!localSource) {
NSLog(#"Local source is not available");
if (error) {
*error = [NSError errorWithDomain:#"ASTEventStore" code:CALENDAR_ACCOUNT_NOT_TYPE_LOCAL userInfo:NULL];
}
}
else{
cal = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:self.store];
cal.title = #"Calendar";
cal.source = self.store.defaultCalendarForNewEvents.source;
cal.CGColor = [UIColor blueColor].CGColor;
NSError *calendarError;
BOOL calendarSaved = [self.store saveCalendar:cal commit:YES error:&calendarError];
if (!calendarSaved) {
NSLog(#"calendar didn't saved %#",calendarError);
}
NSLog(#"cal id = %#", cal.calendarIdentifier);
//We save the calendar ID
calendarId = cal.calendarIdentifier;
[defaults setObject:calendarId forKey:#"calendarId"];
BOOL saved = [defaults synchronize];
if (!saved) {
NSLog(#"CALENDAR_ID didn't saved");
}
}
Now I getting from defaultCalendarForNewEvents:
cal = [EKCalendar calendarForEntityType:EKEntityTypeEvent eventStore:self.store];
cal.title = #"Calendar";
cal.source = self.store.defaultCalendarForNewEvents.source;
cal.CGColor = [UIColor blueColor].CGColor;
NSError *calendarError;
BOOL calendarSaved = [self.store saveCalendar:cal commit:YES error:&calendarError];
if (!calendarSaved) {
NSLog(#"calendar didn't saved %#",calendarError);
}
NSLog(#"cal id = %#", cal.calendarIdentifier);
if (!saved) {
NSLog(#"CALENDAR_ID didn't saved");
}
I tested and it's working great in iOS7.
I hope this help to someone :)
Related
This working perfectly in iOS 8.
But creating issue in iOS 9.Here is code :
self.eventManager.eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
// Create a new calendar.
EKCalendar *calendar = [EKCalendar calendarForEntityType:EKEntityTypeEvent
eventStore:self.eventManager.eventStore];
// Set the calendar title.
calendar.title = #"<APP name>";
calendar.CGColor=APP_Blue_COLOR.CGColor;
// Find the proper source type value.
for (int i=0; i<self.eventManager.eventStore.sources.count; i++) {
EKSource *source = (EKSource *)[self.eventManager.eventStore.sources objectAtIndex:i];
EKSourceType currentSourceType = source.sourceType;
if (currentSourceType == EKSourceTypeLocal) {
calendar.source = source;
break;
}
}
// Save and commit the calendar.
NSError *error;
[self.eventManager.eventStore saveCalendar:calendar commit:YES error:&error];
// If no error occurs then turn the editing mode off, store the new calendar identifier and reload the calendars.
if (error == nil) {
// Turn off the edit mode.
// Store the calendar identifier.
[self.eventManager saveCustomCalendarIdentifier:calendar.calendarIdentifier];self.eventManager.selectedCalendarIdentifier=calendar.calendarIdentifier;//chirag
}
else{
// Display the error description to the debugger.
NSLog(#"CREATE_CALENDER %#", [error localizedDescription]);
}
}
else
{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"" message:#"Please give permission to access your iPhone calender." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
}];
It give me success message but not creating my app calendar in iPhone calendar.
I though that it does not showing it due to no event set to it.so I also tried to set new event.
But it give me following code & error while creating new event.
// Create a new event object.
EKEvent *event = [EKEvent eventWithEventStore:self.eventManager.eventStore];
// Set the event title.
event.title = title;
// Set its calendar.
event.calendar = [self.eventManager.eventStore calendarWithIdentifier:self.eventManager.selectedCalendarIdentifier];
// Set the start and end dates to the event.
event.startDate = startDate;
event.endDate = endDate;
// Save and commit the event.
NSError *error;
if ([self.eventManager.eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&error]) {
// Call the delegate method to notify the caller class (the ViewController class) that the event was saved.
return true;
}
else{
// An error occurred, so log the error description.
NSLog(#"%#", [error localizedDescription]);
return false;
}
It give following error internally however it return will in NSError object:
Error getting shared calendar invitations for entity types 3 from daemon: Error Domain=EKCADErrorDomain Code=1014 "(null)"
The problem is that when iCloud calendars switched on, it hides the locally created ones from the calendar app. To bypass this problem the solution is to add a new calendar to iCloud source:
for (EKSource *source in self.eventStore.sources)
{
if (source.sourceType == EKSourceTypeCalDAV &&
[source.title isEqualToString:#"iCloud"]) //This is a patch.
{
localSource = source;
break;
}
}
if (localSource == nil)
{
for (EKSource *source in self.eventStore.sources)
{
if (source.sourceType == EKSourceTypeLocal)
{
localSource = source;
break;
}
}
}
I am having issue with coredata saving in background. I am implementing the following model :
MasterManagedObject (of type NSPrivateQueueConcurrencyType)
MainManagedObjectContext (of type NSMainQueueConcurrencyType & is child of MasterManagedObject)
TemporaryManagedObjectContext (of type NSPrivateQueueConcurrencyType & is child of MainManagedObjectContext)
Code is :
- (NSManagedObjectContext *)masterManagedObjectContext {
if (_masterManagedObjectContext) {
return _masterManagedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self storeCoordinator];
if (coordinator != nil) {
dime(#"Here in master context");
_masterManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_masterManagedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _masterManagedObjectContext;
}
- (NSManagedObjectContext *)mainManagedObjectContext {
if (_mainManagedObjectContext) {
return _mainManagedObjectContext;
}
_mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainManagedObjectContext setParentContext:self.masterManagedObjectContext];
return _mainManagedObjectContext;
}
+ (NSManagedObjectContext *)temporaryWorkerContext {
NSManagedObjectContext *tempMOContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
tempMOContext.parentContext = [[DDPersist manager] mainManagedObjectContext];
return tempMOContext;
}
Saving contexts:
+ (void)saveTempContext:(NSManagedObjectContext *)context {
NSError *error;
[context save:&error];
if (!error) {
[[DDPersist manager] saveMainContext];
dime(#"Temp Context Saved");
} else {
dime(#"Temp Context Error = %#",error);
}
}
- (void)saveMainContext {
[[[DDPersist manager] mainManagedObjectContext] performBlock:^{
NSError *error = nil;
[[[DDPersist manager] mainManagedObjectContext] save:&error];
if(!error){
//Write to disk after saving on the main UI context
[[DDPersist manager] saveMasterContext];
dime(#"main Context Saved");
} else {
dime(#"Main Context Error = %#",error);
}
}];
}
- (void)saveMasterContext {
[self.masterManagedObjectContext performBlock:^{
NSError *error = nil;
[self.masterManagedObjectContext save:&error];
if(error){
dime(#"Master Context Saved");
} else {
dime(#"Master Context Error %#", error);
if([NSThread isMainThread]) {
dime(#"Master Context Error NOT ON BACKGROUND CONTEXT! WILL AUTOMATICALLY PERSIST ON MAIN CTX!");
}
}
}];
}
I am using above to create new spaceChecklistItems objects in background thread as below :
//space is parent of spaceCheckListItem with one to many relationship.
__block NSManagedObjectID *spaceObjectID = [space objectID];
//Background thread starts here
[DDPersist performTaskOnBackgroundCtxWithParentChildScheme:^(NSManagedObjectContext *bgCtx) {
Space *localSpace = (Space*)[bgCtx objectWithID:spaceObjectID];
for(NSDictionary * spaceChecklistItemDict in spaceChecklistItems) {
SpaceChecklistItem * spaceChecklistItem = [SpaceChecklistItemService importSpaceChecklistItem:spaceChecklistItemDict space:localSpace];
NSAssert(spaceChecklistItem, #"invalid SpaceChecklistItem at import!");
if(!spaceChecklistItem) continue;
}
[bgCtx obtainPermanentIDsForObjects:bgCtx.insertedObjects.allObjects error:nil];
[DDPersist saveTempContext:bgCtx];
}];
The method(importSpaceChecklistItem) used in the background context is as under :
+ (SpaceChecklistItem*)importSpaceChecklistItem:(NSDictionary*)itemDict space:(Space*)space {
NSNumber *spaceChecklistItemId = [itemDict objectForKey:#"id"];
NSString * inspectionStatus ;
if ([itemDict objectForKey:#"inspectionStatus"]) {
inspectionStatus = [itemDict objectForKey:#"inspectionStatus"];
} else {
inspectionStatus = #"UNDECIDED";
}
NSString * notes = [itemDict objectForKey:#"notes"];
MOC * ctx = space.managedObjectContext;
SpaceChecklistItem * spaceChecklistItem = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([SpaceChecklistItem class])
inManagedObjectContext:ctx];
spaceChecklistItem.spaceChecklistItemId = spaceChecklistItemId;
spaceChecklistItem.space = space;// This is the relationship saving & not working.
spaceChecklistItem.inspectionStatus = inspectionStatus;
spaceChecklistItem.notes=notes;
spaceChecklistItem.sync = #NO;
return spaceChecklistItem;
}
The main issue is performance issue. I want to speedup for loop : for(NSDictionary * spaceChecklistItemDict in spaceChecklistItems) from the above. And want to all the processing into background. This for loop might contain more than 50000 iterations. which usually take time(about 3 minutes) to save into coredata.Data is saving if i use a single thread & keep for loop in the single thread child of main(not the master context) . But this one to many relationship giving me issues & i am struggling with it for a long.
I read many stackoverflow questions & many othe articles . But cant get this sort out. Any help will be appreciated.
Have you run Instruments?
Run the Time Profiler and look at what is taking the most amount of time.
Post that trace to your question so that others can see it as well.
I am new to game centre and I am building multiplayer game. I have different users in my tableview; now I want to send an invite for a match to a specific user. For sending the invitation I am using this code:
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
request.playersToInvite = [[NSArray alloc] initWithObjects:player.playerId, nil];
request.inviteMessage = #"Your Custom Invitation Message Here";
request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse response)
{
[self updateUIForPlayer: playerID accepted: (response == GKInviteeResponseAccepted)];
};
But how to receive that invitation? I think I have to implement a method for this in GameKitHelper class but I am not sure how to handle this.
my teacher helped me with this and i thought to post working code here if anyone stuck here can use this code.
- (void)inviteFriends: (NSArray*) friends
{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = 2;
request.maxPlayers = 2;
request.defaultNumberOfPlayers = 2;
request.recipients = friends;
request.inviteMessage = #"Your Custom Invitation Message Here";
[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch* match, NSError *error) {
if (error)
{
//Invite has not been sent
// //NSLog(#"Invitation has not been sent");
}
else if (match != nil)
{
//whatever you want to do when the receiver accepts the invite
//NSLog(#"Invitation has been sent with match object = %#",match);
}
}];
request.recipientResponseHandler= ^(GKPlayer *player, GKInviteeResponse response)
{
//NSLog(#"response Get From Other User.");
switch (response) {
case GKInviteeResponseAccepted:
{
}
break;
case GKInviteeResponseDeclined:
{
}
break;
case GKInviteeResponseFailed:
{
}
break;
case GKInviteeResponseIncompatible:
{
}
break;
case GKInviteeResponseUnableToConnect:
{
}
break;
case GKInviteeResponseNoAnswer:
{
}
break;
default:
break;
}
};
}
I am totally new in IOS Development, And I am making a app using MailCore2 api.
Company has told me to use MCOIMApIdleOperation to get the emails from Gmail Server.
I have google all the way to find out solution about this but it is not worth it.
Here is detail about the Problem,
First I want to load the emails from the INBOX folder through MCOIMAPIdleOperation.Below is my code for fetching emails.
- (void)viewDidLoad{
[super viewDidLoad];
//Do any additional setup after loading the view from its nib.
//Made connection with Gmail Imap Server
NSUserDefaults *defaules = [NSUserDefaults standardUserDefaults];
NSString *emailid = [defaules objectForKey:#"emailid" ];
NSString *password = [defaules objectForKey:#"password" ];
session = [[MCOIMAPSession alloc] init];
session.hostname = #"imap.gmail.com";
session.port = 993;
session.username = emailid;
session.password = password;
session.connectionType = MCOConnectionTypeTLS;
idle=[session idleOperationWithFolder:#"INBOX" lastKnownUID:0];
[idle start:^(NSError *err){
MCOIMAPMessagesRequestKind requestKind = (MCOIMAPMessagesRequestKind)
(MCOIMAPMessagesRequestKindHeaders | MCOIMAPMessagesRequestKindStructure |MCOIMAPMessagesRequestKindInternalDate | MCOIMAPMessagesRequestKindHeaderSubject |MCOIMAPMessagesRequestKindFlags);
MCOIMAPFolderInfoOperation *inboxFolderInfo = [session folderInfoOperation:Folder];
NSLog(#"statrt1");
[inboxFolderInfo start:^(NSError *error, MCOIMAPFolderInfo *info)
{
NSLog(#"start2");
BOOL totalNumberOfMessagesDidChange =
self.totalNumberOfInboxMessages != [info messageCount];
self.totalNumberOfInboxMessages = [info messageCount];
NSUInteger numberOfMessagesToLoad =MIN(self.totalNumberOfInboxMessages, nMessages);
if (numberOfMessagesToLoad == 0)
{
self.isLoading = NO;
return;
}
// If total number of messages did not change since last fetch,
// assume nothing was deleted since our last fetch and just
// fetch what we don't have
MCORange fetchRange;
if (!totalNumberOfMessagesDidChange && msgbody.count)
{
numberOfMessagesToLoad -= msgbody.count;
fetchRange = MCORangeMake(self.totalNumberOfInboxMessages -msgbody.count -(numberOfMessagesToLoad - 1),(numberOfMessagesToLoad - 1));
}
// Else just fetch the last N messages
else
{
fetchRange =MCORangeMake(self.totalNumberOfInboxMessages -(numberOfMessagesToLoad - 1),(numberOfMessagesToLoad - 1));
}
MCOIMAPFetchMessagesOperation *imapMessagesFetchOp =[session fetchMessagesByNumberOperationWithFolder:Folder requestKind:requestKind numbers:
[MCOIndexSet indexSetWithRange:fetchRange]];
[imapMessagesFetchOp start:^(NSError *error, NSArray *messages, MCOIndexSet *vanishedMessages)
{
NSSortDescriptor *sort =[NSSortDescriptor sortDescriptorWithKey:#"header.date" ascending:NO];
NSMutableArray *combinedMessages = [NSMutableArray arrayWithArray:messages];
[combinedMessages removeAllObjects];
[combinedMessages addObjectsFromArray:messages];
msgbody=[combinedMessages sortedArrayUsingDescriptors:#[sort]];
[uitable reloadData];
}];
}];
}];
}
By Above code mails are fetched successfully.Problem is when new mail is arrive above code is not running again.what to do so that i can get the new mails when they arrive..
Please help me to solve this issue.
Currently playing around with GooglePlusSample with scope:
#"https://www.googleapis.com/auth/plus.me",
#"https://www.googleapis.com/auth/userinfo.email" and
#"https://www.googleapis.com/auth/userinfo.profile".
Tried calling auth.userEmail, auth.userData in callback method finishedWithAuth:error:, but both are empty...
-(void)finishedWithAuth:(GTMOAuth2Authentication *)auth error:(NSError *)error{
NSLog(#"Received Error %# and auth object==%#",error,auth);
if (error) {
// Do some error handling here.
} else {
[self refreshInterfaceBasedOnSignIn];
NSLog(#"email %# ",[NSString stringWithFormat:#"Email: %#",[GPPSignIn sharedInstance].authentication.userEmail]);
NSLog(#"Received error %# and auth object %#",error, auth);
// 1. Create a |GTLServicePlus| instance to send a request to Google+.
GTLServicePlus* plusService = [[GTLServicePlus alloc] init] ;
plusService.retryEnabled = YES;
// 2. Set a valid |GTMOAuth2Authentication| object as the authorizer.
[plusService setAuthorizer:[GPPSignIn sharedInstance].authentication];
GTLQueryPlus *query = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"];
// *4. Use the "v1" version of the Google+ API.*
plusService.apiVersion = #"v1";
[plusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLPlusPerson *person,
NSError *error) {
if (error) {
//Handle Error
} else
{
NSLog(#"Email= %#",[GPPSignIn sharedInstance].authentication.userEmail);
NSLog(#"GoogleID=%#",person.identifier);
NSLog(#"User Name=%#",[person.name.givenName stringByAppendingFormat:#" %#",person.name.familyName]);
NSLog(#"Gender=%#",person.gender);
}
}];
}
}
Once user is authenticated you can call [[GPPSignIn sharedInstance] userEmail] to get authenticated user's email.
This worked for me :
Firstly use the userinfo.email scope as per :
signInButton.scope = [NSArray arrayWithObjects:
kGTLAuthScopePlusMe,
kGTLAuthScopePlusUserinfoEmail,
nil];
Then define these methods :
- (GTLServicePlus *)plusService {
static GTLServicePlus* service = nil;
if (!service) {
service = [[GTLServicePlus alloc] init];
// Have the service object set tickets to retry temporary error conditions
// automatically
service.retryEnabled = YES;
// Have the service object set tickets to automatically fetch additional
// pages of feeds when the feed's maxResult value is less than the number
// of items in the feed
service.shouldFetchNextPages = YES;
}
return service;
}
- (void)fetchUserProfile {
// Make a batch for fetching both the user's profile and the activity feed
GTLQueryPlus *profileQuery = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"];
profileQuery.fields = #"id,emails,image,name,displayName";
profileQuery.completionBlock = ^(GTLServiceTicket *ticket, id object, NSError *error) {
if (error == nil) {
// Get the user profile
GTLPlusPerson *userProfile = object;
// Get what we want
NSArray * userEmails = userProfile.emails;
NSString * email = ((GTLPlusPersonEmailsItem *)[userEmails objectAtIndex:0]).value;
NSString * name = userProfile.displayName;
NSString * profileId = userProfile.identifier;
} else {
// Log the error
NSLog(#"Error : %#", [error localizedDescription]);
}
};
GTLBatchQuery *batchQuery = [GTLBatchQuery batchQuery];
[batchQuery addQuery:profileQuery];
GTLServicePlus *service = self.plusService;
self.profileTicket = [service executeQuery:batchQuery
completionHandler:^(GTLServiceTicket *ticket,
id result, NSError *error) {
self.profileTicket = nil;
// Update profile
}];
}
And finally call the "fetchUserProfile" method in the "finishedWithAuth" as per :
- (void)finishedWithAuth: (GTMOAuth2Authentication *)auth
error: (NSError *) error
{
// An error?
if (error != nil) {
// Log
} else {
// Set auth into the app delegate
myAppDelegate *appDelegate = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.auth = auth;
// Get user profile
self.plusService.authorizer = auth;
[self fetchUserProfile];
}
}
Note this may not be perfect as it's a 'work in progress', in particular re: getting the correct email address when the user has more than one but it's a start!
Good luck.
Steve
If you have Access not configured error check services in google api console. make sure you enable google plus api services.