I am working on IOS application.Integrated Dropbox successfully and saving data as record in datastores in DropBox as well.It was fine till here.But I am unable to get data after deleting application and reinstalling it.But in one scenario I am getting data i.e,"I inserted a record in any one of the tables in datastores,after inserting that when I am trying to get data Its coming successfully".But I need to get for the first time as the app installs.If any one worked on it please help me.Thanks in advance.
-(void)dropBoxScuccessLogin:(NSString *)successString
{
if ([successString isEqualToString:#"scuccess"])
{
//appdelegate.window.rootViewController = appdelegate.splitview;
NSArray *array1=[appdelegate.datastoreManager listDatastores:nil];
NSLog(#"array is %#",array1);
if (self.account)
{
NSDate *mydate=[NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MMM-DD-yyyy hh:mm:ss a"];
NSString *stringFromDate = [formatter stringFromDate:mydate];
DBTable *customerTbl = [self.store getTable:#"DataSyncedOndate"];
DBRecord *task = [customerTbl insert:#{ #"SyncedDate": stringFromDate} ];
__weak DropBoxViewController *slf = self;
[self.store addObserver:self block:^ {
if (slf.store.status & (DBDatastoreIncoming | DBDatastoreOutgoing))
{
[self syncTasks];
}
}];
[self.store sync:nil];
}
}
else
{
NSLog(#"Dropbox Login faild");
}
}
- (void)syncTasks
{
NSLog(#"Self Account is in syncTasks is %#",self.account);
if (self.account)
{
NSDictionary *changed = [self.store sync:nil];
NSLog(#" Data is Synced");
// [self getDataSync];
dispatch_async(dispatch_get_main_queue(), ^{
[self retriveDataFromDB];
});
// [self performSelector:#selector(getDataSync) withObject:nil afterDelay:2.0];
}
else
{
// [alertView show];
}
}
in retriveDataFromDB method
-(void)retriveDataFromDB
{
NSLog(#"retrive from DB method called");
///////////Admin details///////////
NSMutableArray *tasks = [NSMutableArray arrayWithArray:[[self.store getTable:#"PriceList"] query:nil error:nil]];
NSLog(#"tasks count is %d",[tasks count]);
for (int k=0; k<[tasks count]; k++)
{
DBRecord *recordObj=[tasks objectAtIndex:k];
NSString *Tier1_Id =recordObj[#"Tier1"];
NSString *Tier2_Id =recordObj[#"Tier2"];
NSString *Tier3_Id =recordObj[#"Tier3"];
NSString *Code_Id =recordObj[#"Code"];
NSString *CRV_Id =recordObj[#"CRV"];
NSString *insertAdminString = [NSString stringWithFormat:#"INSERT INTO admin_Tbl(Code,Tier1,Tier2,Tier3,CRV) VALUES(\"%#\",\"%#\",\"%#\",\"%#\",\"%#\")",Code_Id,Tier1_Id,Tier2_Id,Tier3_Id,CRV_Id];
BOOL isDataadded = [appdelegate executeInsertQuery:insertAdminString];
if (isDataadded == YES)
{
NSLog(#"admin table insertrd successfully");
}
else
{
NSLog(#"admin table not insertrd successfully");
}
}
}
In Log I am getting tasks count is "0".
Related
This below code is fired when I press delete button after selecting messages I want to delete in chat room.
- (void)deleteButtonPressed:(id)sender {
if (arrayToDelete.count) {
for (NSString *str in arrayToDelete) {
NSLog(#"msgID --> %#",str);
[self.chatModel.dataSource removeObject:str]; //??? Remove data from the screen
[[FMDBManager sharedInstance] deleteMessageByMessageId:str]; //??? Delete data from database
}
[arrayToDelete removeAllObjects];
[self.chatTableView reloadData];
}
}
This line successfully removes selected messages from the chat room.
[self.chatModel.dataSource removeObject:str]; //??? Remove data from the screen
When I go out the chat room and re-enter, those messages still exist, so I have this line below.
[[FMDBManager sharedInstance] deleteMessageByMessageId:str]; //??? Delete data from database
I think the above line should delete those selected messages from the database but when I re-enter the chat room I still see those messages. Here below are related code to that.
- (void)deleteMessageByMessageId:(NSString *)messageId {
FMDatabase *db = [self getterDataBase];
[db open];
NSString *sqlString = [NSString stringWithFormat:#"DELETE FROM message WHERE messageId = '%#'",messageId];
BOOL status = [db executeUpdate:sqlString];
NSLog(#"Delete MessageById:%# Status:%d",messageId,status);
[db close];
}
I've found that when chat room calls viewDidLoad it will eventually call the method callBackGetChannelLogNew where server will sync-up data with chat room tableview and local database.
- (void)callBackGetChannelLogNew:(NSDictionary *)resultDataDic status:(enumAPI_STATUS)eAPI_STATUS {
if (isFirstTimeUpdate) {
}
if (eAPI_STATUS == API_STATUS_SUCCEE) {
NSString *readString=[NSString stringWithFormat:#"%#",resultDataDic[#"read_arr"]];
if ([readString isEqualToString:#""]) {
// NSLog(#"read_arr is empty");
}
else {
NSArray *read_arr=resultDataDic[#"read_arr"];
// Copy read_arr
self.readArray=[read_arr mutableCopy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
[self dealWithReadArray:read_arr];
});
}
NSArray *data = [resultDataDic objectForKey:#"msg"];
if (data.count > 0) {
apiHaveData = YES;
} else {
apiHaveData = NO;
self.loadIngView.hidden = YES;
isLoadingData = NO;
return;
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
// Reverse order of data
NSArray* reversedArray = [[data reverseObjectEnumerator] allObjects];
NSMutableArray *messageFromOtherArray = [NSMutableArray new];
NSMutableArray *messageAllArray = [NSMutableArray new];
for (int i = 0; i < reversedArray.count; i++) {
NSDictionary *_dic = reversedArray[i];
NSString *fromId = [_dic objectForKey:#"fid"];
NSString *message = [NSString stringWithFormat:#"%#",[_dic objectForKey:#"say"]];
if ([ObjectManager getChatMessageKindWithString:message] == MessageTypeText) {
message = [ObjectManager decryptWithString:message];
}
NSString *messageId = [_dic objectForKey:#"mid"];
NSString *toId = [_dic objectForKey:#"tid"];
NSDateFormatter *_formatter = [[NSDateFormatter alloc] init];
_formatter.dateFormat = #"yyyy-MM-dd HH:mm:ss.SSS";
NSDate *date_t = [NSDate dateWithTimeIntervalSince1970:[[_dic objectForKey:#"t"] doubleValue]/1000.0]; //換算成日期
NSString *stringDate = [_formatter stringFromDate:date_t];
NSString *sendDate = stringDate;
NSString *lid = _dic[#"lid"];
NSMutableDictionary *myDic = [NSMutableDictionary dictionaryWithObjectsAndKeys:
fromId,#"fromId",
message,#"message",
messageId,#"messageId",
sendDate,#"sendDate",
toId,#"toId",
lid,#"lid",
nil];
NSString *isRead;
if (_chatRoomType == ChatRoomTypePrivate) {
if ([_dic[#"r"] intValue]) {
isRead = #"1";
myDic[#"isRead"] = isRead;
lastReadMessageId = [NSString stringWithFormat:#"%#",messageId];
}
}
if (i == 0) {
if (lidForAPI != [_dic[#"lid"] intValue]) {
lidForAPI = [_dic[#"lid"] intValue];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
apiHaveData = NO;
self.loadIngView.hidden = YES;
isLoadingData = NO;
});
return ;
}
}
if (![myDic[#"fromId"] isEqualToString:[User sharedUser].account]) {
[messageFromOtherArray addObject:myDic];
}
if (_chatRoomType == ChatRoomTypeGroup) {
[myDic setObject:#"1" forKey:#"isGroupMessage"];
}
[myDic setObject:#"1" forKey:#"did_I_Read"];
[messageAllArray addObject:myDic];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self setupViewWithMessageArray:messageAllArray]; //???? Here server sync-up data with tableview
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
if (_chatRoomType == ChatRoomTypePrivate) {
if (messageFromOtherArray.count > 0 && isUplaodLastRead == NO) {
isUplaodLastRead = YES;
NSDictionary *lastReadMsgDic = messageFromOtherArray.lastObject;
[self callMsgReadAPI:lastReadMsgDic];
}
} else {
if (messageAllArray.count > 0 && isUplaodLastRead == NO) {
isUplaodLastRead = YES;
NSDictionary *lastReadMsgDic = messageAllArray.lastObject;
[self callMsgReadAPI:lastReadMsgDic];
}
}
self.chatModel.channelTopic = _topic;
NSArray *read_arr=resultDataDic[#"read_arr"];
[self dealMySendMessageReadedWithReadArray:read_arr AndMessageArray:messageAllArray];
[self saveMessageWithArray:messageAllArray]; //???? Here server sync-up data with local db
});
});
}
}
This lines will sync-up data from server to tableview
dispatch_async(dispatch_get_main_queue(), ^{
[self setupViewWithMessageArray:messageAllArray]; //???? Here server sync-up data with tableview
});
Here below is the method setupViewWithMessageArray
- (void)setupViewWithMessageArray:(NSArray *)messageAllArray {
if (!isFirstTimeUpdate) {
isFirstTimeUpdate = YES;
self.chatModel.dataSource = nil;
[self.chatTableView reloadData];
self.chatModel.dataSource = [[NSMutableArray alloc] init];
[self addMessageWithArray:messageAllArray];
[self.chatTableView reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:self.chatModel.dataSource.count-1 inSection:0];
[self.chatTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
} else {
[self addMessageWithArray:messageAllArray];
[self reloadTableViewWithoutMove];
}
self.loadIngView.hidden = YES;
isLoadingData = NO;
if (_chatRoomType == ChatRoomTypePrivate) {
if (lastReadMessageId) {
[self.chatModel setPrivateChatListAllReadFormMessageId:lastReadMessageId];
}
}
}
This line will sync-up data from server to local db
[self saveMessageWithArray:messageAllArray]; //???? Here server sync-up data with local db
Here below is the method saveMessageWithArray
- (void)saveMessageWithArray:(NSArray *)messageArray {
for (NSDictionary *myDic in messageArray) {
if (![[FMDBManager sharedInstance] didMessageExistWithMessageID:[myDic objectForKey:#"messageId"]]) {
[[FMDBManager sharedInstance] SaveMessage:myDic];
}
else {
NSString *mid=[NSString stringWithFormat:#"%#",myDic[#"messageId"]];
NSString *isRead = myDic[#"isReaed"];
if (isRead) {
[[FMDBManager sharedInstance] UpdateisReadWithMessageID:mid];
}
}
}
}
So I think now my question is how I can update messageAllArray with arrayToDelete before server sync-up?
Below is my code but with this code i can't get image for any contact.
Please help me for this.
- (void)loadAddressBook
{
arrContacts = [[NSMutableArray alloc]init];
APAddressBook *addressBook = [[APAddressBook alloc] init];
[addressBook loadContacts:^(NSArray <APContact *> *contacts, NSError *error)
{
if (!error)
{
for (APContact *strcontact in contacts)
{
NSMutableDictionary *addressDict=[[NSMutableDictionary alloc]init];
[addressDict setValue:strcontact.name.compositeName forKey:COMPOSITENAME];
if (strcontact.thumbnail != nil)
{
NSData *imgData = [NSData dataWithData:UIImagePNGRepresentation(strcontact.thumbnail)];
// From data to string
NSString *strImage = [[NSString alloc] initWithData:imgData encoding:NSUTF8StringEncoding];
[addressDict setObject:strImage forKey:IMAGE];
}else {
[addressDict setObject:NOIMAGE forKey:IMAGE];
}
for (APPhone *phones in strcontact.phones) {
// NSLog(#"Number %#",phones.number);
[addressDict setValue:phones.number forKey:PHONE];
}
for (APEmail *emails in strcontact.emails) {
// NSLog(#"Emails %#",emails.address);
[addressDict setValue:emails.address forKey:EMAIL];
}
for (APAddress *address in strcontact.addresses) {
// NSLog(#"Number %#",phones.number);
[addressDict setValue:address forKey:ADDRESS];
}
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"dd.MM.yyyy";
NSString *strDate = [formatter stringFromDate:[NSDate date]];
[addressDict setValue:strDate forKey:IMPORTDATE];
[arrContacts addObject:addressDict];
}
[tblmportContacts reloadData];
}
else
{
// show error
}
}];
}
I am getting all details but can not get images from APAddressBook.
Please provide solution for this.
Try code below.
addressBook.fieldsMask = APContactFieldAll;
I am using iCloud for sqlite database sync between multiple devices.
i have implemented this functionality in my app for sqlite sync.
But data is updating after 5 mins on other devices.
is this problem from iCloud side because as far as i know we cannot manually update iCloud.
i know it is not correct to use sqlite for icloud sync but i have more 100 tables and i cannot migrate to core data.
Please find my code below:
AppDelegate.m
[self checkForiCloudAccess];
[[sqlmessenger shared] fireQueryForCloudData];
Check for iCloud Access
-(void)checkForiCloudAccess{
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq) {
NSLog(#"iCloud access at %#", ubiq);
isCloudAccees= TRUE;
}
else {
isCloudAccees= FALSE;
UIAlertView *alertb = [[UIAlertView alloc] initWithTitle:#"Error" message:#"No iCloud acces" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertb show];
}
}
sqlmessenger.m
Fire Query to get iCloud Data
- (void)fireQueryForCloudData{
NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
[query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"%K ENDSWITH '.xml'", NSMetadataItemFSNameKey];
[query setPredicate:pred];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query];
[query startQuery];
}
- (void)queryDidFinishGathering:(NSNotification *)notification {
NSMetadataQuery *que = [[NSMetadataQuery alloc]init];
que = [notification object];
[que disableUpdates];
[que stopQuery];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:NSMetadataQueryDidFinishGatheringNotification
object:que];
self.metaQuery = que;
que = nil;
UIAlertView *alrView = [[UIAlertView alloc]initWithTitle:#"" message:#"Cloud updated" delegate:Nil cancelButtonTitle:#"OK" otherButtonTitles:Nil, nil];
[alrView show];
//TODO: Comment this stupid method
//[self fetcLargeTableFromCloud];
}
Update database using Metadata query object
- (void)loadData:(NSString *)tableName {
_TblName = tableName;
for (NSMetadataItem *item in [self.metaQuery results])
{
NSString *filename = [item valueForAttribute:NSMetadataItemDisplayNameKey];
if([filename isEqualToString:tableName])
{
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
//Conflict resolve
//[fileVersion replaceItemAtURL:url options:0 error:nil];
NSData *file = [NSData dataWithContentsOfURL:url];
[NSFileVersion removeOtherVersionsOfItemAtURL:url error:nil];
NSArray *conflicts = [NSFileVersion unresolvedConflictVersionsOfItemAtURL:url];
for (NSFileVersion *conflict in conflicts)
{
conflict.resolved = YES;
NSLog(#"conflict %#",conflict);
}
if (file) {
_arrCloudData = [[NSMutableArray alloc]init];
_tmpDict = [[NSMutableDictionary alloc]init];
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:file];
[parser setDelegate:self];
[parser parse];
if (_arrCloudData.count !=0) {
[self deleteTable:tableName];
_arrColumnList = [self getColumnsForTable:tableName];
//[_arrColumnList removeObjectAtIndex:3];
// [_arrColumnList removeObjectAtIndex:5];
// [_arrColumnList removeObjectAtIndex:8];
NSString *columnNames = [_arrColumnList componentsJoinedByString:#","];
/*
NSMutableArray *arrtmp = [NSMutableArray arrayWithArray:_arrColumnList];
for (int i = 0; i<[arrtmp count]; i++) {
[arrtmp replaceObjectAtIndex:i withObject:#"?"];
}*/
// NSString *blidString = [arrtmp componentsJoinedByString:#","];
//TODO: Uncomment this lines
//NSString *query = [NSString stringWithFormat:#"Insert into %# (%#) values (%#)",tableName,columnNames,blidString];
//TODO: comment this line
NSString *query = [NSString stringWithFormat:#"Insert into %# (%#) values",tableName,columnNames];
// NSDate *parseFinish = [NSDate date];
//[self insertRowIntblMealDetails:tableName :query];
int exCount = _arrCloudData.count/500;
for (int i=0; i<=exCount; i++) {
if ([tableName isEqualToString:#"tblRecipeSubtypes"]) {
[self insertRowIntblMealDetails:tableName :query:i];
}
else{
[self insertRowIntbl:tableName :query :i];
}
}
/*
for (int i=0; i<[_arrCloudData count]; i++) {
//Genralized method
//[self insertRowInTableName:tableName:i:query];
//
//[self insertRowIntblMealDetails:tableName :i :query];
[self insertRowIntblMealDetails:tableName :query];
}*/
sqlite3_close(database);
/*
NSDate *Complete = [NSDate date];
NSTimeInterval PraseComplete = [parseFinish timeIntervalSinceDate:start];
NSTimeInterval LoopTime = [Complete timeIntervalSinceDate:parseFinish];
NSTimeInterval totalTime = [Complete timeIntervalSinceDate:start];
NSLog(#"Parse Execution Time: %f", PraseComplete);
NSLog(#"Loop Execution Time: %f", LoopTime);
NSLog(#"Total Execution Time: %# %f ",tableName, totalTime);
*/
}
else{
NSLog(#"Empty Array %#",tableName);
}
}
else{
NSLog(#"Blank File %#",tableName);
}
}
}
}
i call loaddata from respective classes to update database.
is there anyway with that i can update data early/fast or is there any problem in my code?
Thanks in Advance
I am creating an iOS app using Parse database(asynchronously) to store information that will be used when populating a mapview. I have been trying to figure out what is wrong for a long time and have done plenty of research without any luck. I have, however, found the source of the issue.
In my code, I am querying the parse database in hopes of getting the information I want and then storing the information in a custom pointAnnotation class, which is of type MkPointAnnotation. Each item is stored in an array of pointAnnotations, and once all items in the database have been stored in the array, the annotations are added to MyMapView. --I have tried adding the annotations as they are created, which does not change anything.
The issue I have been having is that randomly, the query will iterate under the for(PFObject *vendor in Vendors) and reach an error, calling NSLog(#"%#", error.debugDescription); which shows (null) in the output log. The amount of objects that return null seems to change each time I run the application, and occasionally it will work as expected. After adding a do while(pointArray.count < query.countObjects), the function will iterate roughly 20-30 times and then will add the correct number of annotations, however, it is extremely inefficient.
Is this an inefficiency within Parse or is there a better way to achieve the expected results?
PFQuery *query = [PFQuery queryWithClassName:#"Vendors"];
[query orderByDescending:#"updatedAt"];
[query findObjectsInBackgroundWithBlock:^(NSArray *vendors, NSError *error){
NSMutableArray *pointArray = [[NSMutableArray alloc] init];
if (!error) {
// The find succeeded.
// Do something with the found objects
do {
pointArray = [[NSMutableArray alloc] init];
for (PFObject *vendor in vendors) {
NSDate *lastUpdated = vendor.updatedAt;
NSDate *today = [NSDate date];
NSDate *newDate = [lastUpdated dateByAddingTimeInterval:86400];
if (today <= newDate) {
PFGeoPoint *point = vendor[#"Location"];
NSString *vendor_ID = vendor[#"Vendor_ID"];
NSMutableArray *FruitList = vendor[#"Fruits"];
NSMutableArray *VeggieList = vendor[#"Veggies"];
NSMutableArray *addressArray = vendor[#"Address"];
NSString *startHr = vendor[#"Start_Time"];
NSString *endHr = vendor[#"End_Time"];
Boolean more = false;
NSString *moreString = vendor[#"And_More"];
if ([moreString isEqual: #"true"]) {
more = true;
}
CLLocationCoordinate2D location;
location.latitude = point.latitude;
location.longitude = point.longitude;
pointAnnotation *newAnnotation = [[pointAnnotation alloc] init];
if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqual:#"ENGLISH"]){
FindCartsLabel.text = #"Find Carts within:";
MilesTextField.text = #"Show All";
milesArray=[[NSArray alloc]initWithObjects:#"Show All", #"1 Mile", #"5 Miles", #"10 Miles", #"20 Miles", nil];
AddressBar.placeholder = ENGLISH_Address;
newAnnotation.title = #"Good. To. Go. Vendor";
newAnnotation.fruits = FruitList;
newAnnotation.veggies = VeggieList;
}else if ([[[NSUserDefaults standardUserDefaults] objectForKey:#"language"] isEqual:#"SPANISH"]){
FindCartsLabel.text = #"Encuentra Carros Dentro:";
newAnnotation.title = #"Good. To. Go. Vendedor";
AddressBar.placeholder = SPANISH_Address;
NSMutableArray *spanishFruitList = [[NSMutableArray alloc]init];
for (NSString *current in FruitList) {
MilesTextField.text = #"Mostrar Todo";
milesArray=[[NSArray alloc]initWithObjects:#"Mostrar Todo", #"1 Milla", #"5 Millas", #"10 Millas", #"20 Millas", nil];
if ([current isEqual:#"Apples"]) {
[spanishFruitList addObject:SPANISH_Apples];
}
if ([current isEqual:#"Bananas"]) {
[spanishFruitList addObject:SPANISH_Bananas];
}
if ([current isEqual:#"Citrus"]) {
[spanishFruitList addObject:SPANISH_Citrus];
}
if ([current isEqual:#"Mangos"]) {
[spanishFruitList addObject:SPANISH_Mangos];
}
if ([current isEqual:#"Strawberries"]) {
[spanishFruitList addObject:SPANISH_Strawberries];
}
if ([current isEqual:#"And More"]) {
[spanishFruitList addObject:SPANISH_More];
}
}
NSMutableArray *spanishVeggieList = [[NSMutableArray alloc]init];
for (NSString *current in VeggieList) {
if ([current isEqual:#"Avocados"]) {
[spanishVeggieList addObject:SPANISH_Avocados];
}
if ([current isEqual:#"Broccoli"]) {
[spanishVeggieList addObject:SPANISH_Broccoli];
}
if ([current isEqual:#"Carrots"]) {
[spanishVeggieList addObject:SPANISH_Carrots];
}
if ([current isEqual:#"Squash"]) {
[spanishVeggieList addObject:SPANISH_Squash];
}
if ([current isEqual:#"Onions"]) {
[spanishVeggieList addObject:SPANISH_Onions];
}
if ([current isEqual:#"Tomatoes"]) {
[spanishVeggieList addObject:SPANISH_Tomatoes];
}
if ([current isEqual:#"And More"]) {
[spanishVeggieList addObject:SPANISH_More];
}
}
newAnnotation.fruits = spanishFruitList;
newAnnotation.veggies = spanishVeggieList;
}
newAnnotation.coordinate = location;
newAnnotation.vendorID = vendor_ID;
newAnnotation.startHour = startHr;
newAnnotation.endHour = endHr;
newAnnotation.loc = point;
newAnnotation.isCustomAddress = false;
//newAnnotation.subtitle = address;
__block NSString *address = [NSString stringWithFormat:#"%# %#, %#, %#, %#",
addressArray[0], addressArray[1],
addressArray[2], addressArray[3],
addressArray[4]];
__block NSString *currAddress = [NSString stringWithFormat:#"%# %#\n"
"%#, %#, %#\n"
"%#\n",
addressArray[0], addressArray[1],
addressArray[2], addressArray[3],
addressArray[4], addressArray[5]];
newAnnotation.subtitle = address;
newAnnotation.addressFormatted = currAddress;
static NSString *identifier = #"MyLocation";
MKPinAnnotationView *currentView = [[MKPinAnnotationView alloc] initWithAnnotation:newAnnotation reuseIdentifier:identifier];
[pointArray addObject:currentView];
} else {
//[self viewDidLoad];
NSLog(#"%#", error.debugDescription);
}
//} ];
}
} while (pointArray.count < query.countObjects);
}
if (pointArray.count == query.countObjects) {
for (MKPinAnnotationView *currentPoint in pointArray) {
[self.MyMapView addAnnotation:currentPoint.annotation];
}
}
}];
Thanks in advance for the help. I do not really understand why this code would not complete after only one iteration.
The NSLog(#"%#", error.debugDescription); doesn't look like it's in the right place. It's in an else block that is associated with the if (today <= newDate) which is inside a block of code that is only executed if error is null which is why it says null in the log (when what it really means is "today > newDate"). – Anna
I am making a call to syncWithCalendar and after events are successfully added, I get low memory warning and app terminates with "Received Low Memory" warning. The events generated and saved in calendar are more than 50. I tried using instruments but I am not able to find the code where memory leak occurs and also through live bytes that show in instruments I am not able to track the code that is causing the leak. Can anyone please help me solve this issue.
- (void)syncWithCalendar
{
#autoreleasepool {
[self deleteEventsIfExist];
NSMutableDictionary *dictionary = [util readPListData];
NSMutableArray *courses = [util getCourses];
__block NSMutableArray *lessons;
__block NSMutableDictionary *lesson;
NSString *studentID = [util getProgramDetails].studentId;
NSString *programName = [util getProgramDetails].programName;
double offset[] = {0, 0, -300, -900, -1800, -3600, -7200, -86400, -172800};
__block NSString *startDateString = #"", *endDateString = #"";
NSTimeInterval relativeOffsetValue = 0;
int index = [[dictionary objectForKey:#"event-alert-option"] intValue];
relativeOffsetValue = offset[index];
NSDateFormatter *formatter;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM/dd/yyyy HH:mm:ss"];
[formatter setDateFormat:#"MM/dd/yyyy"];
NSString *currentDateString = [NSString stringWithFormat:#"%# 09:00:00", [formatter stringFromDate:[NSDate date]]];
[formatter setDateFormat:#"MM/dd/yyyy HH:mm:ss"];
NSDate *currentDate = [formatter dateFromString:currentDateString];
EKEventStore *eventStore = [[EKEventStore alloc] init];
if([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)]) {
// iOS 6 and later
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted){
//---- codes here when user allow your app to access theirs' calendar.
dispatch_async(dispatch_get_main_queue(), ^{
// Event creation code here.
for (int i=0; i<[courses count]; i++)
{
#autoreleasepool {
lessons = [[courses objectAtIndex:i] objectForKey:#"lessons"];
for (int j=0; j<[lessons count]; j++)
{
#autoreleasepool {
lesson = [lessons objectAtIndex:j];
NSString *title = nil;
title = [NSString stringWithFormat:#"%# %#-Complete %# lesson",studentID,programName,[lesson objectForKey:#"lesson-name"]];
if ([[lesson objectForKey:#"actual-exam-date"] isEqualToString:#"00/00/0000"])
{
startDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"plan-exam-date"], #"09:00:00"];
endDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"plan-exam-date"], #"18:00:00"];
}
else
{
if ([[lesson objectForKey:#"retake-actual-date"] isEqualToString:#"00/00/0000"])
{
startDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"retake-plan-date"], #"09:00:00"];
endDateString = [NSString stringWithFormat:#"%# %#", [lesson objectForKey:#"retake-plan-date"], #"18:00:00"];
}
}
if (!([startDateString isEqualToString:#""] && [endDateString isEqualToString:#""]))
{
EKEvent *event = [EKEvent eventWithEventStore:eventStore];
event.title=title;
event.startDate = [formatter dateFromString:startDateString];
event.endDate = [formatter dateFromString:endDateString];
event.allDay = NO;
if (index != 0)
{
event.alarms = [NSArray arrayWithObjects:[EKAlarm alarmWithRelativeOffset:relativeOffsetValue], nil];
}
[event setCalendar:[eventStore defaultCalendarForNewEvents]];
// Compare current date to event start date, if start date has been passed then preventing to sync with calendar
NSComparisonResult result = [event.startDate compare:currentDate];
if (result != NSOrderedAscending)
{
NSError *err = nil;
[eventStore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
if (err) {
NSLog(#"event not saved .. error = %#",err);
} else {
NSLog(#"event added successfully");
}
}
}
} // autoreleasepool
} // lessons for loop
} // autoreleasepool
} // courses for loop
[self hideModal];
});
}else
{
//----- codes here when user NOT allow your app to access the calendar.
// [self performSelectorOnMainThread:#selector(hideModal) withObject:nil waitUntilDone:NO];
}
}];
} else {
// sync calendar for <iOS6
}
} // autoreleasepool
}
- (void)deleteEventsIfExist
{
#autoreleasepool {
NSMutableArray *courses = [util getCourses];
__block NSMutableArray *lessons;
__block NSMutableDictionary *lesson;
NSString *studentID = [util getProgramDetails].studentId;
NSString *programName = [util getProgramDetails].programName;
EKEventStore* store = [[EKEventStore alloc] init];
dispatch_async(dispatch_get_main_queue(), ^{
// Event creation code here.
NSDate* endDate = [NSDate dateWithTimeIntervalSinceNow:[[NSDate distantFuture] timeIntervalSinceReferenceDate]];
NSPredicate *fetchCalendarEvents = [store predicateForEventsWithStartDate:[NSDate date] endDate:endDate calendars:store.calendars];
NSArray *allEvents = [store eventsMatchingPredicate:fetchCalendarEvents];
for (int i=0; i<[courses count]; i++)
{
#autoreleasepool {
lessons = [[courses objectAtIndex:i] objectForKey:#"lessons"];
for (int j=0; j<[lessons count]; j++)
{
#autoreleasepool {
lesson = [lessons objectAtIndex:j];
NSString *oldEventSubtitle = [NSString stringWithFormat:#"%# %#-Complete %# lesson",studentID,programName,[lesson objectForKey:#"lesson-name"]];
for (EKEvent *e in allEvents)
{
if ( [oldEventSubtitle isEqualToString:e.title])
{
NSError* error = nil;
[store removeEvent:e span:EKSpanThisEvent commit:YES error:&error];
NSLog(#"deleting events");
}
}
} // autoreleasepool
} // lessons
} // autoreleasepool
} // courses
});
} // autoreleasepool
}
It's a rough guess, but it seems the asynchronous invocations may lead to troubles.
In order to test this, just use dispatch_sync instead of dispatch_async and examine the memory consumption. If this leads to an improvement, then a solution is in sight, which involves to re-factor your current asynchronous "parallel" approach and turn it into an appropriate asynchronous "serial" approach or an complete synchronous approach.
This may also require to "serialize" all invocations of this asynchronous method:
[eventStore requestAccessToEntityType:EKEntityTypeEvent
completion:^(BOOL granted, NSError *error) {
...
}]
This is how I made a call to syncWithCalendar function
if([eventStore respondsToSelector:#selector(requestAccessToEntityType:completion:)]) {
// iOS 6 and later
[eventStore requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted,
NSError *error) {
if (granted){
dispatch_async(dispatch_get_main_queue(), ^{
[self syncWithCalendar];
});
} else {
// calendar access not granted
}
}];
}
And in syncWithCalendar function everything remains same except the line of code that
was creating the crash/memory issue. Below is the incorrect line of code that I was
using earlier
// wrong
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:YES error:&err];
The correct way to save event: (Note: I didn't require event identifier in my case)
// correct
[self.eventstore saveEvent:event span:EKSpanThisEvent commit:NO error:&err];
and then use [self.eventstore commit:NULL] after all the events are saved. This stopped the crash in my case. Hope this post will
help other get the solution. Thanks !!!!
You need to clear the cache when you are receiving memory warning, use this method it will help you.
-(void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}