Alright,
I'm using Magicalrecord for core data implementation. My app downloads a bunch of info the first time it is loaded. That data is then saved to core data. This is done in the AppDelegate file. But, whenever my app goes to the background or is terminated the data is lost. Here is the didFinishLaunching with options method:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(#"My app is starting");
[MagicalRecord setupAutoMigratingCoreDataStack];
//NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![[NSUserDefaults standardUserDefaults] objectForKey:#"AGM_DataSetup"]) {
NSError* jsonError;
NSArray* json;
Reachability *reachability = [Reachability reachabilityForInternetConnection];
NetworkStatus internetStatus = [reachability currentReachabilityStatus];
if (internetStatus == NotReachable) {
NSLog(#"Offline");
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"static" ofType:#"json"];
NSString *myJSON = [[NSString alloc] initWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
json = [NSJSONSerialization JSONObjectWithData:[myJSON dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&jsonError];
} else {
NSLog(#"Online");
NSData* data = [NSData dataWithContentsOfURL:
aWaterURL];
json = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&jsonError];
}
if (!jsonError) {
[MagicalRecord cleanUp];
NSString* folderPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSError *error = nil;
for (NSString *file in [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:&error])
{
[[NSFileManager defaultManager] removeItemAtPath:[folderPath stringByAppendingPathComponent:file] error:&error];
if(error)
{
NSLog(#"Delete error: %#", error.description);
}
}
[MagicalRecord setupCoreDataStackWithAutoMigratingSqliteStoreNamed:#"Anglers411.sqlite"];
NSLog(#"Initial Data Load");
for (id jsonArea in json) {
// Create an area
Area *area = [Area MR_createEntity];
area.name = [jsonArea objectForKey:#"name"];
area.bulletDescription = [jsonArea objectForKey:#"bulletDescription"];
area.uid = [jsonArea objectForKey:#"id"];
NSArray* jsonLocations = [jsonArea objectForKey:#"locations"];
for (id jsonLocation in jsonLocations) {
// create a location
Location *location = [Location MR_createEntity];
location.uid = [jsonLocation objectForKey:#"id"];
location.name = [jsonLocation objectForKey:#"name"];
location.desc = [jsonLocation objectForKey:#"desc"];
location.directions = [jsonLocation objectForKey:#"directions"];
location.bulletDescription = [jsonLocation objectForKey:#"bulletDescription"];
location.area = area;
NSArray* jsonBugs = [jsonLocation objectForKey:#"bugs"];
for (id jsonBug in jsonBugs) {
Bug *bug = [Bug MR_createEntity];
bug.name = [jsonBug objectForKey:#"name"];
bug.spring = [jsonBug objectForKey:#"spring"];
bug.summer = [jsonBug objectForKey:#"summer"];
bug.fall = [jsonBug objectForKey:#"fall"];
bug.winter = [jsonBug objectForKey:#"winter"];
bug.location = location;
}
}
}
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreWithCompletion:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"You successfully saved your context.");
} else if (error) {
NSLog(#"Error saving context: %#", error.description);
}
}];
// Set User Default to prevent another preload of data on startup.
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"AGM_DataSetup"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
return YES;
}
Here is the method I use in both applicationDidEnterBackground and ApplicationWillTerminate:
- (void)saveContext {
[MagicalRecord cleanUp];
}
Thanks for any help with this. I have read over every magicalrecord non-persist question on here and haven't found anything that worked.
Take Care,
Ben
Sorry,
After further exploration, I see that it is generally not going to work to set up 2 core data stacks with different names, if you want them to be the same stack... I have corrected this.
Related
I am working on an iPhone app. It is a Enterprise calendaring app for my agency. We have a RESTful API backend connected to a web application where the appointments are entered. The appointments for an individual are to show up on that user’s iPhone. Data is sent by XML. There are only 3 or 4 appointments per day and less than 10 fields per record, so not a lot of data is transferred at a time (just the selected day’s information).
I tried to design this with an array on the iPhone for the parsed data, but the security checking on the web server makes the application time out when loading the data, and I didn’t handle the asynchronous processing well.
Now I’m wondering if I’m even approaching the problem correctly. Would it be better to use Core Data to store the appointments and then work to update the Core Data store in the background? I know I need to update the data outside of the loading the table process. I’m just at a loss for the best way to approach this.
I have looked through the site for information as to how to approach this. I have tried looking in books. Any help would be appreciated.
Security.h
typedef void (^touchIDComplete)(BOOL);
typedef void (^fileExists)(BOOL);
typedef void (^sessionVerify)(BOOL);
typedef void (^parsingData)(BOOL);
typedef void (^touchIDSuccess)(BOOL);
typedef void (^sessionRetrieved)(BOOL);
typedef void (^touchIDComplete)(BOOL);
typedef void (^sessionReading)(BOOL);
typedef void (^fillArray)(BOOL);
typedef void (^getTheData)(NSData *myData, NSError *error);
typedef void (^gettingESNBlock)(NSString *myESN, NSString *newSession, BOOL success, NSError *error);
typedef void (^checkingESNBlock)(NSString *myESN, NSString *sessionInfo, BOOL success, NSError *error);
#interface Security : NSObject
#property (strong, nonatomic) NSArray *types;
#property (strong, nonatomic) NSArray *esn;
#property (strong, nonatomic) NSString *idfv;
#property (strong, nonatomic) NSData *parseData;
#property (strong, nonatomic) NSString *sessionDetail;
#property (strong, nonatomic) NSString *loginFinished;
#property (strong, nonatomic) NSMutableURLRequest *request;
#property (atomic) NSString *passESN;
- (void)waitForData:(sessionVerify)compblock;
- (void)waitForFile:(fileExists)compblock;
- (void)waitForESN:(parsingData)compblock;
- (void)findESN:(gettingESNBlock)callback;
- (void)checkThumb:(touchIDSuccess)compblock;
- (void)readIt:(sessionRetrieved)compblock;
- (void)readNewSession:(sessionReading)compblock;
- (void)doTheWork:(NSString *)theESN withSession:(NSString *)newSession withSuccess:(BOOL)success error:(NSError *)error;
- (void)checkESN:(checkingESNBlock)callback;
- (void)checkTheSession:(NSString *)oldESN withSession:(NSString *)oldSession withSuccess:(BOOL)success error:(NSError *)error;
- (void)fillAppointmentData:(fillArray)compblock;
- (void)gettingData:(getTheData)compblock;
#end
Security.m
#implementation Security
void(^getESNForCallback)(NSString *myESN, NSString *newSession, BOOL success, NSError *error);
void(^checkESNWithCallback)(NSString *myESN, NSString *oldSession, BOOL success, NSError *error);
- (void)waitForFile:(fileExists) compblock {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *directoryPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectoryPath = [directoryPaths objectAtIndex:0];
NSString *fullPath = [documentsDirectoryPath stringByAppendingString:#"/session.txt"];
compblock([fileManager fileExistsAtPath:fullPath]);
}
- (void) waitForData:(sessionVerify) compblock {
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:self.request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
return;
}
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != 200) {
if (statusCode == 401) {
// Insert process for thumbprint and session cookie pull
NSFileManager *fileManagerThree = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *sessionPath = [documentsPath stringByAppendingPathComponent:#"session.txt"];
NSError *error;
BOOL success = [fileManagerThree removeItemAtPath:sessionPath error:&error];
if (success) {
} else {
}
} else {
return;
}
}
}
self.parseData = data;
compblock (YES);
}];
[task resume];
}
- (void)waitForESN:(parsingData) compblock {
ParseTypeXML *myParser = [[ParseTypeXML alloc] initWithData:self.parseData];
VariableStore *globals = [VariableStore sharedInstance];
if ([myParser.esn count] == 0) {
globals.user_esn = #"Error";
compblock(YES);
} else {
globals.user_esn = myParser.esn[0];
compblock(YES);
}
}
- (void)findESN:(gettingESNBlock)callback {
getESNForCallback = callback;
VariableStore *globals = [VariableStore sharedInstance];
[self doTheWork:globals.user_esn withSession:globals.sessionInfo withSuccess:YES error:nil];
}
- (void)doTheWork:(NSString *)theESN withSession:(NSString *)newSession withSuccess:(BOOL)success error:(NSError *)error {
[self checkThumb:^(BOOL finished) {
if(finished) {
[self readIt:^(BOOL newFile) {
if (newFile) {
[self readNewSession:^(BOOL seen) {
if (seen) {
VariableStore *globals = [VariableStore sharedInstance];
NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
#"ollie/", NSHTTPCookieDomain,
#"\\", NSHTTPCookiePath,
#"Cookie", NSHTTPCookieName,
globals.sessionInfo, NSHTTPCookieValue,
nil];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
NSArray *cookieArray = [NSArray arrayWithObject:cookie];
NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];
NSMutableString *url = [[NSMutableString alloc] initWithString:#"https://company.com/file.php"];
NSURL *urlNew = [NSURL URLWithString:url];
self.request = [NSMutableURLRequest requestWithURL:urlNew];
[self.request setHTTPMethod:#"GET"];
[self.request setAllHTTPHeaderFields:headers];
[self waitForData:^(BOOL dataReceived) {
if (dataReceived) {
[self waitForESN:^(BOOL esnFound) {
if (esnFound) {
VariableStore *globals = [VariableStore sharedInstance];
getESNForCallback(globals.user_esn, globals.sessionInfo, success, error);
}
}];
}
}];
}
}];
}
}];
}
}];
}
- (void)checkThumb:(touchIDSuccess)compblock {
LAContext *context = [[LAContext alloc] init];
NSError *error = nil;
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
// Authenticate User
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:#"You need to log in."
reply:^(BOOL success, NSError * _Nullable error) {
if (success) {
NSLog(#"success");
compblock(YES);
} else {
switch (error.code) {
case LAErrorAuthenticationFailed:
break;
case LAErrorUserCancel:
break;
case LAErrorUserFallback:
break;
default:
break;
}
}
}];
}
}
- (void)readIt:(sessionRetrieved)compblock {
NSString *idfv = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
NSString *url = #"https://company.com/specialstring.php";
NSMutableString *postText = [[NSMutableString alloc] init];
[postText appendString:idfv];
NSString *postBody = [NSString stringWithString:postText];
XMLPostSecurity *postAction = [[XMLPostSecurity alloc] init];
VariableStore *globals = [VariableStore sharedInstance];
globals.sessionInfo = [postAction sendPostRequestToUrl:url withBody:postBody];
FileSaving *saver = [[FileSaving alloc] init];
[saver saveSession:globals.sessionInfo];
compblock(YES);
}
-(void)readNewSession:(sessionReading)compblock {
NSFileManager *fileManagerTwo;
NSData *dataBuffer;
fileManagerTwo = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingString:#"/session.txt"];
dataBuffer = [fileManagerTwo contentsAtPath:filePath];
VariableStore *globals = [VariableStore sharedInstance];
globals.sessionInfo = [[NSString alloc] initWithData:dataBuffer encoding:(NSASCIIStringEncoding)];
compblock(YES);
}
- (void)checkESN:(checkingESNBlock)callback {
checkESNWithCallback = callback;
VariableStore *globals = [VariableStore sharedInstance];
[self checkTheSession:globals.user_esn withSession:globals.sessionInfo withSuccess:YES error:nil];
}
- (void)checkTheSession:(NSString *)theESN withSession:(NSString *)oldSession withSuccess:(BOOL)success error:(NSError *)error {
[self readNewSession:^(BOOL seen) {
if (seen) {
VariableStore *globals = [VariableStore sharedInstance];
NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
#"ollie/", NSHTTPCookieDomain,
#"\\", NSHTTPCookiePath,
#"Cookie", NSHTTPCookieName,
globals.sessionInfo, NSHTTPCookieValue,
nil];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
NSArray *cookieArray = [NSArray arrayWithObject:cookie];
NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];
NSMutableString *url = [[NSMutableString alloc] initWithString:#"https://company.com/file.php"];
NSURL *urlNew = [NSURL URLWithString:url];
self.request = [NSMutableURLRequest requestWithURL:urlNew];
[self.request setHTTPMethod:#"GET"];
[self.request setAllHTTPHeaderFields:headers];
[self waitForData:^(BOOL dataReceived) {
if (dataReceived) {
[self waitForESN:^(BOOL esnFound) {
if (esnFound) {
VariableStore *globals = [VariableStore sharedInstance];
checkESNWithCallback(globals.user_esn, globals.sessionInfo, success, error);
}
}];
}
}];
}
}];
}
- (void)fillAppointmentData:(fillArray)compblock {
VariableStore *globals = [VariableStore sharedInstance];
NSDictionary *cookieProperties = [NSDictionary dictionaryWithObjectsAndKeys:
#"ollie/", NSHTTPCookieDomain,
#"\\", NSHTTPCookiePath,
#"Cookie", NSHTTPCookieName,
globals.sessionInfo, NSHTTPCookieValue,
nil];
NSHTTPCookie *cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
NSArray *cookieArray = [NSArray arrayWithObject:cookie];
NSDictionary *headers = [NSHTTPCookie requestHeaderFieldsWithCookies:cookieArray];
NSMutableString *url = [[NSMutableString alloc] initWithString:#"https://company.com/file2.php?adb="];
[url appendString:globals.chosenDate];
[url appendString:#"&esn="];
[url appendString:globals.user_esn];
NSURL *urlNew = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlNew];
[request setHTTPMethod:#"GET"];
[request setAllHTTPHeaderFields:headers];
[self gettingData:^(NSData *myData, NSError *error) {
if (myData != nil) {
ParseXML *myParser = [[ParseXML alloc] initWithData:myData];
[globals.appointmentData removeAllObjects];
[globals.appointmentData addObjectsFromArray:myParser.items];
}
}];
}
- (void) gettingData:(getTheData) compblock {
VariableStore *globals = [VariableStore sharedInstance];
globals.got401 = nil;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:self.request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
return;
}
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
if (statusCode != 200) {
if (statusCode == 401) {
// Insert process for thumbprint and session cookie pull
NSFileManager *fileManagerThree = [NSFileManager defaultManager];
NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *sessionPath = [documentsPath stringByAppendingPathComponent:#"session.txt"];
NSError *error;
BOOL success = [fileManagerThree removeItemAtPath:sessionPath error:&error];
if (success) {
} else {
}
globals.got401 = #"Error";
} else {
return;
}
}
}
self.parseData = data;
}];
[task resume];
}
#end
If you only have 3 or 4 appointments worth of data stored locally then the answer is "whatever is easiest for you." It really doesn't matter. You could convert the data to morse code and save dots and dashes and then read that and it would still be small and fast enough.
You can save the data to a plist, serialize it using NSCoding, save it as a SQLite database, or even write the XML and convert it back to an array on reading it (although the XML option is probably the slowest/least efficient.)
Core Data is very powerful (and very cool) but it also has a very steep learning curve. I would not recommend it until you are comfortable working with iOS.
If your application is timing out then there is probably something else wrong. Edit your question to show the code for the problem area and perhaps we can help.
I am trying to store data to iCloud documents, and read it on another device logged in with the same account.
I can detect iCloud, send data to iCloud and read it back on the same device. I can detect the file is there from the second device, but I get an error 'NSCocoaDomainError - code 260' when I try to read or copy the file.
File Store code:
//CREATE FILE
NSError *error;
NSLog(#"string to write:%#",printString);
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
if (ubiq == nil) {
return;
}
NSURL *cloudURL =[[ubiq URLByAppendingPathComponent:#"Documents" isDirectory:true] URLByAppendingPathComponent:#"CogwindInventory.txt"];
[printString writeToURL:cloudURL atomically:YES encoding:NSUTF8StringEncoding error:&error];
Code to run the query:
self.backups = [[NSMutableArray alloc] init];
self.query = [[NSMetadataQuery alloc] init];
[self.query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]];
NSPredicate *pred = [NSPredicate predicateWithFormat: #"%K like 'CogwindInventory.txt'", NSMetadataItemFSNameKey];
[self.query setPredicate:pred];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(queryDidFinishGatheringRestore:)
name:NSMetadataQueryDidFinishGatheringNotification
object:self.query];
[self.CloudActivityIndicator startAnimating];
[self.query startQuery];
- (void)queryDidFinishGatheringRestore:(NSNotification *)notification {
NSMetadataQuery *query = [notification object];
[query disableUpdates];
[query stopQuery];
[self loadDataRestore:query];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
self.query = nil;
}
- (void)loadDataRestore:(NSMetadataQuery *)query {
[self.backups removeAllObjects];
for (NSMetadataItem *item in [query results]) {
NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
//[self.backups addObject:url.lastPathComponent];
[self.backups addObject: url.filePathURL];
}
if (self.backups.count > 0) {
[self retrievefile];
}
[self OperationComplete];
}
Code to do the read:
- (void) retrievefile
{
NSError *error = nil;
NSURL *ubiq = [self.manager URLForUbiquityContainerIdentifier:nil];
if (ubiq == nil) {
return;
}
NSURL *cloudURL =[self.backups objectAtIndex:0];
NSArray *localtoken = [[NSString stringWithContentsOfURL:cloudURL encoding:NSUTF8StringEncoding error:&error] componentsSeparatedByString:#"\n"];
if ((localtoken == nil) || (error !=nil)) {
[self.CloudStatusText setText: #"Restore operation failed."];
return;
} else {
[self.tokeninventory setPlayerInventoryNames:localtoken];
[self.CloudStatusText setText: #"Restore operation successful. New inventory available"];
}
}
The devices are OS 8.1.1 and OS 8.3. iCloud- Documents is enabled in Xcode, but not iCloudKit.
Any help appreciated. Thank you.
I am working on app which use Google API. I am trying to find places around me by it. I am using below code for fetch data,
-(void)fetchedData:(NSData *)responseData {
//this is to parse out the json data
NSError *error = nil; //create some error handling here
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];
//I'm told the returned results from Google will be an array obtained from the NSDictionary object with the key "results"
NSArray *places = [json objectForKey:#"results"];
//display the data to the console for review
NSLog(#" Google data:\n%#", places);
}
But it shows json status = Request Denied.
Any help will appreciated.
Vishal,
You can do it using the following block of Code:
- (void) queryGooglePlaces: (NSString *) googleType
{
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=%#&types=%#&sensor=true&key=%#&language=%#", appDelegate.currentLatitude, appDelegate.currentLongitude, [radiusValueArray objectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:#"selectedDistance"]], googleType, kGOOGLE_API_KEY, appDelegate.selectedLanguageCode];
//Formulate the string as URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
if(data == nil)
{
[placeTableView reloadData];
[SVProgressHUD dismiss];
}
else
{
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
}
});
}
- (void) queryGooglePlaces_WithNextPage
{
// Build the url string we are going to sent to Google. NOTE: The kGOOGLE_API_KEY is a constant which should contain your own API key that you can obtain from Google. See this link for more info:
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/search/json?pagetoken=%#&location=%f,%f&radius=%#&sensor=true&key=%#", nextPageToken, appDelegate.currentLatitude, appDelegate.currentLongitude, [radiusValueArray objectAtIndex:[[NSUserDefaults standardUserDefaults] integerForKey:#"selectedDistance"]], kGOOGLE_API_KEY];
//Formulate the string as URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
if(data == nil)
{
[placeTableView reloadData];
[SVProgressHUD dismiss];
}
else
{
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
}
});
}
- (void)fetchedData:(NSData *)responseData
{
//parse out the json data
NSError* error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
//The results from Google will be an array obtained from the NSDictionary object with the key "results".
if(isNextPageAvailable == FALSE)
[appDelegate.placesArray removeAllObjects];
NSArray *placesTemp = [json objectForKey:#"results"];
if([json valueForKey:#"next_page_token"] != nil)
{
nextPageToken = [json valueForKey:#"next_page_token"];
isNextPageAvailable = TRUE;
}
else
{
nextPageToken = #"";
isNextPageAvailable = FALSE;
}
for(int i=0;i<[placesTemp count];i++)
{
NSMutableDictionary *placeDictionary = [[NSMutableDictionary alloc] initWithDictionary:[placesTemp objectAtIndex:i]];
double lat1 = appDelegate.currentLatitude;
double long1 = appDelegate.currentLongitude;
double lat2 = [[[[placeDictionary objectForKey:#"geometry"] objectForKey:#"location"] valueForKey:#"lat"] doubleValue];
double long2 = [[[[placeDictionary objectForKey:#"geometry"] objectForKey:#"location"] valueForKey:#"lng"] doubleValue];
CLLocation *location1 = [[CLLocation alloc] initWithLatitude:lat1 longitude:long1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:lat2 longitude:long2];
[placeDictionary setValue:[NSString stringWithFormat:#"%f",[location1 distanceFromLocation:location2]] forKey:#"distance"];
[appDelegate.placesArray addObject:placeDictionary];
}
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"distance" ascending:YES comparator:^NSComparisonResult(id obj1, id obj2) {
if ([obj1 floatValue] < [obj2 floatValue])
return NSOrderedAscending;
else
return NSOrderedDescending;
}];
NSArray *sortedArray = [appDelegate.placesArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
[appDelegate.placesArray removeAllObjects];
[appDelegate.placesArray addObjectsFromArray:sortedArray];
[self showPoweredbyGoogle];
[placeTableView reloadData];
[SVProgressHUD dismiss];
// [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:#selector(reloadTableNow) userInfo:nil repeats:NO];
//Plot the data in the places array onto the map with the plotPostions method.
// [self plotPositions:placesArray];
}
- (void) queryGooglePlaceDetail
{
NSString *url = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/place/details/json?reference=%#&sensor=false&key=%#&language=%#", [[appDelegate.placesArray objectAtIndex:selectedPlaceIndex] valueForKey:#"reference"], kGOOGLE_API_KEY, appDelegate.selectedLanguageCode];
//Formulate the string as URL object.
NSURL *googleRequestURL=[NSURL URLWithString:url];
// Retrieve the results of the URL.
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: googleRequestURL];
if(data == nil)
{
[SVProgressHUD dismiss];
}
else
{
[self performSelectorOnMainThread:#selector(fetchedDetailPlaceData:) withObject:data waitUntilDone:YES];
}
});
}
- (void)fetchedDetailPlaceData:(NSData *)responseData
{
//parse out the json data
NSError* error;
NSDictionary *json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error];
NSDictionary *detailTempDic = [[NSMutableDictionary alloc] initWithDictionary:[json objectForKey:#"result"]];
[detailTempDic setValue:[[appDelegate.placesArray objectAtIndex:selectedPlaceIndex] valueForKey:#"distance"] forKey:#"distance"];
[SVProgressHUD dismiss];
[self performSegueWithIdentifier:#"Detail_Place_Push" sender:detailTempDic];
}
Here you have to pass different types of objects from Google Places such as atm, airport, restaurant, bank, hospital, school.
[self queryGooglePlaces:[googlePlaceTypeArray objectAtIndex:SharedManager.selectedPlaceCategoryIndex]];
Thanks,
Best Regards,
Gurprit
I am trying to implement Core Data in an iOS 7 app (and have successfully done so earlier). However, when I execute the executeFetchRequest method, the app crashes. The most relevant code is added below:
#import "JTHuntingSeasonDB.h"
#implementation JTHuntingSeasonDB
- (id)init {
self = [super init];
if (self) {
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSString *documentName = #"JTHuntingDB";
NSURL *url = [documentsDirectory URLByAppendingPathComponent:documentName];
document = [[UIManagedDocument alloc] initWithFileURL:url];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[url path]];
if (fileExists) {
[document openWithCompletionHandler:^(BOOL success) {
if (success) {
NSLog(#"Document opened successfully");
self.allSpecies = [self getSpecies];
self.speciesToday = [self getSpeciesToday];
} else NSLog(#"Failed to open document");
}];
} else {
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if (success) {
NSLog(#"Document created successfully");
self.allSpecies = [self getSpecies];
self.speciesToday = [self getSpeciesToday];
} else NSLog(#"Failed to create document, path: %#", url);
}];
}
}
return self;
}
#pragma mark - Core Data
- (NSArray *)getSpecies {
if (document.documentState == UIDocumentStateNormal) {
context = document.managedObjectContext;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *country = [defaults stringForKey:#"Country"];
NSString *subregion = [defaults stringForKey:#"Subregion"];
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"HuntingDates"];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES selector:#selector(localizedStandardCompare:)];
request.fetchBatchSize = 150;
request.fetchLimit = 150;
request.sortDescriptors = #[sortDescriptor];
if (subregion.length > 0) {
request.predicate = [NSPredicate predicateWithFormat:#"(country IN %#) AND (subregion IN %#)", country, subregion];
} else {
request.predicate = [NSPredicate predicateWithFormat:#"country IN %#", country];
}
NSError *error;
return [context executeFetchRequest:request error:&error];
}
return nil;
}
The line
return [context executeFetchRequest:request error:&error];
causes the app to crash. This is what I have done and discovered so far:
Simulator: Deleted app and reset content and settings
Xcode: Clean (Build folder)
"context" is not nil
NSLog prints out "Document created/opened successfully"
Only "lldb" is printed in the console when the app crashes
Edit:
After following Wain's advice, I turned exception breakpoint off, got a more descriptive error message saying that the predicate was invalid. Problem solved by replacing IN in the predicate with CONTAINS and also changing the variable "country" so that it did not return nil anymore.
I guess it's your predicates, because IN is a collection operator but you're passing strings (should be array / set).
If you're using strings, you should be using CONTAINS in the predicate.
Assuming the CoreData persistent store lives inside the document, you will want to use a UIManagedDocument
Trying to populate core data structure using JSON,
The code is listed below?
NSManagedObjectContext *context = managedObjectContext();
// Save the managed object context
NSError *error = nil;
if (![context save:&error]) {
NSLog(#"Error while saving %#", ([error localizedDescription] != nil) ? [error localizedDescription] : #"Unknown Error");
exit(1);
}
NSError* err = nil;
NSString* dataPath = [[NSBundle mainBundle] pathForResource:#"Exercises" ofType:#"json"];
NSArray* Exercises = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath]
options:kNilOptions
error:&err];
NSLog(#"Imported Exercises: %#", Exercises);
NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:#"Exercise" inManagedObjectContext:context];
NSString *theJSONString = #"{\"key\":\"value\"}";
NSError *theError = NULL;
NSDictionary *jsonDict = [NSDictionary dictionaryWithJSONString:theJSONString error:&theError];
Exercise *exercise = [NSEntityDescription insertNewObjectForEntityForName:#"Exercise"
inManagedObjectContext:context];
[Exercises enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSDictionary *attributes = [[object entity] attributesByName];
for (NSString *attribute in attributes) {
id value = [jsonDict objectForKey:attribute];
if (value == nil) {
continue;
}
[exercise setValue:value forKey:attribute];
}
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}];
The code compiles and after analysing the sqlite database created, all attributes are filled with null values.
NSString* secondDataPath = [[NSBundle mainBundle] pathForResource:#"Weights" ofType:#"json"];
NSArray* weightsFromJSON = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:secondDataPath]
options:kNilOptions
error:&err];
NSLog(#"Imported weightsFromJSON: %#", weightsFromJSON);
[weightsFromJSON enumerateObjectsUsingBlock:^(NSDictionary *weightDictionary, NSUInteger idx, BOOL *stop) {
Weight *weight = [NSEntityDescription insertNewObjectForEntityForName:#"Weight"
inManagedObjectContext:context];
NSDictionary *attributes = [[weight entity] attributesByName];
for (NSString *attribute in [attributes allKeys]) {
id value = [weightDictionary objectForKey:attribute];
if (value == nil) {
continue;
}
[weight setValue:value forKey:attribute];
}
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}];
Edited the code above for the second entity, but fails stating data parameter is hill
You're enumerating every object loaded from the JSON data on disk that you put into Exercises (as an aside, don't capitalize the names of local variables) but then you are not using those objects as the data source, instead you're using jsonDict which is hard-coded from a string and has only one key/value pair. Try changing the line
id value = [jsonDict objectForKey:attribute];
To instead say:
id value = [(NSDictionary *)obj objectForKey:attribute];
That should actually apply the data you loaded. However, there are other problems in your code - you only insert a single entity, not one for each element in Exercises, as well as inserting an extraneous one that you assign to object. Here's some code that I think may do what you're trying to do:
NSError* err = nil;
NSString* dataPath = [[NSBundle mainBundle] pathForResource:#"exercisesFromJSON" ofType:#"json"];
NSArray* exercisesFromJSON = [NSJSONSerialization JSONObjectWithData:[NSData dataWithContentsOfFile:dataPath]
options:kNilOptions
error:&err];
NSLog(#"Imported exercisesFromJSON: %#", exercisesFromJSON);
[exercisesFromJSON enumerateObjectsUsingBlock:^(NSDictionary exerciseDictionary, NSUInteger idx, BOOL *stop) {
Exercise *exercise = [NSEntityDescription insertNewObjectForEntityForName:#"Exercise"
inManagedObjectContext:context];
NSDictionary *attributes = [[exercise entity] attributesByName];
for (NSString *attribute in [attributes allKeys]) {
id value = [exerciseDictionary objectForKey:attribute];
if (value == nil) {
continue;
}
[exercise setValue:value forKey:attribute];
}
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}];