Healthkit: Data not showing first time running. - ios

I have a strange problem when reading data out of healthkit. The first time when i press the button the weight is printed 0, the next times i press the button the weight is printed as normal.I would really appreciate it if someone could help me.
Thanks!
I have the following code.
HealtkitManager.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <HealthKit/HealthKit.h>
#interface HealthKitManager : NSObject
#property (nonatomic) float weight;
#property (nonatomic) HKHealthStore *healthStore;
+(HealthKitManager *)sharedManager;
-(void) requestAuthorization;
-(double) readWeight;
#end
Healthkitmanager.m
#import "HealthKitManager.h"
#import <healthKit/healthKit.h>
#import "StartScreen.h"
#interface HealthKitManager ()
#end
#implementation HealthKitManager
+(HealthKitManager *) sharedManager{
static dispatch_once_t pred = 0;
static HealthKitManager *instance = nil;
dispatch_once(&pred, ^{
instance = [[HealthKitManager alloc]init];
instance.healthStore = [[HKHealthStore alloc]init];
});
return instance;
}
-(void)requestAuthorization {
if([HKHealthStore isHealthDataAvailable]==NO){
return;
}
NSArray *readTypes = #[[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMassIndex],
[HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyFatPercentage]];
[self.healthStore requestAuthorizationToShareTypes:nil readTypes:[NSSet setWithArray:readTypes] completion:nil];
}
-(double) readWeight{
NSMassFormatter *massFormatter = [[NSMassFormatter alloc]init];
massFormatter.unitStyle = NSFormattingUnitStyleLong;
HKQuantityType *weightType = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierBodyMass];
[self fetchMostRecentDataOfQuantityType:weightType withCompletion:^(HKQuantity *mostRecentQuantity, NSError *error) {
if(!mostRecentQuantity){
NSLog(#"%#",#"Error. ");
}
else{
HKUnit *weightUnit = [HKUnit gramUnit];
_weight = [mostRecentQuantity doubleValueForUnit:weightUnit];
_weight = (float)_weight/1000.00f;
}
}];
return _weight;
}
- (void)fetchMostRecentDataOfQuantityType:(HKQuantityType *)quantityType withCompletion:(void (^)(HKQuantity *mostRecentQuantity, NSError *error))completion {
NSSortDescriptor *timeSortDescriptor = [[NSSortDescriptor alloc] initWithKey:HKSampleSortIdentifierEndDate ascending:NO];
HKSampleQuery *query = [[HKSampleQuery alloc] initWithSampleType:quantityType predicate:nil limit:1 sortDescriptors:#[timeSortDescriptor] resultsHandler:^(HKSampleQuery *query, NSArray *results, NSError *error) {
if (!results) {
if (completion) {
completion(nil, error);
}
return;
}
if (completion) {
HKQuantitySample *quantitySample = results.firstObject;
HKQuantity *quantity = quantitySample.quantity;
completion(quantity, error);
}
}];
[self.healthStore executeQuery:query];
}
#end
Startscreen.m
#import "StartScreen.h"
#import "HealthKitManager.h"
#interface StartScreen ()
#property(nonatomic,weak) IBOutlet UILabel *weightLabel;
#end
#implementation StartScreen
- (void)viewDidLoad {
[super viewDidLoad];
[[HealthKitManager sharedManager] requestAuthorization];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)readAgeButtonPressed:(id)sender{
HealthKitManager *readWeight = [[HealthKitManager sharedManager] init];
NSLog(#"%.2f",readWeight.readWeight);
}
#end

You use singleton HealthKitManager but your code
HealthKitManager *readWeight = [[HealthKitManager sharedManager] init];
in IBAction readAgeButtonPressed should be
HealthKitManager *readWeight = [HealthKitManager sharedManager];
You don't need init.
Also, you can change the code
[[HealthKitManager sharedManager] requestAuthorization];
to be
HealthKitManager *readWeight = [HealthKitManager sharedManager];
[readWeight requestAuthorization];
NSLog(#"%.2f",readWeight.readWeight);
checking the value of readWeight.

Related

Increasing update rate of CMPedometer [duplicate]

I've found very limited resources on this topic (CMPedometer). I was wondering if anyone here has managed to get this to work properly. My code is fairly simple, and has more than what I'm trying to do. Basically, the step counter does not increment EVERY step a user takes.
It actually is tracking every step the user takes but it updates so slowly and I can't figure out why. I even tried using NSTimer to make a request to update the labels every half a second. I want to try to get the step counter to update as a user takes a step. Here is my code...
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
#interface ViewController ()
#property (nonatomic, strong) CMPedometer *pedometer;
#property (nonatomic, weak) IBOutlet UILabel *startDateLabel;
#property (nonatomic, weak) IBOutlet UILabel *endDateLabel;
#property (nonatomic, weak) IBOutlet UILabel *stepsLabel;
#property (nonatomic, weak) IBOutlet UILabel *distanceLabel;
#property (nonatomic, weak) IBOutlet UILabel *ascendedLabel;
#property (nonatomic, weak) IBOutlet UILabel *descendedLabel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
if ([CMPedometer isStepCountingAvailable]) {
self.pedometer = [[CMPedometer alloc] init];
[NSTimer scheduledTimerWithTimeInterval:0.5f
target:self
selector:#selector(recursiveQuery)
userInfo:nil
repeats:YES];
} else {
NSLog(#"Nothing available");
self.startDateLabel.text = #"";
self.endDateLabel.text = #"";
self.stepsLabel.text = #"";
self.distanceLabel.text = #"";
self.ascendedLabel.text = #"";
self.descendedLabel.text = #"";
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.pedometer startPedometerUpdatesFromDate:[NSDate date]
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"data:%#, error:%#", pedometerData, error);
});
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.pedometer stopPedometerUpdates];
}
- (NSString *)stringWithObject:(id)obj {
return [NSString stringWithFormat:#"%#", obj];
}
- (NSString *)stringForDate:(NSDate *)date {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterShortStyle;
return [formatter stringFromDate:date];
}
- (void)queryDataFrom:(NSDate *)startDate toDate:(NSDate *)endDate {
[self.pedometer queryPedometerDataFromDate:startDate
toDate:endDate
withHandler:
^(CMPedometerData *pedometerData, NSError *error) {
NSLog(#"data:%#, error:%#", pedometerData, error);
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(#"Error = %#",error.userInfo);
self.startDateLabel.text = #"";
self.endDateLabel.text = #"";
self.stepsLabel.text = #"";
self.distanceLabel.text = #"";
self.ascendedLabel.text = #"";
self.descendedLabel.text = #"";
} else {
self.startDateLabel.text = [self stringForDate:pedometerData.startDate];
self.endDateLabel.text = [self stringForDate:pedometerData.endDate];
self.stepsLabel.text = [self stringWithObject:pedometerData.numberOfSteps];
self.distanceLabel.text = [NSString stringWithFormat:#"%.1f[m]", [pedometerData.distance floatValue]];
self.ascendedLabel.text = [self stringWithObject:pedometerData.floorsAscended];
self.descendedLabel.text = [self stringWithObject:pedometerData.floorsDescended];
}
});
}];
}
- (void)recursiveQuery {
NSDate *to = [NSDate date];
NSDate *from = [to dateByAddingTimeInterval:-(24. * 3600.)];
[self queryDataFrom:from toDate:to];
}
Thanks in advance for any feedback!
EDIT
It seems the appropriate method to use for live updates is the following..
- (void)liveSteps {
[self.pedometer startPedometerUpdatesFromDate:[NSDate date]
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Steps %#",pedometerData.numberOfSteps);
});
}];
}
However, even this is severely delayed. Does anyone have any idea how to use this properly to essentially update as the user takes a step?
I can only confirm your findings. I also wanted to get "true" realtime information. As it seems at this point, the API is not capable of this; even by forcing the updates into a queue, sync, async, etc.
For references and others with this question, here is the code I use based on Swift 3 and Xcode 8.2. I simply apply this portion of code in the concerned viewcontroller, after checking the CMPedometer.isStepCountingAvailable().
As you can see, I've included a small animation to update the UILabel in a more fluid manner.
// Steps update in near realtime - UILabel
self.pedoMeter.startUpdates(from: midnightOfToday) { (data: CMPedometerData?, error) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
if(error == nil){
self.todaySteps.text = "\(data!.numberOfSteps)"
// Animate the changes of numbers in the UILabel
UILabel.transition(with: self.todaySteps,
duration: 0.50,
options: .transitionCrossDissolve,
animations: nil,
completion: nil)
}
})
}

