i want to create some header file for future use but i have 1 problem
i have defined a method in lets say Rimage class called check1
now i want to call that from maiviewcont
so i did this
in mainVC.h
i defined a instance of Rimage class
#import <UIKit/UIKit.h>
#class Rimage;
#interface Rahul_imageplaceCordinatesViewController : UIViewController {
Rimage *aRimage;
}
#property (nonatomic,copy) Rimage *aRimage;
#end
and in .m
[self.aRimage check1];
aRimage = [Rimage check1];
but both are not working
i went for both +(void)check1 and -(void)check1 in Rimage class
The two examples you give do very different things:
[self.aRimage check1];
invokes an check1 instance method on aRimage.
aRimage = [Rimage check1];
calls the check1 class method on the Rimage class, and assigns the result to aRimage.
In both cases, you will need to #import "Rimage.h in your .m file, else you'll get warnings like "aRimage may not respond to 'check1'".
EDIT
Your ".h" file is declaring a property named "aRimage", but that value will be nil until you assign something to it, by doing something like:
self.aRimage = [[[Rimage alloc] init] autorelease];
See this question for a good explanation of the difference between class methods and instance methods.
ps. and don't forget to do a [aRimage release] in your dealloc method
Related
I am relatively new to Objective-C, about 1 year experience, and I had encountered an issue with trying to add a class to my project. When I add a class of UIViewController subclass, with XIB file included, I have no problems with that at all, xcode is working very well that way.
However, I tried to add a simple Objective-C class to the project called Test, with the following .h and .m files, and had a problem where the code compiles and builds without error but the method TestMethod always returns nil. What might be wrong here?
Test.h
#import <Foundation/Foundation.h>
#class Test;
#interface Test : NSObject {
}
- (NSString *)TestMethod;
#end
Test.m
#import "Test.h"
#implementation Test
- (NSString*)TestMethod {
return #"Test";
}
#end
In my UIViewController subclass with XIB file, that subclass works without error, but when I try to include my Test class in it, the method TestMethod returns nothing, even though it is hardcoded to always return the same string:
#import "Test.h"
Test *testobject;
// this compiles and builds but returns nothing
NSString *testString = [testobject TestMethod];
You missed to alloc + init.
Use
Test *testobject=[[Test alloc] init];
or
Test *testobject=[Test new];
Whenever your object is un-initialised you will get nil value.
EDIT:
In ARC : it's default initialized .
In MRC : the value could be uninitialized (garbage value).
TestMethod isn't returing nil - testobject is nil.
Change
Test *testobject;
to
Test *testobject = [[Test alloc] init];
You have not created an instance of Test, so testObject just holds nil. You need to assign an instance of Test to the variable in order to do what you want.
You can also take this approach
//Test.h
#import <Foundation/Foundation.h>
#class Test;
#interface Test : NSObject {
}
- (id)init;
-(NSString*)TestMethod;
#end
Now in your Test.m file
//Test.m
#import "Test.h"
#implementation Test
- (id)init {
if (self=[super init]) {
}
return self;
}
-(NSString*)TestMethod {
return #"Test";
}
#end
Now if you want to call this Test Class in another class, you have to create an instance of Test Class.
Test *testobject = [[Test alloc] init];
NSString *testString = [testobject TestMethod];
To access any method/property of a class, first you need to allocate memory to object of that class using alloc/new method.
Since you created variable of that class type <Test *testobject>. But variable does not allocated any memory, by default it will be nil. Using "nil" you can call any method in objective C. It will not crash. But it will return nil.
So, Before accessing any object you must created memory for that object
Test *testobject = [Test alloc];
initialized the object with default constructor (init, initWith, etc...)
[testobject init];
Now object is ready for calling instance method/setter/getter etc...
NSString *testString = [testobject TestMethod];
Since xcode 4.4 you don't need to #synthesize properties anymore (see here), the compiler does it for you. So, why does the compiler complain
use of the undeclared identifier _aVar
in my viewDidLoad method of ViewControllerSubclass:
#interface ViewController : UIViewController
#property (assign, nonatomic) int aVar;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
#interface ViewControllerSubclass : ViewController
#end
#interface ViewControllerSubclass ()
#property (assign, nonatomic) int aVar;
#end
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
If I move everything to the one file instead of 4 separate files for the respective interfaces and implementations, the compiler instead complains that _aVar is private. But _aVar should have been automatically synthesized in my ViewControllerSubclass.
Still keeping everything in 1 file, if I move the initial property declaration to a class extension:
#interface ViewController ()
#property (assign, nonatomic) int aVar;
#end
The build still fails saying that _aVar is private.
If I go back to the 4 file setup for the respective interfaces and implementations xcode builds without even a warning.
If I then run the code:
[[[ViewControllerSubclass alloc] init] view];
the log statements in the above examples print out the following:
Super value: 0
Subclass value: 5
It makes sense that NSLog(#"Super value: %d", _aVar); produced a result of 0 because this variable is supposed to be private to the superclass. But then, why does NSLog(#"Subclass value: %d", _aVar); produce a result of 5??
This is all very odd.
You are confusing several different issues, and I'm somewhat confused when you talk about jumping between files and you don't specify where your errors are happening.
Anyway, there is the issue of instance variable visibility. If you declare your iVars within the interface scope, they are, by default, protected.
#interface Foo : NSObject {
int protectedInt;
#private
int privateInt;
#public
int publicInt;
}
#end
When you synthesize iVars, the instance variables themselves are private, unless you explicitly specify them.
Methods will always fire on the most derived implementation.
Now, when you call this...
[[[ViewControllerSubclass alloc] init] view];
You will allocate a subclass, initialize, and cause the view to be loaded. This code will execute...
#implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"Subclass value: %d", _aVar);
}
#end
The first thing it does is call the base class implementation...
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(#"Super value: %d", _aVar);
}
#end
Of course, it calls super, but that part's not important here. The next line assigns 5 to self.iVar. But, which iVar? It calls the property setter method on this object. What type is this instance? It's a ViewControllerSubclass. Since you have given both your base class and its subclass the same name (and declared the property as part of the class extension), they each have their own private-scope instance variable .
However, a method is called on the most derived implementation. Thus, self.iVar will set the instance variable of the subclass. The instance variable for the base class remains unchanged.
When you NSLog the value, you are accessing the private instance variable of the base class, which has not been changed.
Now, after the base class viewDidLoad finishes, we get the code running for the subclass. It logs the value of its private instance variable, which was changed as a result of the base class calling the property setter. So, it will now print it's value, which is 5.
When you make the superclass declaration public, the compiler won't attempt to re-synthesize the property; it assumes that's been taken care of in the superclass. Thus, _aVar is not in scope anywhere in the subclass. It's private anyway, so even when you put them all in the same file that's why you see those errors.
However when you make the superclass property declaration inside the class extension, the compiler will auto-synthesize the property for both the superclass and the subclass. This ends up with both classes having private instance variables _aVar (with two distinct addresses). However, when the superclass viewDidLoad method sets the property, the method invokes the subclass's accessors, which set the value of the subclass's private _aVar variable, and not the superclass's. So that explains why you see the superclass value not changing.
Hope this helps!
I just tested your setup and could replicate your error. I came to the following conclusion:
You need to declare your #property in a .h file. If you want a private variable, declare it in .m in the category #interface (the one with the parentheses).
in my AppDelegate I have imported the header of a class I have created and propertied and syntesized an instance of it (in AppDelegate). Now I'm trying to access a method and a variable inside this instance from two other views. I'm relatively new to objective-c, but so far I've learned that if I do this:
AppDelegate *appdelegate = [AppDelegate new];
I will just get a fresh instance from the class inside AppDelegate, so if I set a variable from one view, I can't access it from the other. I've read that if I would do it this way:
AppDelegate *ap = (AppDelegate *)[[UIApplication sharedApplication] delegate];
It would allow me to access the existing instance. But it doesn't work.
Is the way I'm trying to do this totally wrong? Thanks a lot for your help!
UPDATE:
When I do this inside AppDelegate:
myClass.string = #"test";
NSLog(#"appDelegate: %#", myClass.string);
I get this:
appDelegate: (null)
UPDATE2:
I wrote #class AppDelegate; underneath the #import lines in the viewController, but still I can't access myClass. A main problem, which may be the cause why this isn't working from the views, is that I can't even access myClass from AppDelegate.
In AppDelegate.h I wrote:
#property (strong, nonatomic) testClass *myClass;
In AppDelegate.m:
#import "testClass.h"
#synthesize myClass;
This should be right, right?
myClass.h
#property (strong, nonatomic) NSString *string;
myClass.m
#synthesize string;
When I then try to access myClass from appDelegate, I write:
self.myClass.string = #"test";
NSLog(#"appDelegate: %#", self.myClass.string);
The result is:
appDelegate: (null)
I think you have to allocate and initialize the myClass
Write myClass = [MyClass alloc] init] in AppDelegate.m file
#import "AppDelegate"
and also write
#class AppDelegate;
Unless you haven't shown it, you're not allocating testClass and not assigning it to myClass. Objective-C is not like C++ or Java where you can simply declare a variable of a particular class type and have it instantiated on the stack. Each class you use must be instantiated, whether manually or through InterfaceBuilder. The exception is there are some classes provided by the various frameworks which have a single shared instance. Rather than allocating those classes, you simply ask for the shared instance. However, that's not the case here. It's your own class, so you need to allocate it.
It would look like:
myClass = [[testClass alloc] init];
As you can tell, I'm new to Objective-C. I currently have a Singleton working, but I'm trying to use it throughout several methods within the same .m file.
Right now I use this to declare/instantiate the Singleton within a method:
GlobalData *globDat=[GlobalData getInstance];
Do I need to declare it within each method, or is there a way to do this at the top of the .m (or .h?) file so I can access it throughout the other methods?
Thanks...
(BTW I've tried placing the line of code shown above under my "#implementation" line, but I get an error: "Initializer element is not a compile-time constant" which I now know is because the line is not within a method.)
You can add a class extension, and store the global data in ivar, like this:
#interface MyClass() {
GlobalData *globDat;
}
#end
#implementation MyClass
-(id) init {
self = [super init];
if (self) {
globDat=[GlobalData getInstance];
}
return self;
}
#end
This will hide the globDat from the interface, and make it available throughout the methods you implement inside your implementation block of MyClass.
when u need a variable / object that is accessible to all methods in an implementation data, u need to declare it on the header file, and then synthesize it on the implementation file (note that u may need to import the GlobalData header)
so
in header (.h):
#class GlobalData;
#properties (nonatomic, strong) GlobalData *globDat;
and then at the implementation file (.m)
#import "blablabla.h"
#import "GlobalData.h"
#implementation blablabla
#synthesize globDat;
-(void)viewDidLoad
{
globDat = [GlobalData getInstance];
}
good luck
At the moment, the majority of my code is in the same viewcontroller, and i'd like to move some of it over to other areas. Such as moving the animations all over to somewhere else. But then how do i reference things which are in another class? And how do i reference back from that class to items in my viewcontroller class? Not going this has always disuaded me from doing it.
there is a couple of ways you can achieve that.
one way is the cocoa delegate #protocol way, the second way could be creating references to each object in the other class.
for the first way you can do something like this:
#class Class2;
#interface Class1 : NSObject {
Class2 *cls2Pointer;
}
#property Class2 *cls2Pointer;
#end
#class Class1;
#interface Class2 : NSObject {
Class1 *cls1Pointer;
}
#property Class1 *cls1Pointer;
#end
int main(){
Class1 cls1Obj = [[Class1 alloc] init];
Class2 cls2Obj = [[Class2 alloc] init];
[cls1Obj setCls2Pointer:cls2Obj];
[cls2Obj setCls1Pointer:cls1Obj];
}
the second way, is to declare a protocol in one/both of the classes to be able to pass arguments and call different methods on other objects:
#protocol Class1Delegate
- (void)class1:(Class1)obj MethodWithArg:(id)arg;
#end
#interface Class1 : NSObject {
id <Class1Delegate> delegate;
}
#end
#interface Class2 : NSObject <Class1Delegate>{
}
#end
#implementation Class2
- (void)class1:(Class1)obj MethodWithArg:(id)arg {
//do stuff when called from the 1st class
}
#end
You might like to look into this here - to create static classes in objective c and then reference them in a separate file by classname - as in the view controller quoted in the linked example.
Otherwise you can just create a new class within a separate .m file and then code it such that the calling method in another class will first create an instance of this new class and then invoke the necessary method on this instance.
Hope this helps.
Basically what you do is that you create one or more classes, move the code over to these classes and then create instances of these classes in your viewcontroller.
so if you had a method in your view controller
-(void)foo;
you would create a new class say C and move the method there.
then in your view controller you would create an instance variable of that class e.g.
C* myC;
then alloc/init and then call the foo method. This is not object oriented in the sense that foo is not really related to C in any way so method foo could have just been a static method not relating to the instance and as such called just like any other method but as [C foo] instead of [self foo] from the view controller.
the other more OOP method would be to move functionality that belongs to together into a separate class like animation in your example.