Multiple sensors in iOS - ios

I have two different POC, one for the accelerometer and one for GPS. However, I am not comprehending the architecture to put marry both of the applications. I need to initialize both the accel and GPS when the application loads. I have the main view tied to the accel, but also need to the the location of the device.
My current architecture is
Projects in workspace
Main App
Utility App
Services App
Domain App
The main app ViewController inherits
: UIViewController
That all wires up correctly the the accel works as expected.
In the Utility CoreLocationUtility class, I have it inheriting the CLLocationManagerDelegate.
The question is, how do I register a delegate from the same view that is of type AccelDelegate?

If you want to make your ViewController act as delegate for both accelerometer and GPS, state in its header file that it obeys both delegate protocols:
#interface ViewController : UIViewController <CLLocationManagerDelegate, UIAccelerometerDelegate> {
CLLocationManager *myLocationManager; // an instance variable
}
// ... your definitions
#end
then somewhere in your ViewController
[UIAccelerometer sharedAccelerometer].delegate = self;
myLocationManager = [[CLLocationManager alloc] init];
myLocationManager.delegate = self;
then somewhere else in your ViewController, put the delegate methods for both protocols
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// ... your code
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
// ... your code
}
and that should work, although there may be typos, I have not compiled this. Plus, in my experience, location manager code tends to get quite big. You may be much better off putting it in a class of its own, to be instantiated by the ViewController.
Can anyone explain why the only method in the UIAccelerometerDelegate protocol is deprecated?

Related

AppDelegate created with Typhoon Assembly (plist method) is created twice and property injection doesn't work