How to get the value of variable within the blocks

Is there anyway to check the value of 'type' variable with completionHandler.
-(void)sendApiMethod:(NSString*)apiName ApiType:(NSString*)type
{
[SendAPI setAPIWithName:#"APIName" completionHandler:^(NSArray *errors) {
if([type isEqualToString:#"Login"])
{
/// Call Some Other function
}
}];
}
I wrote a small piece of code to verify if works (only reading your question I would say yes as Droppy)
I added all there code in a ViewController in a Simple View App.
some assumption:
- all code there for sake of semplicity ....
- I have added a singleton as it seems You are calling a class method.
- instance method is a bit rough, it simply saves name and block
- I added a typedef for blocks to better reading it.
#import "ViewController.h"
typedef void (^CompletionBlock)(NSArray *errors);
#interface SendAPI : NSObject
-(void)setAPIWithName:(NSString*)name completionHandler: (CompletionBlock)completionHandler;
+(void)setAPIWithName:(NSString*)name completionHandler: (CompletionBlock)completionHandler;
+(SendAPI*)sharedInstance;
#property (strong) CompletionBlock completionBlock;
#property (strong) NSString * name;
#end
#implementation SendAPI : NSObject
static SendAPI * _singleton = nil;
+(SendAPI*)sharedInstance
{
if (_singleton == nil)
{
_singleton = [[SendAPI alloc] init];
}
return _singleton;
}
-(void)setAPIWithName:(NSString*)name completionHandler: (CompletionBlock)completionHandler;
{
self.completionBlock = completionHandler;
self.name = [name copy];
__weak SendAPI * weakRef = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSError* err = [NSError errorWithDomain: #"delayed"
code:1111
userInfo: #{#"info": self.name}
];
weakRef.completionBlock(#[err]);
});
}
+(void)setAPIWithName:(NSString*)name completionHandler: (CompletionBlock)completionHandler;
{
[[SendAPI sharedInstance]setAPIWithName:name completionHandler:completionHandler];
}
#end
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self sendApiMethod:#"HELLO" ApiType: #"Login"];
}
-(void)sendApiMethod:(NSString*)apiName ApiType:(NSString*)type{
[SendAPI setAPIWithName:#"APIName" completionHandler:^(NSArray *errors) {
if([type isEqualToString:#"Login"])
{
/// Call Some Other function
NSLog(#"%#", errors);
}
}];
}
it does LOG correctly

Live Updates with CMPedometer (CoreMotion)

I've found very limited resources on this topic (CMPedometer). I was wondering if anyone here has managed to get this to work properly. My code is fairly simple, and has more than what I'm trying to do. Basically, the step counter does not increment EVERY step a user takes.
It actually is tracking every step the user takes but it updates so slowly and I can't figure out why. I even tried using NSTimer to make a request to update the labels every half a second. I want to try to get the step counter to update as a user takes a step. Here is my code...
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>
#interface ViewController ()
#property (nonatomic, strong) CMPedometer *pedometer;
#property (nonatomic, weak) IBOutlet UILabel *startDateLabel;
#property (nonatomic, weak) IBOutlet UILabel *endDateLabel;
#property (nonatomic, weak) IBOutlet UILabel *stepsLabel;
#property (nonatomic, weak) IBOutlet UILabel *distanceLabel;
#property (nonatomic, weak) IBOutlet UILabel *ascendedLabel;
#property (nonatomic, weak) IBOutlet UILabel *descendedLabel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
if ([CMPedometer isStepCountingAvailable]) {
self.pedometer = [[CMPedometer alloc] init];
[NSTimer scheduledTimerWithTimeInterval:0.5f
target:self
selector:#selector(recursiveQuery)
userInfo:nil
repeats:YES];
} else {
NSLog(#"Nothing available");
self.startDateLabel.text = #"";
self.endDateLabel.text = #"";
self.stepsLabel.text = #"";
self.distanceLabel.text = #"";
self.ascendedLabel.text = #"";
self.descendedLabel.text = #"";
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.pedometer startPedometerUpdatesFromDate:[NSDate date]
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"data:%#, error:%#", pedometerData, error);
});
}];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.pedometer stopPedometerUpdates];
}
- (NSString *)stringWithObject:(id)obj {
return [NSString stringWithFormat:#"%#", obj];
}
- (NSString *)stringForDate:(NSDate *)date {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateStyle = NSDateFormatterShortStyle;
formatter.timeStyle = NSDateFormatterShortStyle;
return [formatter stringFromDate:date];
}
- (void)queryDataFrom:(NSDate *)startDate toDate:(NSDate *)endDate {
[self.pedometer queryPedometerDataFromDate:startDate
toDate:endDate
withHandler:
^(CMPedometerData *pedometerData, NSError *error) {
NSLog(#"data:%#, error:%#", pedometerData, error);
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(#"Error = %#",error.userInfo);
self.startDateLabel.text = #"";
self.endDateLabel.text = #"";
self.stepsLabel.text = #"";
self.distanceLabel.text = #"";
self.ascendedLabel.text = #"";
self.descendedLabel.text = #"";
} else {
self.startDateLabel.text = [self stringForDate:pedometerData.startDate];
self.endDateLabel.text = [self stringForDate:pedometerData.endDate];
self.stepsLabel.text = [self stringWithObject:pedometerData.numberOfSteps];
self.distanceLabel.text = [NSString stringWithFormat:#"%.1f[m]", [pedometerData.distance floatValue]];
self.ascendedLabel.text = [self stringWithObject:pedometerData.floorsAscended];
self.descendedLabel.text = [self stringWithObject:pedometerData.floorsDescended];
}
});
}];
}
- (void)recursiveQuery {
NSDate *to = [NSDate date];
NSDate *from = [to dateByAddingTimeInterval:-(24. * 3600.)];
[self queryDataFrom:from toDate:to];
}
Thanks in advance for any feedback!
EDIT
It seems the appropriate method to use for live updates is the following..
- (void)liveSteps {
[self.pedometer startPedometerUpdatesFromDate:[NSDate date]
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Steps %#",pedometerData.numberOfSteps);
});
}];
}
However, even this is severely delayed. Does anyone have any idea how to use this properly to essentially update as the user takes a step?
I can only confirm your findings. I also wanted to get "true" realtime information. As it seems at this point, the API is not capable of this; even by forcing the updates into a queue, sync, async, etc.
For references and others with this question, here is the code I use based on Swift 3 and Xcode 8.2. I simply apply this portion of code in the concerned viewcontroller, after checking the CMPedometer.isStepCountingAvailable().
As you can see, I've included a small animation to update the UILabel in a more fluid manner.
// Steps update in near realtime - UILabel
self.pedoMeter.startUpdates(from: midnightOfToday) { (data: CMPedometerData?, error) -> Void in
DispatchQueue.main.async(execute: { () -> Void in
if(error == nil){
self.todaySteps.text = "\(data!.numberOfSteps)"
// Animate the changes of numbers in the UILabel
UILabel.transition(with: self.todaySteps,
duration: 0.50,
options: .transitionCrossDissolve,
animations: nil,
completion: nil)
}
})
}

