CMErrorDomain when calling CMPedometer methods - ios

I'm attempting to access data from CMPedometer. I have a class called StepService which has the following property
#property (strong, nonatomic) CMPedometer *pedometer;
Which has the following getter
-(CMPedometer*) pedometer{
if(!_pedometer){
_pedometer = [[CMPedometer alloc] init];
}
return _pedometer;
}
I'm using the following code to get the steps:
-(void) storeData {
[self.pedometer queryPedometerDataFromDate:[[NSCalendar currentCalendar] startOfDayForDate:[NSDate date]]
toDate:[NSDate date]
withHandler:^(CMPedometerData *pedometerData, NSError *err){
if (err) {
NSLog(#"Error getting pedometer data: %#", err);
} else {
...
}
}];
}
When I call the above code like so:
StepService *stepService = [[StepService alloc] init];
[stepService storeData];
I get the following value for err
Error Domain=CMErrorDomain Code=103 "(null)"
Debugging reveals pedometer is not null but pedometerData is. What is going on here, how can I resolve this error?

Following Larme's advice, I created a property in my ViewController and synthesized it, like so:
#interface MainViewController(){
#property (strong, nonatomic) StepService *stepService;
#end
#implementation MainViewController
#synthesize stepService
I was then able to create and call the method containing queryPedometerDataFromDate like so:
stepService = [[StepService alloc] init];
[stepService storeData];

Related

Second access to static property error objective c

Im trying to create a plugin for unity game on ios platform
For some reason the second time i try to access the static property shared instance i get
Thread 1: EXC_BAD_ACCESS (code=1, address=0xb21c290b0) on line => auto *instance = [[AppattestPluginWrapper sharedInstance] appAttestPlugin];
Weird thing is when i use break point in the sharedInstance property,the value returned isn't nil so it looks like something in the assignment of the var *instance crashes and i can't figure out why.
#import "UnityAppController.h"
#import <Foundation/Foundation.h>
#import "UnityFramework/UnityFramework-Swift.h"
#interface AppattestPluginWrapper: NSObject
{
}
#property (nonatomic, strong) AppAttestPlugin *appAttestPlugin;
#end
#implementation AppattestPluginWrapper
+ (id)sharedInstance {
static AppattestPluginWrapper *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
sharedInstance.appAttestPlugin = [[AppAttestPlugin alloc] init];
});
return sharedInstance;
}
#end
extern "C"{
void _generateAppAttestKeyId(){
auto *instance = [[AppattestPluginWrapper sharedInstance] appAttestPlugin];
[instance generateAppAttestKeyWithCompletion: ^(NSString * response, NSError * error){
if(error){
UnitySendMessage("iOSListener", "OnAppAttestKeyGenerationFailed", [[error localizedDescription] UTF8String]);
}
else if(response){
UnitySendMessage("iOSListener","OnAppAttestKeyGenerated", [response UTF8String]);
}
}];
}
}
The cause for this behaviour was a crash that corrupted the shared instance, for some reason there was no indicator for the corruption and it took some time to detect the issue that was related to the unity code.

Instance variable nil after it has been set