I am trying to bootstrap Typhoon using the PList integration method but my ApplicationDelegate is being created twice. The first time it is created, it is obviously being created by Typhoon. That time, it uses the special initializer initWithAssembly: and Typhoon feeds it the assembly.
The second time, the time that matters, it is created using init. It never gets a reference to the assembly.
Just in case, I also injected the assembly via the property method. No go.
Here is the code:
Assembly
- (UIApplication *)sharedApplication {
return [TyphoonDefinition withClass:[UIApplication class] configuration:^(TyphoonDefinition *definition) {
[definition useInitializer:#selector(sharedApplication)];
}];
}
- (CTISApplicationDelegate *)appDelegate {
return [TyphoonDefinition withClass:[CTISApplicationDelegate class]
configuration:^(TyphoonDefinition *definition) {
[definition useInitializer:#selector(initWithAssembly:) parameters:^(TyphoonMethod *initializer) {
[initializer injectParameterWith:#(3)];
}];
definition.scope = TyphoonScopeSingleton;
}];
}
AppDelegate
#property (nonatomic, strong, readwrite) ApplicationAssembly *assembly;
#property (nonatomic, strong, readwrite) UIWindow *window;
- (instancetype)initWithAssembly:(ApplicationAssembly *)assembly;
...
// This gets called once, the first time, and assembly is NOT nil.
- (instancetype)initWithAssembly:(ApplicationAssembly *)assembly {
self = [super init];
if (self) {
self.assembly = assembly;
}
return self;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
// This gets ca
lled once (after second init) and self.assembly is nil.
AcceptDisclaimerAppInfoModule *disclaimer = [[self.assembly applicationInformationModuleAssembly] acceptDisclaimerModule];
[disclaimer launchModuleFromWindow:self.window];
[self.window makeKeyAndVisible];
return YES;
}
After looking online and going a bit crazy over-thinking this problem, I came to a number of conclusions.
The root of the problem is that Typhoon and my main.m entry point were not in sync in any form. So, main.m calls UIApplicationMain() and one of the arguments is a string that specifies the kind of id<UIApplicationDelegate> you want. I've never seen any deviation from this pattern so I was not willing to change that up.
Therefore, it is a given that the id<UIApplicationDelegate> is not going to be constructed via Typhoon in a way that is "built-into" the framework. And while you could do one of the following, I don't recommend any: they all seem wrong.
Instantiate an instance of your root TyphoonAssembly directly from your app delegate
Create a singleton IContainer object that can hug the TyphoonAssembly instance created on startup
Use categories with associated objects in an evil manner
The problem is... at some point, you're going to need to do one of these evil things no matter what if you don't get it right.
The reason is... Typhoon is clearly designed to work in the context of "object graphs," so the entire TyphoonAssembly and any connected assemblies can be thought of as webs of graphs. Once you get in the web, you're fine - you can take it from there. You just need to get in...
So, I decided to do as follows:
Create interfaces for each "object graph" of related objects I call IContainer, even if they spanned multiple assemblies or if were smaller than an assembly. This disconnected the idea of Typhoon from the IContainer and makes it possible to debug without Typhoon by substituting a mock IContainer in place.
Use constructor injection EXCLUSIVELY except in one very notable case - the one I had just mentioned, the app delegate. There, use property injection to inject just one property - the IContainer in question.
Whenever you use property injection, you might as well just inject a single property, the IContainer, because you've already broken encapsulation and you might as well make it easy on yourself.
Implement something fun to prove to yourself that Typhoon's default scope works they way you think it does. I implemented a few "alerts" whenever I detected multiple calls to any constructor in the same object graph.
Use id<nonatomic, weak> for delegate types, not id<nonatomic, assign> as I had done for the past year. Something about the way Typhoon works under the hood must make it constantly be letting go of delegates.
Use PList injection and Assembly Composition. An example:
In your Info.plist, add a key called TyphoonInitialAssemblies with Array type and values that are the class names of your assemblies. But...
Don't forget to do the other half, which is to make sure you have a "root" assembly like RootAssembly and then some ModuleAssemblys that are stored by the RootAssembly:
#protocol IAppLaunchContainer
- (UIWindow *)launchWindow;
- (UIViewController *)launchRootViewController;
- (UIImageView *)launchImageView;
#end
#protocol IDefaultUIComponentsContainer
- (UIView *)uiDefaultView;
- (UILabel *)uiDefaultLabelWithName:(NSString *)name;
- (UIButton *)uiDefaultButtonWithTitle:(NSString *)title;
#end
#interface RootAssembly : TyphoonAssembly<IAppLaunchContainer, IDefaultUIComponentsContainer>
#property (nonatomic, strong) SubAssemblyA *thisModuleAssembly;
#property (nonatomic, strong) SubAssemblyB *thatModuleAssembly;
#end
In this case, your Info.plist would have:
TyphoonInitialAssemblies (Array)
SubAssemblyA
SubAssemblyB

iOS kontakt.io beacons search

I have two kontakt.io Beacons. I'm able to find it using the default Kontakt.io app available in the AppStore. But when I use the SDK and try to find it in my custom app, the app requests Bluetooth, which means it does something with it, but no beacons are found.
According to the documentation I must only create an object of KTKBeaconManager class, assign a KTKBeaconManagerDelegate and call startFindingDevices method. After that the delegate should receive callbacks whenever devices in range changes. I extended the KTKBeaconManager with a class called BeaconManager. Here's its code (Yes I have imported everything and code compiles. I didn't put it here to save space.).
BeaconManager.h
#interface BeaconManager : KTKBeaconManager <KTKBluetoothManagerDelegate>
#end
BeaconManager.m
#implementation BeaconManager
- (instancetype)init
{
self = [super init];
if (self) {
//Setting the delegate to self
self.delegate = self;
}
return self;
}
- (void)bluetoothManager:(KTKBluetoothManager *)bluetoothManager didChangeDevices:(NSSet *)devices {
NSLog(#"Entered didChangeDevices. Devices size: %d", devices.count);
}
#end
Starting the search.
BeaconManager *beaconManager = [BeaconManager new];
[beaconManager startFindingDevices];
[beaconManager reloadDevices]; //Tells the manager to forget all devices and start searching again.
This is actually a sample code from the documentation, but it's not working. Anybody's going through something similar and has got a clue what to do?
Your beaconManager is most probably deallocated just after it's created. You have to move it to an instance variable.
It's not written that directly but you should know what's the scope of life for object - it should be a property if you want to have it working all the time etc.

When to unregister a delegate of a UIView or UILabel

I got a customized UILabel which register itself to a communication instance during creation. This part works perfect, the UILabel will . But when I remove the UILabel will update itself after called by the communication instance. I have of course remove the listener delegate too. But as ViewDidUnload is not call anymore, I do not know where.
Here the code sample:
#implementation MyValueLabel
- (id)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self)
{
self.text=[NSString stringWithFormat:#"%.02f", ((double)g_com.getRemoteValue())/100 ];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate addBalanceListener:self];
}
return self;
}
-(void)communicationUpdate
{
self.text=[NSString stringWithFormat:#"%.02f", ((double)g_com.getRemoteValue())/100 ];
}
// This is the missing Method
-(void) DestructionOfTheLabelWhichIDidNotFound
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate removeBalanceListener:self];
}
#end
Technically you seem to be looking for the -dealloc method which is called on an object when it is to be deallocated. However I do not believe that is an adequate solution.
The example provided here seems to be doing a number of unexpected things which I believe will result in code which is surprising to other developers, requires fighting against common patterns in the UIKit framework, and be difficult to maintain.
Normally iOS view controllers are responsible for mediating or coordinating how data reaches view objects. A controller supplies a view with either the data it should currently display or provides it with a source of that data. This allows a single view class to be used in many different locations and to display data of the same type regardless of its source. Instead here we have a view which reaches out to obtain it's own data. There's no way for a controller to determine when an instance of this view class should update or what data it should display. For example the controller cannot decide to pause updates, or cause other view elements to update at the same time.
In addition this view makes several assumptions about the source of it's data and how that source may be obtained. The view assumes that the current application's app delegate is specifically an AppDelegate class so it will not work if you want to use this view in another application. Since the view also obtains this AppDelegate instance via a call to + sharedApplication there's no hint to users of this view that it has this dependency.
Consider instead allowing classes which use this view class to provide it with the data it should display.
If the property where addBalanceListener: stores the reference is weak, you don't need to do anything. Weak properties are automatically set to nil when the instance they are pointing to is dealloced.