NSSet property returning count of 1 when added to CoreData via Mantle

so I have an object with several properties that I want to add to coredata however I'm using the Mantle framework that I am not too familiar with.
My Object(.h):
#import <Foundation/Foundation.h>
#import "RTModel.h"
#import CoreLocation;
#class RTPhoto;
#class RTContact;
#class RTUser;
#interface MyInteraction : RTModel <NSCopying, MTLJSONSerializing>
+ (NSManagedObject *)managedObjectWithIdentifier:(NSNumber *)identifier;
- (NSManagedObject *)managedObject;
#property (nonatomic, strong) NSNumber *latitude;
#property (nonatomic, strong) NSNumber *longitude;
#property (strong, nonatomic) RTUser *user;
#property (nonatomic, strong) NSNumber *createdByID;
#property (nonatomic, copy) NSString *createdByLabel;
#property (nonatomic, copy) NSString *interactedWithLabel;
#property (strong, nonatomic) NSString *publicShareURLString;
#property (nonatomic, strong) NSSet *photos;
- (void)addPhotosObject:(RTPhoto *)photo;
#end
My Object(.m):
#import "OUTInteraction.h"
#import "RTComment.h"
#import "RTPhoto.h"
#import "RTUser.h"
#import "RTContact.h"
#import "OUTCoreDataController.h"
#import "OUTInteractionsController.h"
#interface MyInteraction () <UIActionSheetDelegate>
#end
#implementation MyInteraction
#synthesize identifier = _identifier;
#synthesize createdAt = _createdAt;
#synthesize updatedAt = _updatedAt;
- (void)deleteWithCompletion:(void (^)(NSError *))completion
{
NSManagedObject *managedObject = [self managedObject];
if (!managedObject) {
completion(nil);
};
[[[MyCoreDataController sharedController] persistenceController] deleteObject:managedObject
saveContextAndWait:YES
completion:^(NSError *error) {
completion(error);
}];
}
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return [[super JSONKeyPathsByPropertyKey] mtl_dictionaryByAddingEntriesFromDictionary: #{
#"createdByID" : #"created_by_id",
#"createdByLabel" : #"created_by_label",
#"interactedWithLabel" : #"interacted_with_label",
#"interactionType" : #"interaction_type",
#"latitude" : #"latitude",
#"longitude" : #"longitude",
#"formID" : #"form_id",
#"formEntries" : #"form_entries",
#"interactedWithCity" : #"interacted_with_city",
#"interactedWithRegion" : #"interacted_with_region",
#"publicShareURLString" : #"share_url",
#"photos" : #"images"
}];
}
#pragma mark - Photos
- (void)addPhotosObject:(RTPhoto *)photo
{
if (!photo) return;
NSMutableSet *mutablePhotos = [NSMutableSet setWithSet:self.photos];
[mutablePhotos addObject:photo];
self.photos = [mutablePhotos copy];
}
- (BOOL)hasPhotoToDisplay
{
if (!self.photos) return NO;
if ([[self.photos allObjects] count] > 0) return YES;
return NO;
}
#pragma mark - JSON Transformers
/// #note used by Mantle
+ (NSValueTransformer *)photosJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *array) {
NSMutableSet *mutableSet = [NSMutableSet set];
[array enumerateObjectsUsingBlock:^(NSDictionary *JSON, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTPhoto *item = [MTLJSONAdapter modelOfClass:[RTPhoto class]
fromJSONDictionary:JSON
error:&error];
if (error) DDLogError([error description], nil);
[mutableSet addObject:item];
}];
NSLog(#"mutable set");
return mutableSet;
} reverseBlock:^id(NSSet *set) {
NSLog(#"all objects");
return [set allObjects];
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)commentsJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *array) {
NSMutableSet *mutableSet = [NSMutableSet set];
[array enumerateObjectsUsingBlock:^(NSDictionary *JSON, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTComment *item = [MTLJSONAdapter modelOfClass:[RTComment class]
fromJSONDictionary:JSON
error:&error];
if (error) DDLogError([error description], nil);
[mutableSet addObject:item];
}];
return mutableSet;
} reverseBlock:^id(NSSet *set) {
return [set allObjects];
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)contactsJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *array) {
NSMutableSet *mutableSet = [NSMutableSet set];
[array enumerateObjectsUsingBlock:^(NSDictionary *JSON, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTComment *item = [MTLJSONAdapter modelOfClass:[RTContact class]
fromJSONDictionary:JSON
error:&error];
if (error) DDLogError([error description], nil);
[mutableSet addObject:item];
}];
return mutableSet;
} reverseBlock:^id(NSSet *set) {
return [set allObjects];
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)formEntriesJSONTransformer
{
return [MTLValueTransformer reversibleTransformerWithForwardBlock:^id(NSArray *entryDictionaries) {
NSMutableSet *set = [NSMutableSet set];
[entryDictionaries enumerateObjectsUsingBlock:^(NSDictionary *entryDict, NSUInteger idx, BOOL *stop) {
NSError *error = nil;
RTInteractionFormEntry *entry = [MTLJSONAdapter modelOfClass:[RTInteractionFormEntry class]
fromJSONDictionary:entryDict
error:&error];
[set addObject:entry];
}];
return set;
} reverseBlock:^id(NSSet *set) {
NSMutableArray *array = [NSMutableArray array];
[set enumerateObjectsUsingBlock:^(RTInteractionFormEntry *entry, BOOL *stop) {
[array addObject:[entry jsonDictionary]];
}];
return array;
}];
}
/// #note used by Mantle
+ (NSValueTransformer *)userJSONTransformer
{
return [MTLValueTransformer mtl_JSONDictionaryTransformerWithModelClass:[RTUser class]];
}
/// #note used by Mantle
+ (NSValueTransformer *)interactionTypeJSONTransformer
{
return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:#{
#"email" : #(kRTInteractionTypeEmail),
#"check_in" : #(kRTInteractionTypeCheckIn),
#"note" : #(kRTInteractionTypeNote),
#"meeting" : #(kRTInteractionTypeMeeting)
}];
}
#pragma mark - Core Data
+ (NSString *)managedObjectEntityName
{
return #"Interaction";
}
+ (NSSet *)propertyKeysForManagedObjectUniquing
{
return [NSSet setWithArray:#[#"identifier"]];
}
+ (NSDictionary *)managedObjectKeysByPropertyKey
{
return [[super managedObjectKeysByPropertyKey] mtl_dictionaryByAddingEntriesFromDictionary:#{
#"metadata" : [NSNull null],
#"identifier" : #"interactionIdentifier",
}];
}
+ (NSDictionary *)relationshipModelClassesByPropertyKey
{
return [[super relationshipModelClassesByPropertyKey] mtl_dictionaryByAddingEntriesFromDictionary:#{
#"comments" : [RTComment class],
#"formEntries" : [RTInteractionFormEntry class],
#"photos" : [RTPhoto class],
#"contacts" : [RTContact class],
#"user" : [RTUser class]
}];
}
#pragma mark - Actions
- (void)delete
{
[[MyInteractionsController controller] deleteInteraction:self
success:^{
} failure:^(NSError *error) {
DDLogError([error description], nil);
}];
}
+ (NSManagedObject *)managedObjectWithIdentifier:(NSNumber *)identifier
{
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[MyInteraction managedObjectEntityName]];
fetchRequest.predicate = [NSPredicate predicateWithFormat:#"interactionIdentifier == %#", identifier];
fetchRequest.fetchLimit = 1;
NSManagedObjectContext *managedObjectContext = [[MyCoreDataController sharedController] managedObjectContext];
NSError *error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:fetchRequest
error:&error];
NSLog(#"Results: %#", results);
if (error) {
DDLogError(#"Error fetching managed object: %#", [error description]);
}
return [results firstObject];
}
- (NSManagedObject *)managedObject
{
return [MyInteraction managedObjectWithIdentifier:self.identifier];
}
- (void)mergeValuesForKeysFromManagedObject:(NSManagedObject *)managedObject
{
if ([managedObject valueForKey:#"photos"]) {
NSMutableSet *combinedPhotos = [NSMutableSet setWithSet:self.photos];
for (NSManagedObject *photoManagedObject in [managedObject valueForKey:#"photos"]) {
RTPhoto *photo = [MTLManagedObjectAdapter modelOfClass:[RTPhoto class]
fromManagedObject:photoManagedObject
error:nil];
if (photo.identifier || photo.localImageData || photo.imageDataPendingUpload) {
[combinedPhotos addObject:photo];
}
}
self.photos = [combinedPhotos copy];
}
}
#end
Basically the problem I'm having when adding the whole object to CoreData
via Mantle is that everything gets added except when it reaches the photos property which is a NSSet it only adds one of the objects, usually the last one.
Here is when the object is added to the context using Mantle(in another file):
[MTLManagedObjectAdapter managedObjectFromModel:interaction
insertingIntoContext:self.context
error:&coreDataError];
If someone has any clue as to why there is only one photos object being added under the "photos" key. I'm unfamiliar with how mantle handles toMany relationships and how to get all of the children added. Thanks

In Core data unable to store objects

My code here i am trying to add list of object in to my array form that array i trying to add it to code data attributes.
#import "ViewController.h"
#import "model.h"
#import "coredataManager.h"
#interface ViewController ()
{
NSMutableArray *entries;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
entries = [[NSMutableArray alloc]init];
coredataManager *coreobj = [[coredataManager alloc]init];
model *obj = [[model alloc]initWithContents:#"1" alternateLink:#"1" DownloadURL:#"1"];
model *obj2 = [[model alloc]initWithContents:#"2" alternateLink:#"2" DownloadURL:#"2"];
model *obj3 = [[model alloc]initWithContents:#"3" alternateLink:#"3" DownloadURL:#"3"];
[entries addObject:obj];
[entries addObject:obj2];
[entries addObject:obj3];
NSLog(#"%#",entries);
[coreobj StoreValues:entries];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
my NSObject Class
#import <Foundation/Foundation.h>
#interface model : NSObject
#property(copy)NSString *filename;
#property(copy)NSString *alternatelink;
#property(copy)NSString *downloadurl;
-(id)initWithContents:(NSString *)Fname alternateLink :(NSString *) ALink DownloadURL :(NSString *)DURL;
#end
NSObject Implementation File
#import "model.h"
#implementation model
#synthesize downloadurl,filename,alternatelink;
-(id)initWithContents:(NSString *)Fname alternateLink :(NSString *) ALink DownloadURL :(NSString *)DURL
{
if ((self = [super init])) {
downloadurl = [DURL copy];
filename = [Fname copy];
alternatelink = [ALink copy];
}
return self;
}
#end
Code to store in core data
-(void)StoreValues:(NSMutableArray *) sample
{
Sample *value = [NSEntityDescription insertNewObjectForEntityForName:#"Sample"
inManagedObjectContext:self.managedObjectContext];
for (int i=0;i<sample.count;i++)
{
model *obj=[sample objectAtIndex:i];
value.url = obj.downloadurl;
value.filename = obj.filename;
value.alternate = obj.alternatelink;
}
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
But only the last value of the array is getting stored in the core data can any one guide me solve this issue
Thanks in advance.
Before you save, you rewrite the object. Do this instead:
Sample *value;
for (int i=0;i<sample.count;i++)
{
value = [NSEntityDescription insertNewObjectForEntityForName:#"Sample"
inManagedObjectContext:self.managedObjectContext];
model *obj=[sample objectAtIndex:i];
value.url = obj.downloadurl;
value.filename = obj.filename;
value.alternate = obj.alternatelink;
NSError *error;
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
}
That saves the object after every iteration and doesn't rewrite it. Then starts anew.

Resources