How to access self in class method objective C - ios

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];
}

Related

Swift singleton that does not look like a singleton

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.

Reset singleton instance to nil after each test case

I am using OCMock 3 to unit test my iOS project.
I use dispatch_once() created a singleton class MyManager :
#implementation MyManager
+ (id)sharedInstance {
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
I have a method in School class which uses the above singleton:
#implementation School
...
- (void) createLecture {
MyManager *mgr = [MyManager sharedInstance];
[mgr checkLectures];
...
}
#end
Now, I want to unit test this method, I use a partial mock of MyManager:
- (void) testCreateLecture {
// create a partially mocked instance of MyManager
id partialMockMgr = [OCMockObject partialMockForObject:[MyManager sharedInstance]];
// run method to test
[schoolToTest createLecture];
...
}
- (void)tearDown {
// I want to set the singleton instance to nil, how to?
[super tearDown];
}
In tearDown phase, I want to set the singleton instance to nil so that the following test case could start from clean state.
I know on internet, some people suggest to move the static MyManager *sharedMyManager outside the +(id)sharedInstance method. But I would like to ask, is there any way to set the instance to nil without moving it outside +(id)sharedInstance method? (Any solution like java reflection?)
You can't achieve what you want with a local static variable. Block-scoped statics are only visible inside their lexical context.
We do this by making the singleton instance a static variable scoped to the class implementation and adding a mutator to override it. Generally that mutator is only called by tests.
#implementation MyManager
static MyManager *_sharedInstance = nil;
static dispatch_once_t once_token = 0;
+(instancetype)sharedInstance {
dispatch_once(&once_token, ^{
if (_sharedInstance == nil) {
_sharedInstance = [[MyManager alloc] init];
}
});
return _sharedInstance;
}
+(void)setSharedInstance:(MyManager *)instance {
once_token = 0; // resets the once_token so dispatch_once will run again
_sharedInstance = instance;
}
#end
Then in your unit test:
// we can replace it with a mock object
id mockManager = [OCMockObject mockForClass:[MyManager class]];
[MyManager setSharedInstance:mockManager];
// we can reset it so that it returns the actual MyManager
[MyManager setSharedInstance:nil];
This also works with partial mocks, as in your example:
id mockMyManager = [OCMockObject partialMockForObject:[MyManager sharedInstance]];
[[mockMyManager expect] checkLectures];
[MyManager setSharedInstance:mockMyManager];
[schoolToTest createLecture];
[mockMyManager verify];
[mockMyManager stopMocking];
// reset it so that it returns the actual MyManager
[MyManager setSharedInstance:nil];
Here's a full breakdown of the approach.
The answer is no, because you use dispatch_once(&onceToken, ^{ so even if you added another method which could reset the variable to nil you'd never be able to initialise it again.
So you already have one solution and the best solution is to not access the singleton directly (use dependency injection instead).
It is an easier way to solute your issue.
Your class have a singleton. you can add a method that is destroy this class instance. So when you call shareManager method again , it will create a new instance.
Such as:
static MyManager *sharedMyManager = nil;
+ (void)destroy
{
sharedMyManager = nil;
}
As others have stated, what you should really do is refactor your code to use dependency injection. This means that if the School class needs a MyManager instance to operate, then it should have an initWithManager:(MyManager *)manager method which should be the designated initializer. Or if the MyManager is only needed in this particular method, it should be a method parameter, e.g. createLectureWithManager:(MyManager *)manager.
Then in your tests, you could just do School *schoolToTest = [[School alloc] initWithManager:[[MyManager alloc] init]], and each test would have a new MyManager instance. You could drop the singleton pattern entirely, removing the sharedInstance method on MyManager and your application's logic would be responsible to ensure that there is only one instance that you pass around.
But sometimes, you have to work with legacy code that you can't just refactor. In these cases, you need to stub the class method. That is, you need to replace the implementation of -[MyManager sharedInstance] with an implementation that returns [[MyManager alloc] init]. This can be accomplished using the runtime to swizzle the class method, which would be the equivalent of Java reflection that you are looking for. See this for an example of how to use the runtime.
You can also do it with OCMock, which uses the runtime behind the scenes, just like mocking frameworks in Java are based on the reflection API :
MyManager *testManager = [[MyManager alloc] init];
id mock = [[OCMockObject mockForClass:[MyManager class]];
[[[mock stub] andReturn:testManager] sharedInstance];
If you don't want to refactor your code for easier unit testing then there is another solution (not perfect but works):
Create a local property of MyManager type
In setUp instantiate the property from above and swizzle the sharedInstance method with your local method (e.g. swizzle_sharedInstance)
Inside the swizzle_sharedInstance return the local property
In tearDown swizzle back to original sharedInstance and nullify the local property
I suggest a little bit different approach. You can create a mock of your sharedInstance using OCMock:
id myManagerMock = OCMClassMock([MyManager class]);
OCMStub([myManagerMock sharedManager]).andReturn(myManagerMock);
Now School implementation will use myManagerMock object, and you can stub this object to return anything you want under you test case. For example:
OCMStub([myManagerMock someMethodThatReturnsBoolean]).andReturn(YES);
It's important that after your tests, you will perform cleaning of your mock object by calling (at the end of your test method or in -tearDown):
[myManagerMock stopMocking];

Can Singleton Inheritance be achieved in iOS

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.)

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)

How do I get subclass to initialize property as its correct class?

I have a class named SPPanelManager, which has a property of another class, named SPPanelSettingsManager. SPPanelManager has the following in it's -init method:
self.settingsManager = [[SPPanelSettingsManager alloc] init];
The purpose of SPPanelManager is to be subclassed, and the subclasses are used throughout my app. For example, there's SPGreetingManager. In the .h file of SPGreetingManager, I have declared:
#property (nonatomic, strong) SPGreetingSettingsManager *settingsManager;
which makes the settingsManager be of the correct class. The problem is that when the SPGreetingManager subclass is initialized, it calls the init method above, and initializes the settingsManager as the SPPanelSettingsManager class, rather than SPGreetingSettingsManager.
How can I get it to initialize this as the correct class for that property without having to re-write the init code in every subclass?
The super class (SPPanelManager) somehow has to know which class the concrete panel manager wants to use as a settingsManager.
Apple uses the following approach to match CALayers to UIViews:
The base class declares a class method that returns the concrete SPPanelSettingsManager subclass:
// in SPPanelManager.h
+ (Class)settingsManagerClass;
... which subclasses override to return their custom class:
// in SPGreetingManager.m
+ (Class)settingsManagerClass
{
return [SPGreetingSettingsManager class];
}
Now the superclass can instantiate the settings manager as follows:
self.settingsManager = [[[[self class] settingsManagerClass] alloc] init];
Another common solution is to use a naming convention. Just match the names of the classes: SPGreetingManager has a SPGreetingSettingsManager.
By definition each ...Manager has to have a matching ...SettingsManager.
// in SPPanelManager.m init
NSString *className = NSStringFromClass([self class]);
className = [className stringByReplacingOccurrencesOfString:#"Manager"
withString:#"SettingsManager"];
Class settingsManagerClass = NSClassFromString(className);
NSAssert(settingsManagerClass != Nil, #"no settings manager class found");
self.settingsManager = [[[settingsManagerClass settingsManagerClass] alloc] init];
The advantage is that subclasses don't have to override a common method to declare the class type. On the other hand it might seem a bit obfuscated what's going on.
Also, above code forces a one to one relationship between the classes. No settings controller could be reused.
Is SPPanelManager a class you developed? Simply give it a init with a parameter for the settings instance.

Resources