I have a class with an object incall. I have a method that sets it and another methods that runs a method available for that object.
Here is my header file:
#interface RCTPlivo : NSObject <PlivoEndpointDelegate, CXProviderDelegate>
#property (nonatomic) PlivoIncoming *incall;
#property (nonatomic) PlivoEndpoint *endpoint;
#end
And here is my implementation file:
#implementation RCTPlivo
- (void)login {
endpoint = [[PlivoEndpoint alloc] init];
[endpoint login:plivoUser AndPassword:plivoPass];
endpoint.delegate = self;
}
- (void)triggerIncomingCall {
...
CXProvider *callkitProvider = [[CXProvider alloc] initWithConfiguration: configuration];
[callkitProvider setDelegate:self queue:nil];
...
[callkitProvider reportNewIncomingCallWithUUID:currentCall update:update completion:^(NSError * _Nullable error) {
if (error) {
NSLog(#"Error: %#", error);
}
}];
}
- (void)onIncomingCall:(PlivoIncoming *)incoming {
// setting
self.incall = incoming
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action
{
// Here self.incall is null
[self.incall answer];
}
#end
When i log self.incall in perfromAnswerCall delegate it's null. When I log it in the onIncomingCall delegate the variable is set.
What am I missing here?
Update
Added the code that initializes the delegates and removed ivars.
Your interface should be:
#interface RCTPlivo : NSObject <PlivoEndpointDelegate>
#property (nonatomic, strong) PlivoIncoming *incall;
#end
and your implementation should be:
#implementation RCTPlivo
- (void)onIncomingCall:(PlivoIncoming *)incoming {
self.incall = incoming;
}
- (void)provider:(CXProvider *)provider performAnswerCallAction:(CXAnswerCallAction *)action {
[self.incall answer];
}
#end
One way this can happen is that you somehow have two separate instances of RCTPlivo. Try stopping the debugger in each of those calls and in the debugger do:
(lldb) po self
If everything's ok then the addresses should be the same.
The infall property is not defined as strong. So we can assume that there is no strong reference to the original object outside this method and it was released.
Update
This property was mentioned as delegate so its weak nature can be a designated behaviour and if this is an option the message sender should have a strong property holding the object reference.

Unable to access static variables from NSObject class but I am able from UIViewController

Ok, strange thing occurred and I guess answer is quite simple, but I fail to figure out what's going on.
Situation is next:
I have an NSObject class called Constants.
Constants.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <GooglePlus/GooglePlus.h>
#interface Constants : NSObject
+(Constants*)shared;
#property GTLPlusPerson* googlePlusUser;
#property int profileType;
#property NSString *userName, *userLastName, *userEmail, *userGoogleId,*userProfilePicture;
#end
Constants.m
#import "Constants.h"
#implementation Constants
#synthesize profileType, userProfilePicture, userLastName,userName,userGoogleId,userEmail;
static Constants *constants = nil;
+ (Constants*)shared {
if (nil == constants) {
constants = [[Constants alloc] init];
}
return constants;
}
I use this class in order to save some static variables that I will use throughout the app.
Now, If I try and declare one of the variables like
[Constants shared].userName = #"name";
from an NSObject class method (Which I call from a ViewController), I fail to do so.
But If I declare Constant variables directly from ViewController (after viewDidLoad for example) everything works fine.
Here is the Class I try to declare variables from, but I fail (It also has singleton in it, that might be the source of the problem, but im not sure why would it)
#implementation GoogleLogin
static GoogleLogin* gLogin = nil;
+(GoogleLogin*)shared
{
if (nil == gLogin){
gLogin = [[[self class]alloc]init];
}
return gLogin;
}
-(void)getProfile
{
GTLServicePlus* plusService = [[GTLServicePlus alloc] init];
plusService.retryEnabled = YES;
[plusService setAuthorizer:[GPPSignIn sharedInstance].authentication];
GTLQueryPlus *query = [GTLQueryPlus queryForPeopleGetWithUserId:#"me"];
plusService.apiVersion=#"v1";
[plusService executeQuery:query
completionHandler:^(GTLServiceTicket *ticket,
GTLPlusPerson *person,
NSError *error) {
if (error){
NSLog(#"Error while fetching user profile: %#", error);
}else{
NSLog(#"User profile information fetched OK");
[Constants shared].googlePlusUser = person;
[Constants shared].profileType = 1;
[Constants shared].userName = person.name.givenName;
[Constants shared].userLastName = person.name.familyName;
[Constants shared].userEmail = [GPPSignIn sharedInstance].authentication.userEmail;
[Constants shared].userGoogleId = person.identifier;
[Constants shared].userProfilePicture = person.image.url;
NSLog(#"%# %# %# %# %# ",person.name.givenName,person.name.familyName,[GPPSignIn sharedInstance].authentication.userEmail,person.identifier,person.image.url);
}
}];
}
and this is how I call those methods, from my ViewController:
- (IBAction)signupWithGoogle:(UIButton *)sender {
//if i call this method here, on button click, it will finish all the steps needed, except setting constant variables
[[GoogleLogin shared] googleLoginFromViewController:self];
//if I uncomment next line, username will be declared and I will be able to access it later
//[Constants shared].userName = #"Petar";
}
Can anybody figure out why is this happening and what should I do to change that?
When you define a property is strongly suggested to declare the attributes to use with it. I guess the compiler should complain about this with a message like
No 'assign', 'retain', or 'copy' attribute is specified - 'assign' is
assumed
So, use the following instead (copy semantics is fine for mutable classes).
#property (nonatomic, copy) NSString *myString;
You should also specify if the property should be accessed in a atomic or nonatomic way. If you don't specify it, the former will be applied.
Then, you are using a singleton pattern. The suggested way is to use GCD like so.
+ (ConstantsManager*)sharedManager {
static ConstantsManager *sharedManager;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedManager = [[[self class] alloc] init];
});
return sharedManager;
}
Well you did not set your property attributes on the singleton class.
For example,
#property (nonatomic, strong, readonly) ...
Have you tried moving the property assignments out of the completionHandler? It may be that your properties are being assigned on a background thread and your view controller is not catching the assignment. An easy way to check is to override the setters and getters and put breakpoints in them to see what order they are being accessed.
1) Remove the #synthesize because it's not needed (properties will be synthesized as _property automatically)
2) Override setter & getter
-(void)setProfileType:(NSInteger)profileType {
_profileType = profileType;
}
-(NSInteger)profileType {
return _profileType;
}
3) Place breakpoints within these methods and see if the getter is being called before the setter. Alternatively, if simply moving the assignments out of the completionHandler fixes it you know you have some concurrency issues.
I suggest reading up on atomic/nonatomic properties, #synthesize and Objective-C concurrency.

Saving data from block into an NSMutableDictionary, and blocks in general

I am having a lot of trouble wrapping my head around the best way to use blocks. I am trying to retrieve pedometer data, and the method of accessing the data is a block...
[self.pedometer queryPedometerDataFromDate:yesterday
toDate:midnightOfToday
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(#"Pedometer is NOT available.");
}
else {
NSLog(#"Steps %#", pedometerData.numberOfSteps);
yesterdaysNumbersLabel.text = [pedometerData.numberOfSteps stringValue];
[pedometerDictionary setValue:[pedometerData.numberOfSteps stringValue] forKey:#"2"];
}
});
}];
Using the above code I am able to get the data, log the data, and update the label on the screen, But I can't figure out how to set the data into an array or dictionary so I can do something else with it.
I understand why the arrays and dictionaries are always null... the blocks are running on a different thread and I am accessing them before the blocks have completed.
Can someone help me get through my head how to do something more with the data.
Update 1:
Right now I have this in .h
#property (strong, atomic) NSMutableDictionary *pedometerDictionary;
and I am synthesizing it in .m and I call this...
[self getNumbersForYesterday];
NSLog(#"Dictionary: %#", pedometerDictionary);
...which runs the above function and immediately tries to log the result. And like I said, I understand all the reasons it is NOT working. I just need to figure out how to change what i am doing to get it working.
Update 2:
This is in .h
#property (strong, atomic) NSMutableDictionary *pedometerDictionary;
and this is in .m
#synthesize pedometerDictionary;
- (id)init {
self = [super init];
if (self != nil) {
self.pedometerDictionary = [[NSMutableDictionary alloc] init];
}
return self;
}
and I am using it like this.
[self getNumbersForYesterday];
NSLog(#"Dictionary: %#", self.pedometerDictionary);
to call this.
- (void)getNumbersForYesterday {
[self.pedometer queryPedometerDataFromDate:yesterday
toDate:midnightOfToday
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(#"Pedometer is NOT available.");
}
else {
NSLog(#"Steps %#", pedometerData.numberOfSteps);
yesterdaysNumbersLabel.text = [pedometerData.numberOfSteps stringValue];
[self.pedometerDictionary setValue:[pedometerData.numberOfSteps stringValue] forKey:#"2"];
}
});
}];
}
If I just wanted to keep all the work in the block I would be fine. What I have come to understand is that since blocks are asynchronous, I am trying to NSLog my dictionary, and the block isn't finished running yet. So, my dictionary is still NULL.
Dollars to donuts, your pedometerDictionary was never created in the first place (or it was, but the declaration isn't in a useful spot).
I.e. where is your line of code that says pedometerDictionary = [[NSMutableDictionary alloc] init];? And where is pedometerDictionary declared? How did you try to NSLog() values from it?
Also, use setObject:forKey:.
It is also odd that it is named pedometerDictionary. That is evidence that it is either declared as a global (which it shouldn't be), a local variable of whatever method contains the above code (which won't work), or you are declaring and using an instance variable directly.
The issue you are having is not a block timing issue, your dictionary should never be nil at worst it would contain no values.
You need to create your dictionary before using it. The appropriate place would be init method for most objects. If you are creating your object in Interface Builder then the method should be awakeFromNib.
To do something with the dictionary you can use an NSTimer or call a method from queryPedometerDataFromDate block handler. The use of #synchronized() directive is an example of how to keep access to the dictionary from overlapping at the same time in a threaded environment. This is not the case in this particular example as you are dispatching on the main thread and NSTimer also runs on the main thread. But should you go threaded #synchronized() would keep you from overlapping access.
#interface HelloWorld : NSObject
#property (retain, atomic) NSMutableDictionary *pedometerDictionary;
#property (retain, nonatomic) NSTimer *timer;
#end
#implementation HelloWorld
#synthesize pedometerDictionary, timer;
...
- (id)init {
self = [super init];
if (self != nil) {
self.pedometerDictionary = [NSMutableDictionary dictionary];
self.timer = [NSTimer timerWithTimeInterval:5.0 target:self selector:#selector(doSomethingInterestingWithDictionary:) userInfo:nil repeats:YES];
}
return self;
}
or
- (void)awakeFromNib {
self.pedometerDictionary = [NSMutableDictionary dictionary];
self.timer = [NSTimer timerWithTimeInterval:5.0 target:self selector:#selector(doSomethingInterestingWithDictionary:) userInfo:nil repeats:YES];
}
...
- (void)getNumbersForYesterday {
[self.pedometer queryPedometerDataFromDate:yesterday
toDate:midnightOfToday
withHandler:^(CMPedometerData *pedometerData, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(#"Pedometer is NOT available.");
}
else {
NSLog(#"Steps %#", pedometerData.numberOfSteps);
yesterdaysNumbersLabel.text = [pedometerData.numberOfSteps stringValue];
#synchronized (self) {
[self.pedometerDictionary setValue:[pedometerData.numberOfSteps stringValue] forKey:#"2"];
}
[self doSomethingInterestingWithDictionary:nil];
}
});
}];
}
// Will be called when queryPedometerDataFromDate returns and from a timer every 5 seconds.
- (void)doSomethingInterestingWithDictionary:(NSTimer *)aTimer {
#synchronized (self) {
NSLog(#"My days dictionary: %#", self.pedometerDictionary);
}
}

iOS Game Center unable to send match data with NSCoding

So right now I'm working on sending the match data in a turn based game and I was using this post as a reference.
Good practices for Game Center matchData
I created a new class and it implements NSCoding. It currently only holds one variable for a NSString. This is the code for when I send the match data.
self.game.status = #"Test";
NSData *updatedMatchData = [NSKeyedArchiver archivedDataWithRootObject:self.game];
[self.currentMatch endTurnWithNextParticipants:[NSArray arrayWithObject:nextPerson]
turnTimeout:1000
matchData:updatedMatchData
completionHandler:^(NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
}
}];
NSLog(#"Successfully ended turn");
}
When I try retrieving the match data, I tried this.
[match loadMatchDataWithCompletionHandler:^(NSData *matchData, NSError *error) {
if (matchData)
{
RaceGame *updatedGame = [NSKeyedUnarchiver unarchiveObjectWithData:matchData];
NSLog(#"Match Data: %#", updatedGame.status); //prints null
callback(matchData);
}
}];
However, status is null. I've checked that match isn't null either. I also printed out the match and it said that matchData.length = 135, but I kept changing things around and it was still 135 so I'm not sure if that's helpful.
Any ideas on why status isn't changing?
--EDIT--
.m
#implementation RaceGame
#synthesize status;
#pragma mark - NSCoding protocol
- (void)encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:status forKey:#"status"];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super init]) {
self.status = [aDecoder decodeObjectForKey:#"status"];
}
return self;
}
#end
.h
#interface RaceGame : NSObject <NSCoding> {
NSString *status;
}
/* Match Data */
#property (nonatomic, copy) NSString *status;
#end
Never mind, really stupid mistake by me. I was testing it on two devices and I only ran the updated version on one of the devices.

Resources