I have method which take NSTimer has parameter which is in Class A
-(void)demoMethod:(NSTimer *)timer{
//Do something!
}
Now I have covering test case for the method:
-(void)testDemoMethodPassNilTimer{
//Created class Instance for the ClassA
ClassA *testA = [[ClassA alloc]init];
//[test testDemoMethod:nil];
STAssertThrows([testA testDemoMethod:nil],#"should throw exception");
}
-(void)testDemoMethodPassTimer{
ClassA *testA = [[ClassA alloc]init];
STAssertNoThrows([testA testDemoMethod:??????]);
}
What should be the proper way to pass the parameter for NSTimer Object for the test Case method testDemoMethodPassTimer?
Give it an actual timer object, but don't schedule it on the run loop.
It was also my need to parse parameter to NSTimer. So I had come up with creation of category class, which helped me.
Here are the steps to create Category class over NSTimer.
Right click on project and select "New File"
Cacoa Touch > Objective-C category > Next
Give Category : additions & Category on : NSTimer
in .h file just create property of placeId
in .m synthesize it using #dynamic & create setter, getter
import that .h file in you file.
NSTimer+additions.h file
#import <Foundation/Foundation.h>
#interface NSTimer (additions)
#property(nonatomic,retain) NSString *additionalTag;
#end
NSTimer+additions.m file
#import "NSTimer+additions.h"
#import <objc/runtime.h>
NSString *const additionalTagKey = #"additionalTagKey";
#implementation NSTimer (additions)
#dynamic additionalTag;
- (void)setAdditionalTag:(NSString*)aObject
{
objc_setAssociatedObject(self, additionalTagKey, aObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString*)additionalTag
{
return objc_getAssociatedObject(self, additionalTagKey);
}
#end
Now #import "NSTimer+additions.h" in your class using NSTimer
Passing parameter to NSTimer
-(void)testDemoMethodPassTimer{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0f
target:self
selector:#selector(timerTick:)
userInfo:nil
repeats:YES];
timer.additionalTag = #"parameter passed to timer";
ClassA *testA = [[ClassA alloc]init];
STAssertNoThrows([testA testDemoMethod:timer]);
}
Retrieving parameter from timer
-(void)demoMethod:(NSTimer *)timer{
NSLog(#"My Parameter: %#",timer.additionalTag);
}
Many Steps are involved but hopefully help you a bit. :)
Related
I want to invoke a delegate in class method.
The example below obviously does not work, since the delegate is an instance variable that is accessed within a class method. (Error: instance variable 'delegate' accessed in class method)
Is there an alertnative?
My header file:
// MyClass.h
#import <Foundation/Foundation.h>
#protocol MyDelegate <NSObject>
-(void)update;
#end
#interface MyClass : NSObject
{
id<MyDelegate> delegate;
}
#property (nonatomic, retain) id delegate;
+(void)methodThatInvokesDelegate;
#end
My implementation file:
// MyClass.m
#import "MyClass.h"
#implementation MyClass
#synthesize delegate;
+(void)methodThatInvokesDelegate{
[delegate update];
}
#end
Three obvious options:
Singleton
Static variable (i.e., class variable) pointing to the delegate
Use NSNotification's rather than delegates
Since a singleton (and a static variable) can't keep track of the lifecycle of delegates, I think option three would be the cleanest.
I want to know the context, which let you run in that situation. ;-) Anyway:
First: Delegates are set for a specific instance object. Because of this, you can have different delegates for different instances of the same (delegating) class.
Second: A class method runs inside a class object of that class. This is an object that is different from every instance object of that class. So there is nothing that can be called "the delegate". You can have 100s of delegates.
Third: Your class object needs a delegate at its own. So you have to add a property delegate to the class object and then use this. (Yes, it is possible to have properties an a class object. I did not write declared property.) If you need further information on how to do this, just comment it. I will add code.
I'm not sure if this will help you, but I have a similar situation where I have a class method used for data loads. In this case, the class instantiates itself (so that the caller doesn't need to) until it is done. (this code was edited somewhat to make it work here)
header file:
#protocol DataLoaderDelegate2 <NSObject>
- (void) dataLoaderSuccess:(NSData *)data loader:(id)theloader;
- (void) dataLoaderFailed:(NSString *)error loader:(id)theloader;
#end
#interface DataLoader2 : NSObject {
NSURLConnection *conn;
NSMutableData *receivedData;
NSFileHandle *fileHandle;
id <DataLoaderDelegate2> delegate;
}
#property (nonatomic, assign) id<DataLoaderDelegate2>delegate;
Call to start the process - the call to initWithRequest passes "self" along.
+ (DataLoader2 *)loadWithURLRequest:(NSURLRequest *)req delegate:(id)_delegate
{
DataLoader2 *dl = [[DataLoader2 alloc] init];
[dl setDelegate:_delegate];
conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
return dl;
}
When the data is done loading, it cleans up with something like
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([delegate respondsToSelector:#selector(dataLoaderSuccess:loader:)])
[delegate dataLoaderSuccess:(fileHandle)?(id)fileHandle:(id)receivedData loader:self];
[self autorelease];
}
I have written two classes which contains same method (print). I want to access first class print method using second class object. How i can achieve this?
Code:
#interface classA : NSObject
-(void) print;
#end
#implementation classA
-(void) print
{
NSLog(#"hello");
}
#end
#interface classB : classA
-(void) print;
#end
#implementation classB
-(void) print{
NSLog(#"hey");
}
#end
Now i created second class object like
classB *B = [classB alloc]init];
use delegates to access other classes
#protocol
you can do like this way also
#implementation view1
(void)someMethod
{
......code of method...
}
#implementation view2
(void)fistMethod
{
view1 *abc = [[view1 alloc]init];
[abc someMethod];
[abc release];
}
also check this Objective-C call function on another class?
hi i'm wondering category in objective-c
i have 3 files
A_ViewController
A_ViewController+Category
B_ViewController
here's example code
1-1. A_ViewController.h
#interface A_ViewController {
// some instance Variables
}
//some public methods
#end
1-2 A_ViewController.m
#import "A_ViewController.h."
#implementation A_ViewController
// implementation public methods and private methods
#end
2-1. A_ViewController+Category.h
#interface A_ViewControler(Category)
-(void) categoryMethod;
#end
2-2. A_ViewController+Category.m
#import "A_ViewController.h"
#import "A_ViewController+Category.h"
#implementation A_ViewController(Category)
-(void) categoryMethod {
NSLog(#"it's A_ViewController+Category");
}
#end
3-1. B_ViewController.h
#interface B_ViewController {
// some instance variables
}
-(void) myMethod;
3-2. B_ViewController.m
#import "B_ViewController.h"
#import "A_ViewController.h"
#interface A_ViewController() // i think it's A_ViewController extension, not A_ViewController+Category, am i right?
-(void) categoryMethod;
#end
#implementation B_ViewController
-(void) myMethod
{
A_ViewController *obj = [[A_ViewController alloc] init];
[obj categoryMethod];
}
#end
i thought it's crashed because i'm not import A_ViewController+Category.h
and i'm not implement -(void) categoryMethod in B_ViewController.m
but it works fine, and no warning.
how [obj categoryMethod] can be linked??
if that's perfectly fine syntax, i have extension question.
if i have another category called A_ViewController+Category2
here's A_ViewController+Category.h
#interface A_ViewController(Category2)
-(void) categoryMethod;
#end
and A_ViewController+Category2.m
#import "A_ViewController.h"
#import "A_ViewController+Category2.h"
#implementation A_ViewController(Category2)
-(void) categoryMethod
{
NSLog(#"it's A_ViewController+Category2");
}
#end
and this situation, if i write a code like 3-2,
then [obj categoryMethod] can' be guaranteed
that comes from A_ViewController+Category or A_ViewController+Category2, right?
I'm struggling slightly to work out what you're trying to do but in regard to standard category behaviour.
If you want to call categoryMethod on an instance of A_ViewController from within B_BiewController you need to import the header that contains the category method #interface.
You can't declare the private category () on A_ViewController from within B_ViewController.m, as the private category or class extension is a special category.
B_ViewController.m should look like this
#import "B_ViewController.h"
#import "A_ViewController+Category.h"
#implementation B_ViewController
- (void) myMethod {
A_ViewController *obj = [[A_ViewController alloc] init];
[obj categoryMethod];
}
#end
Edit
I've just noticed your Category2 method name is the same as your Category method name. This is incorrect and undefined behaviour in Objective C.
I have made a simple app to try a nut out the problem; this is also the first time I have used a class method so excuse me if I am doing it wrong.
ViewController.h
#import <UIKit/UIKit.h>
#import "ClassB.h"
#interface ViewController : UIViewController {
NSString *string;
}
#property (nonatomic,retain) NSString *string;
-(void)setString;
-(void)printStringViaClassB;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize string;
- (void)viewDidLoad
{
NSLog(#"I'm inside viewDidLoad");
[super viewDidLoad];
[self setString];
[self printStringViaClassB];
}
-(void)setString {
NSLog(#"I'm inside the setString Method of the ViewController Class");
string = #"HelloWorld";
NSLog(#"String set to: %#",string);
}
-(void)printStringViaClassB {
NSLog(#"I'm inside the printStringViaClassB method of the ViewController Class");
[ClassB printLog];
}
ClassB.h
#import <Foundation/Foundation.h>
#import "ViewController.h"
#class ViewController;
#interface ClassB : NSObject{
}
+(void)printLog;
#end
ClassB.m
#import "ClassB.h"
#implementation ClassB {
}
+(void)printLog {
NSLog(#"I'm in the PrintLog Method of ClassB");
ViewController* VC = [[ViewController alloc] init];
NSLog(#"The set string is: %#",VC.string);
}
#end
This is the resulting log; as you can see, it is showing "(null)" when accessing the string from B instead of HelloWorld.
2011-11-20 14:21:18.223 ClassA[2253:f803] I'm inside viewDidLoad
2011-11-20 14:21:18.224 ClassA[2253:f803] I'm inside the setString Method of the ViewController Class
2011-11-20 14:21:18.225 ClassA[2253:f803] String set to: HelloWorld
2011-11-20 14:21:18.225 ClassA[2253:f803] I'm inside the printStringViaClassB method of the ViewController Class
2011-11-20 14:21:18.226 ClassA[2253:f803] I'm in the PrintLog Method of ClassB
2011-11-20 14:21:18.226 ClassA[2253:f803] The set string is: (null)
When you run the following code: ViewController* VC = [[ViewController alloc] init];, you are creating a NEW instance of ViewController. Since new instances of ViewController don't have their string value until their loaded (i.e., until viewdidload is run), you are simply printing out null.
Try passing in the string value you want to access from the second class as a parameter:
+(void)printLog:(NSString*)log;
+(void)printLog:(NSString*)log {
NSLog(#"I'm in the PrintLog Method of ClassB");
NSLog(#"The set string is: %#",log);
}
to call the function, say [ClassB printLog:string]; instead of [ClassB printLog];
I simply want to change a variable of an object from another class. I can compile without a problem, but my variable always is set to 'null'.
I used the following code:
Object.h:
#interface Object : NSObject {
//...
NSString *color;
//...
}
#property(nonatomic, retain) NSString* color;
+ (id)Object;
- (void)setColor:(NSString*)col;
- (NSString*)getColor;
#end
Object.m:
+(id)Object{
return [[[Object alloc] init] autorelease];
}
- (void)setColor:(NSString*)col {
self.color = col;
}
- (NSString*)getColor {
return self.color;
}
MyViewController.h
#import "Object.h"
#interface ClassesTestViewController : UIViewController {
Object *myObject;
UILabel *label1;
}
#property UILabel *label1;
#property (assign) Object *myObject;
#end
MyViewController.m:
#import "Object.h"
#implementation MyViewController
#synthesize myObject;
- (void)viewDidLoad {
[myObject setColor:#"red"];
NSLog(#"Color = %#", [myObject getColor]);
[super viewDidLoad];
}
The NSLog message is always Color = (null)
I tried many different ways to solve this problem, but no success.
Any help would be appreciated.
Thanks for the help so far.
I modified the code as follow, but it still doesn't work as it should.
MyViewController.h:
#import <UIKit/UIKit.h>
#import "Object.h"
#interface MyViewController : UIViewController {
Object *myObject;
}
#property (nonatomic, retain) Object *myObject;
#end
MyViewController.m:
#import "MyViewController.h"
#import "Object.h"
#implementation MyViewController
#synthesize myObject;
- (void)viewDidLoad {
Object *myObject = [Object new];
myObject = 0;
[myObject setColor:#"red"];
NSLog(#"color = %#", myObject.color);
[super viewDidLoad];
}
If I do it like this, NSLog returns color = null (and I think myObject is only visible in viewDidLoad). How can declare myObject and make it visible in MyViewController?
I stripped down my Object class to
Object.h:
#interface Object : NSObject {
NSString *color;
}
#property(nonatomic, retain) NSString *color;
#end
Object.m:
#import "Object.h"
#implementation Object
#synthesize color;
#end
I wasn't able to define an object myObject in ViewDidLoad so that I can access its properties from the whole ViewController class? What did I miss?
Side question: Why do I have to set myObject to 0?
You're declaring a property, then explicitly declaring the accessors in Object.h. You only need to do one or the other - they mean the same thing (well, almost - you'll have color instead of getColor)
To implement the property in Object.m you should use #synthesize color. The explicit implementations, again, are then redundant (unless they do anything extra).
The explicit setColor implementation in Object.m is calling the property - which you are implementing explicitly, so I would have expected you to get an infinite recursion here.
MyViewController.m should probably synthesize label1, since you declare the property in the header (although it's not being used in your snippet).
[myObject getColor] is calling the color property, which you declared but did not synthesize. If you had explicitly implemented it as color it would have picked that up - but it won't match getColor (which is fortunately as that would have led to an infinite recursion again.
I don't see anywhere where you create your myObject instance. If you don't it will be nil and methods called on it (including property accesses) will return 0 or nil.
I suspect (6) is the cause of your issue, but the others need to be addressed too. Make sure you read up on property syntax.