How do I initialize CMMotionManager globaly to be used by different classes? - objective-c

i am trying to initialize the device motion manager in a class that contains all of my global variables to use in different classes. However i cant seem to get this working.
I have this in my global class:
// Motion Manager
CMMotionManager *motionManager;
Then set the property in a different class header file:
#property (retain) CMMotionManager *motionManager;
And on the .m file i synthetize and start the updates:
#synthesize motionManager;
motionManager = [[CMMotionManager alloc] init];
if (motionManager.deviceMotionAvailable)
{
motionManager.deviceMotionUpdateInterval = 1.0/100.0;
[motionManager startDeviceMotionUpdates];
NSLog(#"Device Started");
}
But when i call this on my third class:
motionManager.deviceMotionAvailable
It returns NO.
PD: both classes import the global class, and the third class imports the second one's header.

Ok it Seems i can use a singleton class to achieve this:
h file:
//
// MotionManagerSingleton.h
// Air Interface
//
// Created by MacBook on 11/12/28.
// Copyright 2011年 __MyCompanyName__. All rights reserved.
// File created using Singleton XCode Template by Mugunth Kumar (http://blog.mugunthkumar.com)
// More information about this template on the post http://mk.sg/89
// Permission granted to do anything, commercial/non-commercial with this file apart from removing the line/URL above
#import <Foundation/Foundation.h>
#import <CoreMotion/CoreMotion.h>
#interface MotionManagerSingleton : NSObject
+ (MotionManagerSingleton*) sharedInstance;
- (void)startMotionManager;
- (CMAcceleration)getCurrentAcceleration;
- (CMAttitude*)getCurrentAttitude;
- (CMAttitude*)getStartingAttitude;
- (void)setStartingAttitude: (CMAttitude*) ref;
- (bool)isDeviceReady;
- (void)destroyMotionManager;
- (NSTimeInterval) getStamp;
#end
m file:
//
// MotionManagerSingleton.m
// Air Interface
//
// Created by MacBook on 11/12/28.
// Copyright 2011年 __MyCompanyName__. All rights reserved.
// File created using Singleton XCode Template by Mugunth Kumar (http://blog.mugunthkumar.com)
// More information about this template on the post http://mk.sg/89
// Permission granted to do anything, commercial/non-commercial with this file apart from removing the line/URL above
#import "MotionManagerSingleton.h"
#implementation MotionManagerSingleton
CMMotionManager *motionManager;
CMAttitude *referenceAttitude;
bool initialized;
#pragma mark -
#pragma mark Singleton Methods
+ (MotionManagerSingleton*)sharedInstance {
static MotionManagerSingleton *_sharedInstance;
if(!_sharedInstance) {
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[super allocWithZone:nil] init];
});
}
return _sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
return [self sharedInstance];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#if (!__has_feature(objc_arc))
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
#endif
#pragma mark -
#pragma mark Custom Methods
// Add your custom methods here
- (void)startMotionManager{
if (!initialized) {
motionManager = [[CMMotionManager alloc] init];
if (motionManager.deviceMotionAvailable) {
motionManager.deviceMotionUpdateInterval = 1.0/70.0;
[motionManager startDeviceMotionUpdates];
NSLog(#"Device Motion Manager Started");
initialized = YES;
}
}
}
- (CMAcceleration)getCurrentAcceleration{
return motionManager.deviceMotion.userAcceleration;
}
- (CMAttitude*)getCurrentAttitude{
return motionManager.deviceMotion.attitude;
}
- (CMAttitude*)getStartingAttitude{
return referenceAttitude;
}
- (float)getInterval{
return motionManager.accelerometerUpdateInterval;
}
- (NSTimeInterval) getStamp{
return motionManager.deviceMotion.timestamp;
}
- (void)setStartingAttitude: (CMAttitude*) ref{
referenceAttitude = motionManager.deviceMotion.attitude;
}
- (bool)isDeviceReady{
return motionManager.deviceMotionActive;
}
- (void)destroyMotionManager{
[motionManager stopDeviceMotionUpdates];
motionManager = nil;
}
#end
and whenever I want to use it i can just declare a variable in that class header like this:
MotionManagerSingleton *Manager;
and use it like this on the m file:
Manager = [MotionManagerSingleton sharedInstance];
if ([Manager isDeviceReady]) {
NSLog(#"Device Is Ready on Drawing View Controller");
}
referenceAttitude = [Manager getStartingAttitude];

There is already a singleton class in every iOS App, and usually it's called AppDelegate :-)
This is because AppDelegate technically implements UIApplicationDelegate.
So, I followed this suggestion by Jonathan Hui, and it works perfectly for me.
I hope this helps, and it's not too late of an answer..

Related

How to swizzle initialization method?

I have one class MyOldController with init method
-(instancetype) initWithMyController: (MyController *) myController {
if((self = [self init])) {
_myController = myController;
}
return self;
}
I want swizzle this initialization method to another and this my swizzle code
#implementation MyOldController(Swizzle)
+ (void)load {
[MyOldController swizzleMethods];
}
+ (void)swizzleMethods {
method_exchangeImplementations(class_getInstanceMethod(self, #selector(initWithMyController)), class_getInstanceMethod(self, #selector(swizzle_ initWithMyController)));
}
I try write this
-(instancetype) swizzle_initWithMyController: (MyController *) myController {
if((self = [self init])) {
_myController = myController;
}
return self;
}
But it drops error
Then I renamed init method to this and updated (void)swizzleMethods
-(instancetype) initWithMyController_swizzle: (MyController *) myController {
if((self = [self init])) {
_myController = myController;
}
return self;
}
Error message disappeared but swizzle doesn't works. It just calls old initialization method, not my new.
Which point i missed? Is swizzling of initialization method have some special way to do it?
(Starting with the required caveat: this is incredibly dangerous and should never be used in production code. Swizzling initializers is particularly dangerous given designated initializer chaining, and should definitely never be done for anything but exploration and debugging without first confirming the implementation of the swizzled initializer. OK, got that out of the way.)
I can't reproduce your issue. And initializer should always start with with init, so your second approach is correct. I suspect you've just made a small mistake, perhaps in your #selector (which has a typo in your question, which suggests maybe there's a mistake in your actual code). Here is code that does what you're describing.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#interface MyOldController: NSObject
- (instancetype)initWithInt:(NSInteger)x
#end
#implementation MyOldController
- (instancetype)initWithInt:(NSInteger)x
{
self = [super init];
if (self) {
NSLog(#"init");
}
return self;
}
#end
#implementation MyOldController(Swizzle)
+ (void)load {
[MyOldController swizzleMethods];
}
+ (void)swizzleMethods {
method_exchangeImplementations(class_getInstanceMethod(self, #selector(initWithInt:)), class_getInstanceMethod(self, #selector(initWithInt_swizzle:)));
}
- (instancetype)initWithInt_swizzle:(NSInteger)x
{
self = [super init];
if (self) {
NSLog(#"init_swizzle");
}
return self;
}
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
MyOldController *controller = [[MyOldController alloc] initWithInt:1];
NSLog(#"%#", controller);
}
return 0;
}
This prints, as expected:
2018-06-21 12:23:14.431936-0400 test[30981:401466] init_swizzle
2018-06-21 12:23:14.432172-0400 test[30981:401466] <MyOldController: 0x10051ee10>

iOS Store random property in Component e.g. UITextField without Subclass

Does anyone know if there is a way to set a property like a string in the User Defined Runtime Atributes sections of Interface Builder without creating a subclass of said component? For example, I want to store a metadata value for each component in my interface that I use later. I just don't want to have to create a subclass or each component to add a metadata property.
This is one approach I came up with. Opinions?
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#interface UIControl(MetaData)
#property (nonatomic, retain) id entityProperty;
#end
#implementation UIControl(MetaData)
static char const * const EntityPropertyKey = "EntityProperty";
#dynamic entityProperty;
- (id)entityProperty {
return objc_getAssociatedObject(self, EntityPropertyKey);
}
- (void)setEntityProperty:(id)newEntityProperty {
objc_setAssociatedObject(self, EntityPropertyKey, newEntityProperty, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#end
...
if (textField.entityProperty)
[managedObject setValue: textField.text forKey:textField.entityProperty];
You could keep an NSDictionary somewhere, perhaps in a singleton object that has methods for issuing unique ids for objects and storing metadata by the id keys in the dictionary. The UI objects have a tag property that you can use, if your ids are just incremented integers. Then the dictionary keys would just be NSNumbers for those unique integers.
Like this:
#import <Foundation/Foundation.h>
#interface ACLMetadataManager : NSArray
+(ACLMetadataManager*) sharedMetadataManager;
-(NSUInteger) getUniqueId;
-(void) setObject: (id) object forId:(NSUInteger) theId;
-(id) objectForId:(NSUInteger) theId;
#end
And:
#import "ACLMetadataManager.h"
#implementation ACLMetadataManager { // Private variables
NSMutableDictionary *_metadata;
NSUInteger _ids;
}
- (id)init {
self = [super init];
if (self) {
_metadata = [[NSMutableDictionary alloc] init];
}
return self;
}
+(ACLMetadataManager*) sharedMetadataManager { // Singleton getter
static ACLMetadataManager *instance;
if (instance != nil) {
return instance;
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_4_0
static dispatch_once_t oneTimeThread;
dispatch_once(&oneTimeThread, ^(void) {
instance = [[ACLMetadataManager alloc] init];
});
#else
#synchronized(self) {
instance = [[ACLMetadataManager alloc] init];
}
#endif
return instance;
}
-(NSUInteger) getUniqueId { // Increment unique id when getter is called.
return ++_ids; // Start from 1 because tag is 0 by default.
}
-(void) setObject: (id) object forId:(NSUInteger) theId {
[_metadata setObject:object forKey:[NSNumber numberWithInteger:theId]];
}
-(id) objectForId:(NSUInteger) theId {
return [_metadata objectForKey:[NSNumber numberWithInteger:theId]];
}
// Override some methods to ensure singleton stays instantiated.
- (id) retain {
return self;
}
- (oneway void) release {
// Does nothing here.
}
- (id) autorelease {
return self;
}
- (NSUInteger) retainCount {
return INT32_MAX;
}
#end
Usage:
ACLMetadataManager *metadataManager = [ACLMetadataManager sharedMetadataManager];
myControl.tag = [metadataManager getUniqueId];
[metadataManager setObject:myMetadata forId:myControl.tag];

OCMock: Mocking protocols with excluding optional methods

I'm using OCMock for creating mocks in my tests for my iOS app, and I'd like to create mocks of protocols that don't implement all of the optional methods.
If it's not clear what I mean... here's some code:
// Protocol definition
#protocol MyAwesomeProtocol
- (void)doThatRequiredThing;
#optional
- (void)doThatOptionalThing;
#end
...
// In a test
id mock = [OCMockObject mockObjectForProtocol:#protocol(MyAwesomeProtocol)];
// This should return YES:
[mock respondsToSelector:#selector(doThatRequiredThing)];
// This should return NO:
[mock respondsToSelector:#selector(doThatOptionalThing)];
I hit this limitation as well. The basic idea is to override respondsToSelector: (which CANNOT be reliably mocked by OCMock).
I made the following class which does this for you.
You can then use it as follows:
extend GCOCMockOptionalMethodSupportingObject, and implement your protocol
#interface GCTestDelegate : GCOCMockOptionalMethodSupportingObject <GCDelegate>
#end
#implementation GCTestDelegate
//required methods
- (void)requiredMethod{
}
#end
// create your testdelegate
self.classBeingTested.delegate = [OCMock partialMockForObject:[GCTestDelegate new]];
[self.classBeingTested.delegate markSelectorAsImplemented:#selector(optionalMethod:)];
[[self.classBeingTested.delegate expect] optionalMethod:self.classBeingTested];
[self.classBeingTested doSomethingThatwillCheckIfYourDelegateRespondsToYourOptionalMethod];
If you do not call markSelectorAsImplemented, then your classBeingTested will get NO for respondsToSleectorForThatMethod
I've put the code for it here. I'm using this to great effect. Thanks to jer on #iphonedev for setting me off on this path (overriding respondsToSelector was his idea, I was doing some crazy runtime method addition - this is much cleaner methinks).
here's the code
/**
* This class is specifically useful and intended for testing code paths that branch
* pending implementation of optional methods.
* OCMock does not support mocking of protocols with unimplemented optional methods.
* Further compounding the issue is the fact that OCMock does not allow mocking of
* respondsToSelector (in fact, it does but the behaviour is undefined),
* As such this class can be extending to implement a given protocol, the methods can be mocked/expected
* as normal, but in addition we can tell the class to report it conforms to a protocol method or not.
*
*/
#interface GCOCMockOptionalMethodSupportingObject : NSObject
- (void)markSelectorAsImplemented:(SEL)aSelector;
- (void)unmarkSelectorAsImplemented:(SEL)aSelector;
#end
#import "GCOCMockOptionalMethodSupportingObject.h"
#interface GCOCMockOptionalMethodSupportingObject ()
#property(nonatomic, strong) NSMutableArray *implementedSelectors;
#end
#implementation GCOCMockOptionalMethodSupportingObject {
}
//////////////////////////////////////////////////////////////
#pragma mark init
//////////////////////////////////////////////////////////////
- (id)init {
self = [super init];
if (self) {
self.implementedSelectors = [NSMutableArray array];
}
return self;
}
//////////////////////////////////////////////////////////////
#pragma mark public api
//////////////////////////////////////////////////////////////
- (void)markSelectorAsImplemented:(SEL)aSelector {
if (![self isImplemented:aSelector]) {
[self.implementedSelectors addObject:NSStringFromSelector(aSelector)];
}
}
- (void)unmarkSelectorAsImplemented:(SEL)aSelector {
for (NSString *selectorValue in [self.implementedSelectors mutableCopy]) {
SEL storedSelector = NSSelectorFromString(selectorValue);
if (sel_isEqual(aSelector, storedSelector)) {
[self.implementedSelectors removeObject:selectorValue];
break;
}
}
}
//////////////////////////////////////////////////////////////
#pragma mark private impl
//////////////////////////////////////////////////////////////
- (BOOL)isImplemented:(SEL)aSelector {
for (NSString *selectorValue in self.implementedSelectors) {
SEL storedSelector = NSSelectorFromString(selectorValue);
if (sel_isEqual(aSelector, storedSelector)) {
return YES;
}
}
return NO;
}
//////////////////////////////////////////////////////////////
#pragma mark overridden
//////////////////////////////////////////////////////////////
- (BOOL)respondsToSelector:(SEL)aSelector {
if ([self isImplemented:aSelector]) {
return YES;
} else {
return [super respondsToSelector:aSelector];
}
}
#end
The easiest thing to do is to create a class containing the selectors you do want implemented. There doesn't need to be any implementation. Then you create a class mock of that class instead of a protocol mock and use it just the same way.
For example:
#interface MyAwesomeImplementation : NSObject <MyAwesomeProtocol>
- (void)doThatRequiredThing;
#end
#implementation MyAwesomeImplementation
- (void)doThatRequiredThing {}
#end
id mock = OCMStrictClassMock([MyAwesomeImplementation class]);

Objective C - deallocated variable

I have this static/singelton class that has a member variable.
Everything works just fine, however, when I quit the app, and the come back, that member variable is causing the app to crash.
I tried reinitializing the member variable, but doesn't seem to do the trick.
I am including samples of my code below, has anyone seen this before?
The header (.h) file:
#interface Metrics : NSObject {
Metrics *metrics;
Distance *distance;
}
The implementation (.m) file:
#implementation Metrics
static Metrics *metrics = nil;
+ (Metrics *)sharedInstance {
#synchronized(self) {
if (metrics == nil) {
metrics = [[Metrics alloc] init];
}
}
return metrics;
}
- (id)init {
self = [super init];
if (self) {
}
return self;
}
-(void) setupDistance
{
distance = [[Distance alloc] init];
distance.test; // it dies here after I quit the app and come back
}
And where it is used, AppDelegate.m
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[Metrics sharedInstance] setupDistance];
}
Thank you,
Tee
When you say "quit the app" you almost certainly mean "send the app to the background." This does not terminate your application. When you become active again, you're leaking distance and assigning a new one. I suspect that something in test is actually the problem.
First, don't access your ivars directly, except in init and dealloc. Use accessors. This will make most of your problems go away.
Second, don't call setupDistance in applicationDidBecomeActive. You mean to call it in applicationDidFinishLaunchingWithOptions:. But better yet, just initialize it during Metrics init. Why have this internal Metrics detail in the app delegate?
applicationDidBecomeActive will get called when it comes back from sleep calling to setup in the distance again. It's wierd that you're calling a property (.test) and not assigning. Is test doing work? Should it be a method? What's it doing?
Also, in a singleton you have to overload quite a few things. Here's a good template for a singleton that I use.
static MySingleton *sharedInstance = nil;
#implementation MySingleton
#pragma mark -
#pragma mark class instance methods
#pragma mark -
#pragma mark Singleton methods
+ (MySingleton*)sharedInstance
{
#synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone {
#synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [super allocWithZone:zone];
return sharedInstance;  // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX;  // denotes an object that cannot be released
}
- (void)release {
//do nothing
}
- (id)autorelease {
return self;
}
#end

Singleton not initializing correctly

I have the following code that I am calling using this statement: SQLiteDB *db = [[[SQLiteDB alloc] init] autorelease];
The problem is "sharedSQLiteDB" is not being called, but rather "allocWithZone" is, and therefore "checkIfDatabaseExists" is not being called, which is where the database is created.
I don't understand why... (i.e. what am I doing wrong?)
#import "SQLiteDB.h"
static SQLiteDB *sharedSQLiteDB = nil; // makes this a singleton class
#implementation SQLiteDB
#synthesize searchPaths, documentPath, databasePath, cDatabasePath;
#pragma mark Singleton Methods
+ (SQLiteDB *) sharedSQLiteDB {
if(!sharedSQLiteDB) {
sharedSQLiteDB = [[SQLiteDB alloc] init];
[sharedSQLiteDB checkIfDatabaseExists]; // check to see if d/b exists
}
return sharedSQLiteDB;
}
+(id)allocWithZone:(NSZone *)zone { // makes sure another instance is not allocated
if(!sharedSQLiteDB) {
sharedSQLiteDB = [super allocWithZone:zone];
return sharedSQLiteDB;
}
else {
return nil;
}
}
-(id)copyWithZone:(NSZone *)zone {
return self;
}
-(void) release {
// no-op
}
In the singleton pattern your use pattern should be:
SQLiteDB* db = [SQLiteDB sharedSQLiteDB];
They way you are calling it doesn't fit the singelton pattern. All access should be through your sharedSQLiteDB message.
In other words you shouldn't be initializing via typical Cocoa patterns (SQLiteDB *db = [[[SQLiteDB alloc] init] autorelease]; is incorrect and full of problems) outside the scope of the class.
In a singleton using the default initialization pattern for the language (alloc/init for ObjC or the default constructor for C++) should generate a compile time error message since the constructor/init method should be protected.
See the Wikipedia entry. consult the Design Pattern C++ bible. There is even a version for Cocoa
Good luck.
It isn't executing your + (SQLiteDB *) sharedSQLiteDB method because you're not actually calling that method anywhere.
As you've seen, when you call [[SQLiteDB alloc] init], the allocWithZone method is called.
Change your call to be SQLiteDB *db = [SQLiteDB sharedSQLiteDB], which will call your checkIfDatabaseExists method in this case. However, if [[SQLiteDB alloc] init] is called somewhere else, then the checkIfDatabaseExists method call will still be skipped.
Maybe consider moving the checkIfDatabaseExists method into an init method so that it will be called for both your singleton method and your allocWithZone.
Honestly I don't see any error...
However I post the code I used to create a Singleton. It's from a source that now I don't remember the link... it's not my code.
static DataManager *_instance;
#implementation DataManager
+ (DataManager*)sharedInstance
{
#synchronized(self) {
if (_instance == nil) {
_instance = [[super allocWithZone:NULL] init];
// Allocate/initialize any member variables of the singleton class her
// example
//_instance.member = #"";
}
}
return _instance;
}
#pragma mark Singleton Methods
+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedInstance]retain];
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
I hope it helps
I highly recommend using the SyntesizeSingleton header file first created by Matt Gallagher.
Find the latest version (that I know about) here:
https://github.com/cjhanson/Objective-C-Optimized-Singleton
It makes creating a singleton dead simple.
Here's an example header:
#import <Foundation/Foundation.h>
#interface Example : NSObject {}
+(Example*)sharedExample;
#end
And the corresponding .m:
#import "FMUser.h"
#import "SynthesizeSingleton.h"
#implementation Example
SYNTHESIZE_SINGLETON_FOR_CLASS(Example);
#end
[Example sharedExample] is created for you. It's pretty sweet.