Forward selected class to use in another class - ios

I'm having a bit of a brain fart. I hope someone can help me.
I have an app that communicates with different devices. Based on which device it's communicating with, I need to use different methods.
I have several different classes that do some parsing that I have made subclasses of a class called Parse (Don't confuse with the Parse cloud service), these only have Class methods. e.g. Parse_Device1 Parse_Device2
I have a third class (lets call it Selection) that returns all sorts of different stuff depending on what device the app is communicating with.
How can I have this class return the needed Parse subclass and use what's returned?
I know I could easily alloc and init the needed class, store it or return it.
However as all the methods on the parse classes are just Class methods, there's no need to init at all.
I've tried like this, however I don't seem to be able to use the returned class directly:
+ (Parser *)parser_AccessList
{
switch ([self brand]) {
case Brand1:
return [Parse_AccessList_1 alloc];
break;
case Brand2:
return [Parse_AccessList_2 alloc];
break;
case Brand3:
return [Parse_AccessList_3 alloc];
break;
default:
return nil;
break;
}
}
I'm probably missing something really simple here.
Thanks

This returns the class object. The caller may then instanciate on object of that very class or call class methods to it (by sending class method selectors).
return [Parse_AccessList_1 class];
Let's assume this is within the caller somewhere:
Class clazz = yourObject parser_AccessList];
[clazz performSelector:#selector(someMethod)];
As clazz is an object of type Class the related class method someMethod shoulc be called.
However, I am sure there are better ways of reaching your goal. Try using a delegation pattern and/or dependency inversion.

This method (message):
parser_AccessList
Is returning:
(Parser *)
That means that it will always return that allocated class type, so if you want to return "any" class you should define your method like this:
+ (id)parser_AccessList
The problem with this is that you don't know which class you should expect, so probably you are going to validate it after initialized.
Also, are you sure you don't need to initialize those parsers?
...
return [[Parse_AccessList_1 alloc] init];
...

In class methods "self" is the class itself. When allocating an instance ([Parse_AccessList_1 alloc]) you have to initialize!
EDIT:
#import <objc/runtime.h>
...
Class cl = NSClassFromString(#"TestClass");
return [[cl alloc] init];

Related

Testing void methods using OCMock in iOS

I am trying to write a test case for a method in Objective-C class which returns void. The method mobileTest just creates another object of class AnotherClass and calls a method makeNoise. How to test this ?
I tried to use OCMock to create test this. Created a mock object of AnotherClass, and called mobileTest method. Obviously, the OCMVerify([mockObject makeNoise]) won't work, as I am not setting this object anywhere in the code. So, how to test in such cases ?
#interface Hello
#end
#implementation HelloWorldClass()
-(void)mobileTest{
AnotherClass *anotherClassObject = [AnotherClass alloc] init];
[anotherClassObject makeNoise];
}
#end
#interface AnotherClass
#end
#implementation AnotherClass()
-(void) makeNoise{
NSLog(#"Makes lot of noise");
}
#end
Test case for the above is as follows :
-(void)testMobileTest{
id mockObject = OCMClassMock([AnotherClass class]);
HelloWorldClass *helloWorldObject = [[HelloWorld alloc] init];
[helloWorldObject mobileTest];
OCMVerify([mockObject makeNoise]);
}
There's not a simple answer to this without going a bit into what OCMock is meant for and what test design paradigm it implies.
The short version is: You should not test this like that in the first place. Tests should treat the tested methods as a black box and only compare & verify input vs output.
Longer version: You're trying to test for a side effect, basically, since makeNoise doesn't do anything that the HelloWorldClass even registers (or "sees"). Or to put it in a more positive way: As long as makeNoise is properly tested in the tests written for AnotherClass you don't need to test that simple call.
The example you provide may be a bit confusing, since obviously that doesn't leave anything meaningful to test in mobileTest's unit test, but considering that you might also question why to outsource the simple NSLog call to another class in the first place (and testing for an NSLog call is kind of pointless, of course). Of course I understand you're just using this as an example and envision a more complex different scenario in which you want to ensure that a specific call happens.
In such a situation, you should always ask yourself "Is this the correct place to verify this?" If the answer is "yes" that should imply that whatever message you want to test to be called needs to go to an object that's not completely inside the scope of the tested class only. For example, it could be a singleton (some global logging class) or a property of the class. Then you have a handle, an object that you can properly mock (for example, set the property to a partially mocked object) and verify.
In rare cases that might lead you to provide a handle/property for an object simply to be able to replace it with a mock during testing, but that often indicates a sub-optimal class and/or method design (I'm not gonna claim that's always the case, though).
Let me provide three examples from one of my projects to illustrate something similar to your situation:
Example 1: Verifying that an URL is opened (in mobile Safari): This is basically verifying that openURL: is called on the shared NSApplication instance, something very similar to what you have in mind. Note that the shared instance is not "completely inside the tested methods scope" as it is a singleton"
id mockApp = OCMPartialMock([UIApplication sharedApplication]);
OCMExpect([mockApp openURL:[OCMArg any]]);
// call the method to test that should call openURL:
OCMVerify([mockApp openURL:[OCMArg any]]);
Note that this works due to the specifics of a partial mock: Even though openURL: is not called on the mock, because the mock has a relationship to same instance that is used in the tested method it can still verify the call. If the instance weren't a singleton that would not work, you would not be able to create the mock from the same object that is used in your method.
Example 2: Adapted version of your code to allow "grabbing" the internal object.
#interface HelloWorldClass
#property (nonatomic, strong) AnotherClass *lazyLoadedClass;
#end
#implementation HelloWorldClass()
// ...
// overridden getter
-(AnotherClass *)lazyLoadedClass {
if (!_lazyLoadedClass) {
_lazyLoadedClass = [[AnotherClass alloc] init];
}
return _lazyLoadedClass;
}
-(void)mobileTest{
[self.lazyLoadedClass makeNoise];
}
#end
And now the test:
-(void)testMobileTest{
HelloWorldClass *helloWorldObject = [[HelloWorld alloc] init];
id mockObject = OCMPartialMock([helloWorldObject lazyLoadedClass]);
OCMExpect([mockObject makeNoise]);
[helloWorldObject mobileTest];
OCMVerify([mockObject makeNoise]);
}
The lazyLoadedClass method might even be in a class extension, i.e. "private". In that case, just copy the according category definition to the top of your test file (I usually do this, and yes, this is, IMO, a valid case of basically "testing private methods"). This approach makes sense if AnotherClass is more complex and requires elaborate setup or something. Usually stuff like this then leads to the scenario you have in the first place, i.e. its complexity makes it to more than just a helper than can be thrown away after the method finishes. this will then also lead you to better code structure, since you have its initializer in a separate method and can test that accordingly, too.
Example 3: If AnotherClass has a non-standard initializer (like a singleton, or it comes from a factory class) you can stub that and return a mocked object (this is kind of a brain-knot, but I have used it)
#implementation AnotherClass()
// ...
-(AnotherClass *)crazyInitializer { // this is in addition to the normal one...
return [[AnotherClass alloc] init];
}
#end
-(void)testMobileTest{
HelloWorldClass *helloWorldObject = [[HelloWorld alloc] init];
id mockForStubbingClassMethod = OCMClassMock([AnotherClass class]);
AnotherClass *baseForPartialMock = [[AnotherClass alloc] init];
// maybe do something with it for test settup
id mockObject = OCMPartialMock(baseForPartialMock);
OCMStub([mockForStubbingClassMethod crazyInitializer]).andReturn(mockObject);
OCMExpect([mockObject makeNoise]);
[helloWorldObject mobileTest];
OCMVerify([mockObject makeNoise]);
}
This looks kind of stupid and I admit it's plain ugly, but I have used this in some tests (you know that point in a project...). Here I tried to make it easier to read and used two mocks, one to stub the class method (i.e. the initializer) and one that then is returned. The mobileTest method should then obviously use the custom initializer of AnotherClass, then it gets the mocked object (like a cuckoo's egg...). This is useful if you want to specially prepare the object (which is why I used a partial mock here). I am actually not sure atm if you could also do this with only one class mock (stub the class method/initializer on it so it returns itself, then expect the method call you want to verify)... as I said, brain-knotting.

Stub a class method on an OCMPartialMock?

I’m using OCMock, and attempting to test a class with two class methods. I’d like to stub one in order to write a test for the other, so I’d normally use an OCMPartialMock. However, if I do this, I can’t call the class method since OCMPartialMock uses an instance of the class, not the class itself. If I use OCMClassMock, it’ll lose the implementation of the method I want to test.
In summary: I have two class methods, and I’d like to stub one but retain the ability to call the other, using OCMock. How can I achieve this?
Found the answer: need to use an OCMClassMock, and since it’s swizzled the class, call the other class method on the class itself, not on my mocked id version.
sample code:
#interface MyClass: NSObject
+ (void)hello;//this is a class method
#end
id mock = OCMClassMock([MyModel class]);
[OCMStub([mock hello]) andDo:^(NSInvocation *invocation) {
NSLog(#"hello everyone");
}];
[MyModel hello]; //it will print 'hello everyone'

When to use respondsToSelector vs objc_getClass

if respondsToSelector("UIAlertController"){
//do something
}
if objc_getClass("UIAlertController") != nil{
//do something
}
These both have the same results overall. Is there a case when one is better than the other one? Or should only one of them be used and the other forgotten?
respondsToSelector : This is basically used for to check if object reference, can call perticular method or not. For example, object has inherited from some base class or implemented by some protocols, then it is better to check whether object is able to respond to that method or not, then only call it.
Otherwise it will throw runtime error, method not found type.
if([obj respondsToSelector:#selector(anyMethod)]) {
[obj fizzyWizzle];
}
else {
// do something
}
objc_getClass : The Class object for the named class, or nil if the class is not registered with the Objective-C runtime. It means, are you able to access this class or not, if that class does not exist then it will return 'nil'. So,
if objc_getClass("UIAlertController") != nil{
// it means, these class is available in SDK, hence its iOS version is 8.x
// here you can alloc - init and use UIAlertController functionality
}
else {
// class could not be found
// iOS version is < 8.0
// here that class is not available hence use UIAlertView which is supported by iOS 7 and earlier.
}
Hope this helps.
For checking the class existence you must use objc_getClass. (For Class compatibility with iOS versions)
For checking whether a class implemented a method or a method is available or not you need to use respondsToSelector (For method availability with versions)
These two methods do not have the same result overall.
Responds to Selector
The first case respondsToSelector is a part of the NSObject protocol and will simply indicate if an object is capable of responding to a message with the given signature, at the time of calling. It can be used for a number of cases:
Polymorphism. Ie, informal protocols, or particularly in conjunction with conformsToProtocol for checking if an instance (of any class) responds to the part of a protocol under the #optional directive.
For deciding whether to forward a message to another target.
For instrumenting an object with additional functionality at runtime, for example putting transaction/rollback capability on a persistent model object.
In publish/subscribe type scenarios.
Get Class
The second method is a low-level member of the Objective-C runtime. It is used to simply check the kind of class an object is presenting itself as. (It will check the isa pointer). There are methods on the NSObject protocol that can do the same thing, and it would be generally recommended to use these, unless you have a specific reason to fall back to the lower level APIs. These methods are [an instance class] and [anInstance isKindOfClass].
Replace instanceof with Polymorphism
While there are a great deal of valid uses for querying an object's class, in a typical application it is often a design flaw. There's a refactoring pattern called "replace instanceof with polymorphism". By that we mean, instead of asking an object what kind of class it is, then doing something, instead specific based on that, instead create a protocol and have each of the possible classes implement the method of that protocol in their specific way. Example:
if ([foo isKindOfClass:[Holiday class]]) {
//evaluate if approved
} else if ([foo isKindOfClass:[SickLeave class]]) {
//evaluate if approved
}
Instead do . .
id<Leave> leave;
[leave approveOrDecline]

what does do method class in objective c

This might be a silly question. I'm learning objective C (iOS) by studying the code and I came across the expression
[InstanceName class];
What does it do?
I tried to search for class method but It just pops up difference between class method and instance method etc. I guess it might give some sort of class object but I have no idea what is the purpose of the statement.
the original code is Sample Facebook App (scrumptious) using FB SDK....
If you see something like this as a standalone expression....
[InstanceName class];
... then the code is most likely forcing the execution of the +initialize method on said class. The first time any method is invoked on a class, the +initialize method will be invoked prior by the runtime. So, have a look at InstanceName and see if it has a +initialize method.
Note that forcing +initialize to execute in this fashion is a sure sign of bad design. +initialize should never need to be forced like this and should not have execution order dependencies.
There is a legitimate additional reason why this line of code might exist. By referring to InstanceName with a hard reference, it'll force the linker to link in all symbols in the library. (If you don't have a hard reference to at least one symbol in a library -- a .a -- some linkers will simply drop the library from the link unit entirely.)
It gets the class of the object.
So for instance if InstanceName is an instance of class Foo
[InstanceName class]; will return Foo, in a variable of type Class
You can use class_getClassName to get an NSString from this class to log it.
class is a method inherited from NSObject. It lets you get the instance of the class object representing the class of the instance on which the method is called.
It can be used to examine the metadata of the current object. For example, you can use class method to determine if a given object is of a particular class:
if ([sender isKindOfClass:[UIButton class]]) {
...
}
It returns the class of the object. Suppose you have an array of UIView subclasses you created and you want to perform some action only to those who belong to a certain class. You could loop through the array and check for each object's class:
for (id view in myViews) {
if ([view isKindOfClass:[MyUIViewSubclass class]]) {
// Do something
}
}

resolveInstanceMethod on super returns NO for a valid selector

I've implemented +resolveInstanceMethod on a class that subclasses NSDictionary. I will dynamically add methods to my class for certain cases, but I want standard NSDictionary methods to 'just work'.
I thought this would be the case if I just call [super resolveInstanceMethod:sel]; at the end of my method but it doesn't work.
+ (BOOL) resolveInstanceMethod:(SEL)sel
{
BOOL value = [super resolveInstanceMethod:sel]; // this is always NO!?
return value;
}
Why is this? How do I get my class to behave 'normally' for existing methods on the superclass?
What leads you to expect that -resolveInstanceMethod: would return YES for already existing methods? The release notes which introduced the new method say that the default implementation simply returns NO:
The NSObject class implements these methods with a default
implementation that returns NO today, though you should still invoke
it even if you're just directly subclassing NSObject.
In any case, it should never even be called for methods which are already present on the class. It's only called when you message an object with a selector which isn't already "resolved" to an implementation.

Resources