What does aDecoder in the initWithCoder method do in cocoa-touch?

Following my previous post about UIViewControllers designated initializer initWithCoder I have another question about the argument aDecoder passed into the protocol method.
Here is the code in question:
#implementation WhereamiViewController
- (id)initWithCoder:(NSCoder *)aDecoder //we're overiding the superclasses (UIViewController) inititalizer
{
self = [super initWithCoder:aDecoder];
if (self){
//create location manager object
locationManager = [[CLLocationManager alloc] init];
//there will be a warning from this line of code
[locationManager setDelegate:self];
//and we want it to be as accurate as possible
//regardless of how much time/power it takes
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
//tell our manager to start looking for its location immediately
[locationManager startUpdatingLocation];
}
return self;
}
I was curious about aDecoder so renamed it to see if my code would still work and it did. What I want to know is what exactly is being passed into initWithCoder as an argument? It seems like nothing is in my code. Is the argument just part of the method and has to be shown even if nothings being passed into it? Other times I have created designated initializers I've done it like this:
self = [super init]
init is NSObjects designated initializer right?
This is the only part of the code I don't understand. I see I'm calling my superclasses initializer and then implementing it with additional custom code / making it selfs (whereamiviewcontroller) value.
I did set a marker and look in the logs to see if anything would catch my eye but had no luck with that.
Thanks in advance
Regards
You can see the -initWithCoder: method in action when you try to initialise your view controller instance from nib or storyboard. In this case Cocoa Touch will decode the controller elements from the xml using UINibDecoder instance by -initWithCoder: initialiser.

General design - Where do I put centrally accessed objects

I have my main app delegate
I have a few UIViewController derived instances driven by a Storyboard
Say I'd like to provide a centralized persistence layer for my application - perhaps Core Data of SQLite. Where would I put those objects? I'm missing some centrally accessible "Application" class you can access from all the UIViewController instances.
Is there a pattern to follow here?
you should check the singleton pattern:
In software engineering, the singleton pattern is a design pattern
that restricts the instantiation of a class to one object. This is
useful when exactly one object is needed to coordinate actions across
the system. The concept is sometimes generalized to systems that
operate more efficiently when only one object exists, or that restrict
the instantiation to a certain number of objects. The term comes from
the mathematical concept of a singleton.
here is a source for a example implementation: What should my Objective-C singleton look like?
and here is the direct link for the modern solution:
https://stackoverflow.com/a/145395/644629
What you're describing is your model layer. There are two main ways to manage the model:
At application startup, create the main model object and hand it to the first view controller.
Make the main model object a Singleton.
The "main model object" in both cases is generally some kind of object manager. It could be a document, or it could be a PersonManager if you have a bunch of Person objects. This object will vend model objects from your persistence store (generally Core Data).
The advantage of a Singleton here is that it's a little easier to implement and you don't have to pass around the manager. The advantage of a non-Singleton is that it's easier to have more than one (for a document-based system), and it's easier to test and reason about non-singletons than singletons. That said, probably 80% of my projects use a singleton model manager.
As a side note, that you appear to already understand: never store the model in the application delegate, and never use the application delegate as a "rendezvous point" to get to the model. That is, never have a sharedModel method on the application delegate. If you find yourself calling [[UIApplication sharedApplication] delegate] anywhere in your code, you're almost always doing something wrong. Hanging data on the application delegate makes code reuse extremely difficult.
Go with a singleton pattern, which has scope of application lifetime.
#interface DataManager ()
#end
#pragma mark -
#implementation DataManager
#pragma mark - Shared Instance
static DataManager* sharedInstance = nil;
#pragma mark - Singleton Methods
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
+ (DataManager*)sharedInstance
{
#synchronized([DataManager class])
{
if (!sharedInstance) {
//[[self alloc] init];
sharedInstance = [[DataManager alloc] init];
}
return sharedInstance;
}
return nil;
}
+ (id)alloc
{
#synchronized([DataManager class])
{
NSAssert(sharedInstance == nil, #"Attempted to allocate a second instance \
of a singleton.");
sharedInstance = [super alloc];
return sharedInstance;
}
return nil;
}
#end
Declare your properties in .h file and synthesize them here in .m file.
To use that property just call:
// set value
[[DataManager sharedInstance] setSharedProperty:#"ABC"]; // If its a string
// get Value
NSLog(#"value : %#", [[DataManager sharedInstance] sharedProperty]);
Hope this is what you required.
Enjoy Coding :)

Resources