In Objective-C one can make a singleton that does not have a sharedInstance or similar class call simply by making the -init method reference the status singleton variable, like so
static MyObject *sharedObject;
/*
* The init will return the actual singleton instance if called directly.
* The first time called it will create it and intialize it.
*/
- (instancetype)init
{
static dispatch_once_t once;
dispatch_once(&once, ^{
id myself = [super init];
if (nil != myself) {
[self initialize];
sharedObject = myself;
}
});
return sharedObject;
}
So a user could call this MyObject *myObject = [[MyObject alloc] init]; as many times as he wanted and would get the same object back each time. But it is not obviously, from syntax, a singleton.
I am trying to get a similar functionality in Swift, where I can return the same object each time (an NSObject subclass) but so that it is not obviously a singleton.
I would call it var myObject = MyObject() or when bridging to Objective-C as above but they would all reference the same object.
I am familiar with the normal sharedInstance method of singleton in Swift.
Suggestions on how to do this would be appreciated.
This is not the same as the dispatch_once in Swift answers as that still uses a sharedInstance
In Objective-C an initialiser is just like any other method that is called on an instance
[[alloc SomeClass] init]
You first alloc an instance and then explicitly invoke its initialiser.
init is able to return any object; returning self is just a convention that can be ignored in special cases, such as the one you have shown.
In Swift, init is special. An initialiser is invoked implicitly as part of the allocation
let x = SomeClass()
A Swift init implicitly returns self (or it can return nil in the case of failable initialiser that has failed). As a result, you cannot implement a "hidden singleton" in Swift by returning some other object.
I think you can do something similar to what you're looking for using Objective-C's associated objects. You can see a blog post about how to use it in Swift here: http://en.swifter.tips/associated-object/
I don't really understand the purpose of this though, necessarily- I think it would be desirable to make a singleton look like a singleton.
You can technically use these associated objects to create a function that always returns the same associated object, eg, func giveMeTheSameObjectEveryTime() -> AssociatedObjectType, which would be similar in syntax to init() -> AssociatedObjectType, but I think you're getting a similar effect to a singleton, since you'll have to create some boilerplate variables to hold the association, which is quite a bit more work than a simple static let sharedInstance property.
Related
Today I was going through some of the online codes and I found some NSObject Class.
Some are having:
- (id)init
{
self = [super init];
return self;
}
And some doesn't have it.
Then I also tried this in my Sample Code. I was totally confused. Before this I was thinking that we must write -(id)init method to instantiate a NSObject Class. But now it is working without it.
Here are my some of my doubts:
is -(id)init method really necessary?
What happens if we don't use it.
If we don't write init method even then my code works. Why?
Having an empty -init has absolutely no function.
NSObject already has -init method. And methods in Objective-C are inherited.
It's the same as overriding any other method and just call super:
- (void)someMethod {
[super someMethod];
}
You'll find answers to your questions in the Apple documentation on initializers. I'd recommend you go through those materials, they will clarify a lot of things.
To sum up the documentation with regards to your questions:
is -(id)init method really necessary?
If you don't need to perform extra logic when your class is instanced, then you don't need to implement an init in your class.
What happens if we don't use it.
Even if you don't need to implement it in your subclasses, you need to call it when creating a new object, e.g. [[MyClass alloc] init]
If we don't write init method even then my code works. Why?
As I wrote above, you don't need to declare one for your class, but you need to call it. Otherwise your code might not properly work.
[super init] is highly recommended to give a chance for the superclass to also properly configure the newly created object.
Not calling super init is an error, and results are undefined. (Bad things my happen)
-init() is initializer of NSObject. If a user creates a Person Class which inherits NSObject. It can override this initializer, or one can create their own custom initializer as show below
eg.
class Person : NSObject
{
let name:String
//Initializer inherited from NSObject
override init()
{
super.init()
}
//Custom Initializer
init(withName name:String)
{
super.init()
self.name = name
}
}
I have couple of classes that should be inherited from some A class.
Each of them should be a Singleton.
Can this be achieved?
This realization of Singleton-pattern allows the inheritance:
+ (instancetype)sharedInstance {
static dispatch_once_t once;
static NSMutableDictionary *sharedInstances;
dispatch_once(&once, ^{ /* This code fires only once */
// Creating of the container for shared instances for different classes
sharedInstances = [NSMutableDictionary new];
});
id sharedInstance;
#synchronized(self) { /* Critical section for Singleton-behavior */
// Getting of the shared instance for exact class
sharedInstance = sharedInstances[NSStringFromClass(self)];
if (!sharedInstance) {
// Creating of the shared instance if it's not created yet
sharedInstance = [self new];
sharedInstances[NSStringFromClass(self)] = sharedInstance;
}
}
return sharedInstance;
}
You never, ever inherit from a Singleton class. That completely breaks the concept of a Singleton in a bad way.
Having multiple singleton classes inheriting from the same base class: No problem whatsoever. In fact, most singletons have the common superclass NSObject, but you can use any other superclass.
Yes. I'm not sure if you're familiar with Obj-C singleton patterns, but here is a guide:
http://www.galloway.me.uk/tutorials/singleton-classes/
There shouldn't be any more complications in subclassing. Just create a subclass of the singleton, and it will inherit it's singleton abilities as well. I think each subclass will create it's own unique singleton, but if not, override the singleton generator so it's unique for that subclass.
Keep in mind, singletons are falling out of favor on iOS, so they should be used sparingly. I try to only use them when attempting to create multiple instances is simply not possible (i.e. a class for accessing a hardware resource that must be reserved exclusively by a class.)
I havea Utility class that uses class methods. I am trying to refer to self in the class method but can't. I was wondering how would I declare the following in a class method:
[MRProgressOverlayView showOverlayAddedTo:self.window animated:YES];
self.window it says member reference type struct objc_class *' is a pointer; maybe you meant to use '->'
Another problem that relates to not being able to call self is how would I refer to a declared #property in my .h in a class method in my .m.
Here is my class method:
.m
+ (void)showHUD
{
[UIApplication sharedApplication].networkActivityIndicatorVisible=YES;
[MRProgressOverlayView showOverlayAddedTo:self.window animated:YES];
//I would preferably like to call my property here instead
}
.h
#property (nonatomic) MRProgress * mrProgress;
The whole point of a class method is that it is not part of a specific instance. Inside of a class method, self is the class.
If you need to be tied to a specific instance, then it should be an instance method. If you want a static method that accesses a specific instance, then pass that instance (self) to it (though it's hard to imagine many cases where that makes sense).
In the above example, showHUD should be an instance method almost certainly. If that doesn't make sense for some reason, then it should be:
+ (void)showHUDForWindow:(UIWindow *)window;
You can then call it as showHUDForWindow:self.window and use that as needed.
You can use a singleton pattern. Singleton pattern assumes that the only instance of your class exists. Since it's the only instance, you can then use it from class methods.
Example implementation:
+ (MyClass*)sharedInstance {
static dispatch_once_t once;
static MyClass *sharedMyClass;
dispatch_once(&once, ^ {
sharedMyClass = [[self alloc] init];
});
return sharedMyClass;
}
Then you can access the shared instance via [MyClass sharedInstance], for example:
+ (void)doSomethingCool {
[[self sharedMyClass] doSomething];
}
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)
When I have code like the following:
self = [super init]
does self point to super? If so, why would you want this? if my instance object has the variable "someVal", I won't be able to get to it by doing [self someVal]. correct?
How then would I get to the instance variable's using self when self points to super?
does self point to super?
It's really the other way around. super is really the same as self, except that it tells the compiler to start looking for method implementations starting with the superclass rather than the class itself. You can check this by logging the value of super and the value of self; you'll find that they both point to the same address.
When you create an object, you do this:
Foo *f = [[Foo alloc] init];
The alloc allocates the memory that will become the object you're creating, but until that memory is initialized it's just a chunk of memory -- not a valid object. If Foo is a subclass of Bar and Bar is a subclass of NSObject, then by convention Foo's initializer will call Bar's, and Bar's will call NSObject's, so that the initialization proceeds in order: first the memory is initialized by NSObjects' -init, and Bar's init receives the returned value and assigns it to self. It then proceeds to do any Bar-specific initialization, and returns self. Foo's -init then assigns the returned value to self again and finally does any Foo-specific initialization.
All that assigning to self might seem both redundant and confusing. It's really just a convention, but the purpose is to allow the superclass's initializer to return some object other than the one that was allocated, including nil. So, for example, if the initialization of Bar failed for some reason, -[Bar init] could return nil. The possibility that nil might be returned from [super init] is the reason we put the self = [super init] assignment inside a conditional: if the assigned value is nil, the initialization part is skipped and nil is returned. It's also possible that -[Bar init] could return a pointer to an object other than the one that was allocated, such as when an object similar to the one being created already exists and can be reused.
Most of the time, the pointer you get back from -init will be the same one that you got from +alloc, so you could write this:
Foo *f = [Foo alloc];
[f init];
If you write that, however, you're making an assumption that the initializers of your class and all the classes that it inherits from will always return the same object, and will never return nil. By doing that you're breaking the convention and severely hamstringing yourself and whoever wrote the classes from which Foo inherits -- they'll break your code if they return a different object in a future release of the class. Also, it'll look like you don't know what you're doing.
does self point to super?
This question doesn't make sense in an instance method, since there super is not really a concrete/actual pointer-to-instance, it just indicates that the implementation of the superclass must be called. And since in the case of most objects (except class clusters) all methods return self;, then the answer is no: the actual pointer to the instance doesn't change magically by itself.
For the record: the exception is manifested by class clusters (most Cocoa container classes, for example, NSString, NSArray, etc.). These classes often have an initializer method that returns a different instance than the one that was originally allocated, and of which the class is a concrete subclass of the class of the original self. For example, an implementation of the NSString initializer could be:
#implementation NSString
- (NSString *)init
{
[self release];
self = [[__NSCFString alloc] init];
return self;
}
#end
The reason for this is that optimizing for different types of initialization can be achieved this way.
Self is always pointing to one instance. When you use super you are referencing parent methods not a parent instance.
self means current class' instance.
self = [super init] means self is getting the value returned by [super init].