A singleton with delegates? - ios

I have some bluetooth class that needs to be alive during all views .
That means, that i have to call functions in this class from different views, and ALSO get delegates from this class to different views .
So , i have to initialise it once to create connection, than later, i have to use it again from different views(classes) and register to get notifications from it.
I was thinking about a singleton, that HE will create an instance of that bluetooth class, and i can access him from anywhere .
But, i would also like that any view can get delegates from it .
How would i do that ?
i have read What should my Objective-C singleton look like?
But maybe singleton is not what i need ?
How can you create a class to always be alive, and register to get delegates from it from anywhere ?
(how can it be done with app delegate class ? )

I have had the similar query a while back
Problem : Multiple Classes need to receive delegate calls from single instance
Solution: I used a combination of sharedInstance , delegates and NSNotifications to handle the problem
SharedInstance
+ (SomeBluetoothClass *) sharedInstance {
static dispatch_once_t once;
static SomeBluetoothClass *sharedInstance;
dispatch_once(&once, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Delegate
#property (weak, nonatomic) id <SomeBluetoothClassDelegate> delegate;
Since delegate can respond to only one class at a time. Assign class in focus based on your logic. Then whenever you want send info to all send it across using NSNotificationCenter from the sharedInstance. Send the info through using userInfo dictionary of NSNotifications
Notifications
[[NSNotificationCenter defaultCenter] postNotificationName:SomeBluetoothClassNotification
object:self
userInfo:info];
Model the structure of SomeBluetoothClass to be thread safe and handle all notifications along with the delegates and it should work fine.

Have a lots way for your situation. Firstly, you should understand that creating object is not too heavy.
So if you want to use Delegate, you can create a Factory method
Ex:
+ (instancetype)bluetoothManagerWithDelegate:(id<delegate>)delegate {
return [self alloc] initWithDelegate:delegate];
}
So that you also don't care about conflict of concurrence. Because you have separate Bluetooth class.
If you still want to use Singleton, in this situation, it depends on how many object you want to notify.
Only 1 views, just use delegate, and set new delegate when you present new view.
More than one, you can use NSNotificationCenter or Observer, you can google these keywords, it have a lot of tutorial and document on the internet help you use it.

I think you can create NSMutableArray in your singleton with links on your views and call someMethod for all objects when is needed. Don't forget remove views from array when its don't need anymore. That is simple realization of pattern called "Observer".

You need to create a class that should be allocated memory once in a lifetime
I am posting a small code snippet which can help you.
In your .m file
#pragma mark - Shared Instance
static BlootoothClass *_sharedblootoothclass = nil;
+ (BlootoothClass *) sharedClass {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedblootoothclass = [[self alloc] init];
// DO YOUR STUFF TO INTIALISE YOUR CLASS
});
return _sharedblootoothclass;
}
in Your .h file
+ (BlootoothClass *) sharedClass
dispatch_once is the queue with dispatch the instance of your class one in a lifetime and you can access its function all over in the app any time.
Now to get any data from it you can get it from instance from any where like
[BlootoothClass sharedClass].anyObject
And you also can send post notification from here in any of its function
- (void)detectedBlootoothdevice{
[[NSNotificationCenter defaultCenter] postNotificationName:#"newdevicedetected" object:nil];
}
You should not use delegates as you cant call same delegate function at multiple class because last delegate get overwritten.

Related

Where should I initialize my singleton in iOS/OS X app?

I want to initialize my singleton object which stores and manages the application settings over the entire class within my app. Also, the singleton instance should be initialized by loading the data from NSUserDefaults upon launch. However, I'm not fully sure where I should initialize the singleton upon launch.
In Cocoa app, I first wrote the singleton initialization code within applicationWillFinishLaunching:, taking parameters from NSUserDefaults. However, later I found that this doesn't work properly if I also write the singleton initialization code (taking no parameter!) within my initial view controller, set in storyboard, because the viewWillLoad:, viewDidLoad: etc. of the class of the view controller are called before the applicationWillFinishLaunching:.
So now I'm sure I should write the singleton initalization code within viewWillLoad: earlier than applicationWillFinishLaunching, but still not sure whether it is appropriate. Specifically, I know the NSApplicationMain is the first method to be called upon launch, but it seems that the next method is not anything within AppDelegate, at least if you use storyboard.
To summary, what I want to ask are the following:
What method from what class will be called after NSApplicationMain, if you use storyboard.
Where should I write my singleton initialization code within my app? I want to initialize it as soon as possible.
Does it differ between iOS and OS X app?
You should initialize it when it's first accessed. Something like this, maybe:
+ (instancetype)sharedInstance {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
As a side note, if you're literally only using this class as an accessor to NSUserDefaults, you might want to consider using static methods instead.
+ (id)mySpecificDataPoint {
return [[NSUserDefaults standardUserDefaults] objectForKey:#"whatever"];
}
+ (void)setMySpecificDataPoint:(id)data {
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"whatever"];
}
Or maybe a more well-designed way might be to add a category to NSUserDefaults for this purpose.
#interface NSUserDefaults (MyData)
#property (nonatomic) NSString *someDataPoint;
#property (nonatomic) NSInteger somePrimitiveDataPoint;
#end
#implementation NSUserDefaults (MyData)
- (NSString *)someDataPoint {
return [self objectForKey:#"someDataPoint"];
}
- (void)setSomeDataPoint:(NSString *)someDataPoint {
[self setObject:someDataPoint forKey:#"someDataPoint"];
}
- (NSInteger)somePrimitiveDataPoint {
return [[self objectForKey:#"somePrimitiveDataPoint"] integerValue];
}
- (void)setSomePrimitiveDataPoint:(NSInteger)somePrimitiveDataPoint {
[self setObject:#(somePrimitiveDataPoint) forKey:#"somePrimitiveDataPoint"];
}
#end
You init the singleton when you have to use it. So as Daji Djan said: lazy wins. Just take attention that, you should not do a long-run process in your applicationWillFinishLaunching, it should return as soon as possible.
If the singleton is not mandatory during applicationWillFinishLaunching, you should call it in viewWillAppear of first view controller if you need to initialize it ASAP.
lazy always wins
if you can get away with it: as late as possible :) AND always do the minimum needed (but do as much as is reasonable to keep your code clean!)

How can I access UITextFields from outside the ViewController (from a .m file)?

I have a class where I keep utility methods; one of those methods takes the values in some textboxes stored in a ViewController and saves those values to a plist.
The problem is the utility methods class is not a ViewController and therefore I can't "hook up" the outlet properties of the textboxes tothe Utility class.
Is there a way I can pass the ViewController as a parameter to the Utility class method?
Just make the utilities class a Singleton inheriting just from NSObject. That way you can easily access the methods wherever you'd like and you'll only have one instance of it.
https://developer.apple.com/library/ios/documentation/general/conceptual/DevPedia-CocoaCore/Singleton.html
Matt Gallagher wrote a great helper file to create Singletons. Check it out here:
http://www.cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
If these utility methodes are class methods use a singleton. Something like this:
+ (__CMMotionManager__ *)__sharedMotionManager__ {
static __CMMotionManager__ *shared = nil;
if (!shared) {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ // all threads will block here until the block executes
shared = [[__CMMotionManager__ alloc] init]; // this line of code can only ever happen once
});
}
return shared;
}
(it's my CoreMotionManager snippet)

Copying of NSMutableArray from one viewcontroller to another viewcontroller?

I have one NSMutableArray in FirstViewController declared as firstArray.
I want to copy the secondArray into firstArray.
In the SecondViewController,
Self.FirstViewController.firstArray = self.secondArray;
When I attempt to NSLog the firstArray.count from the FirstViewController, it display 0. It should have two objects in the array
Anyone can advise on this?
You can choose one of this solutions:
Singleton
Passing Data between ViewControllers
Delegation
You can find all the info you need right here: https://stackoverflow.com/a/9736559/1578927
Singleton example:
static MySingleton *sharedSingleton;
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
sharedSingleton = [[MySingleton alloc] init];
}
}
It looks like either the second array has already been deallocated when passing the reference to the first view controller, or the first view controller itself has already been nilled out. If the first is true, then you may need a different model object to hold your data rather than persisting it in the controller layer of your app. If that is not the case, then you may want to consider a direct copy. The easiest way of doing this is to declare the firstArray property as the keyword copy rather than strong in your interface file.
If you do need to persist the data in the model layer of your app, a singleton pattern object would indeed be one way of achieving this as EXEC_BAD_ACCESS (nice name!) points out. A slightly more modern (though functionally equivalent) way of writing a singleton is as follows.
#interface MySingleton : NSObject
#property (strong, readwrite) id myData;
+ (id)sharedSingleton
#end
#implementation MySingleton
+ (id)sharedSingleton
{
static MySingleton *singleton = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [[MySingleton alloc] init];
// Do other setup code here.
});
return singleton;
}
#end
Note the use of dispatch_once - this makes certain that the static singleton can only be created once (whereas technically, you can invoke +[NSObject initialize] as many times as you feel like manually, though I'd never advise doing so).
You may also take advantage of NSNotificationCenter
SecondViewController.m
[[NSNotificationCenter defaultCenter] postNotificationName:#"arrayFromSecondVC" object:secondArray];
FirstViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(populateArray:) name:#"arrayFromSecondVC" object:nil];
}
-(void)populateArray:(NSNotification *)notif
{
self.firstArray = [notif object];
}
And remove the notification when the viewUnload or didRecieveMemoryWarning method.
Hope it helps.

Can I load the data for all my tabs when my app launches?

I have a tab bar application that works fine, but if the app is opened without it having been running in the background, then the tabs are a little slower to open than usual, as they are loading plists.
Is it possible to load all the data into the views when the app launches?
I would recommend using a service class from which all of the view controllers can query. A common method of defining such a helper class is using the singleton design pattern. The singleton pattern allows only one instance of a singleton class to ever be instantiated. Using this method, you know that every other instance that will be making use of this service will be going through this one instance.
Here's the snippet I noramlly use, it might not be the optimal so I invite other users to suggest changes please:
//.h:
+ (MySingletonServiceInstance *)sharedInstance;
//.m:
static MySingletonServiceInstance *sharedInstance = nil;
+ (MySingletonServiceInstance *)sharedInstance{
#synchronized(self){
if(sharedInstance == nil)
sharedInstance = [[self alloc] init];
}
return sharedInstance;
}
- (id)init {
if ((self = [super init])) {
//Set up
}
return self;
}
Now in any other class (such as a view controller that needs some data), you can do something like this:
[[MySingletonServiceInstance sharedInstance] doSomething];
or
NSDictionary *myData = [MySingletonServiceInstance sharedInstance].data;
and it will call the same object. I often use singleton objects for loading data and suchlike, whether it's an interface to a web service or to the local CoreData. It's a really useful design pattern and I learned so much by picking it up.

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