I have a SenTest class I am attempting to write which uses a Category to override a method in a controller class. I want my mock controller class to call a method in the SenTest class to determine how to behave for various tests.
For example:
Set a var in the testFoo method.
In testFoo, call my mock controller's overridden method.
Have it call back up to the SenTest singleton to figure out how to behave for testFoo.
Is this possible, or am I an idiot?
Turns out the trick to doing this is to to make the associated reference IN the category code, not in the SenTest case.
So for example, declare this in category:
-(void)fakeMethodToSetTestData:(NSDictionary *)data;
And in that method set the associative reference to store your data "associated" with "self".
Call this in your test case on your object, passing in your data.
Then in your test case, call your:
-(void)realMethodInCategoryWhichIsBeingOverridden;
And in your category implementation of this method, retrieve the data from the associative reference you set in the first method.
This will let you set test data on a Controller so that you can hijack the delegation chain, for example, to prevent the second method from going to the network and returning your test data into your controller's code.
Related
I have a class with an optional type property (static). I set this when I start to use the class. Obviously, when the program first starts, the property has no value.
My question is about testing. I expected the class to be initialised at the start of every test (i.e. the type property set back to having no value). However, it seems the class is initiated once at the beginning of all my tests and therefore the type property has the same value in all tests, which is not what I want.
What are the rules about class initialisation in testing? Is there any way I can force my class to "reset"?
Thanks,
Julian
As you've noticed, static properties on your test case are persistent throughout all your tests. However, XCTestCase has two sets of methods that you can override to customize this, called setUp() and tearDown(). It's somewhat confusing, since there are identically named class and instance methods for each of these; override the class methods to have something happen only once, and override the instance methods to make something happen before or after each individual test. In your case, it would probably make the most sense to override the instance method version of setUp() and have it reset your properties.
I have created a class which contain only static method in iPhone. The class was mainly to do my core data operations. But suddenly, I had a need to make a method call in a view controller, when an insertion of data in to a table got completed.
At first, I decided to send an NSNotification, once the loop finishes iteration. But then, since I need to use this only for single time, I decided not to go for NSNotificationCenter, instead to use delegation.
Now I have many static method, and two instance methods:
//1
-(id)initWithDelegate:(id)delegate;
//2
-(void)insertContentsInToTheTableFromArray:(NSArray *)contentArray;
Is this a good design pattern, to have both instance methods and class methods in this class. Please share your thoughts.
We can use both method in one class. We know that instance methods use an instance of a class, whereas a static method can be used with just the class name. But the static method is a convenience method that use on many foundation classes.
I know usually, when you want to call a method on another object, you do:
NewObject *object = [NewObject alloc]init];
[object callMethod];
But I created a class that isn't an object itself meaning it doesn't have properties or memory management. It has a couple methods that calculate some stuff.
From any other class, all I have to do is import the header for this class and do:
#import "MyClass.h"
[MyClass callMethod];
Why in this case do I not have to alloc init? It works just fine.
It sounds like you are trying to call a class method. These are methods which have been defined as:
+(void) myStaticMethod;
instead of
-(void) myMethod;
The plus sign indicates that the method does not use any fields, and thereby does not need to instantiate the object.
In your example, "object" is an instance of a class "NewObject" which has been allocated memory and initialized. Where-as your example, "MyClass" is only a class which because it has static members declared as above, does not need to be instantiated.
Class methods provide a nice way to combine a bunch of related functions into one place, rather than having them spread out in the regular namespace, as would usually be done in straight C. You can also have both class methods and instance methods in the same class, using the class ones when needed, and instantiating the class to use the instance ones when needed.
EDIT: Changed terminology to refer to class methods instead of static methods.
because you are calling a class method. You only need to alloc init objects. Classes only need to be included but not alloc inited. So you don't need to init an NSString class, say.
Edit:
Let's just have some nonsense examples:
+ (void)classMethod {
NSLog("Hi!");
}
[SomeClass classMethod]; // prints Hi!
- (void)instanceMethod { // (say it's an instance method of NSString)
NSLog(self);
}
[#"someNSString" instanceMethod]; // prints someNSString. But you need to have a string first, otherwise you cannot use this method.
There is a difference between "instance" methods (normal ones), that have to be called on an object and have access to self, and "class" methods (called static, in many programming languages), that are invoked on the class and thus do not have a self.
Class methods are similar to C++ static methods, in that they can be invoked without creating a concrete instance of the class. The usefulness of this is you can call a class's specialized factory methods to create a new instance; or, you can define a utility library under the scope of a class that may or may not provide concrete instances depending on the task.
Look at NSDate and NSNumber are good examples of this in the Foundation framework.
I have two classes, both are subclasses of CCLayer,
I want to call a method of first class into second class, what should I code?
Your question is not providing much detail, but from my understanding of what you say, you need the following:
a selector in the public interface of your first class;
a pointer ivar in the second class that you will properly initialize so that it points to an instance of the first class;
In this way you will be able to call the first class' method from the second class.
In Objective-C, if I override a class method using a category, is there a way I can call the original method (the one that was overridden)?
I present you with three icky ways to do this in +(void)load. In every case, name your method MyCategory_method or so.
class_getMethodImplementation() and class_replaceMethod(). Store the old IMP, and call it directly. You need to get the method's type encoding. Note that you can just use a normal C function too...
class_getInstanceMethod(), method_getImplementation(), method_setImplementation(). As above, but you don't need to get the method's type encoding.
class_getInstanceMethod() on both methods, and then method_exchangeImplementations(). Call MyCategory_method to get the original implementation. This is the easiest way to do it.
Sometimes, it's the only reasonably easy way to make it do what you want...
EDIT: And only do this if you know what you're doing!
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocCategories.html
Doesn't look like it is possible.
When a category overrides an inherited method, the method in the category can, as usual, invoke the inherited implementation via a message to super. However, if a category overrides a method that already existed in the category's class, there is no way to invoke the original implementation.
What this is saying to me is that if you override a method on a subclass via a category, you can call [super methodName] as you would normally, but if you override the base class method directly, you can't invoke the original.
If you dynamically provide the category override (see resolveInstanceMethod:), you can cache the previous method selector beforehand, and call that.