How do I dynamically define an instance variable? - objective-c

I have two classes (class1 and class2) that just store data, no methods. I have a third class that has an instance variable that, depending on some user input, will be set to one of the two classes. So, in the third class I declare the variable generically as
NSObject *aClass;
and during runtime set it to whatever it should be.
aClass = [[Class1 alloc] init]; // or
aClass = [[Class2 alloc] init];
However, when I try to access fields from aClass
NSString *str = aClass.field1;
It gives me the error: request for member 'field1' in something not a structure or a union. Field1 is declared in both class1 and class2. When I try to cast aClass
aClass = (Class1 *) aClass;
it gives the same error. What am I doing wrong, is there a better way to do this?

It's because properties only work when the compiler knows the class it has to deal with. NSObject has no property called field1, so it doesn't work.
You can, however, use the field1 method the property implicitly created:
NSString* str = [aClass field1];
But if you're doing it on a NSObject, it's going to emit a warning.
If you don't know which of the two classes you will have and they don't have any class relationship, I suggest you use the id type instead of NSObject. Using id, the compiler won't emit warnings about method calls that could potentially fail (but still won't resolve your properties).

All the compiler knows about aClass is that its an NSObject, so you can only treat it as such. Otherwise, what should happen if you try to access field1 when aClass points to an NSString? Make a superclass with the instance variables you want and declare aClass to be of that type. That ensures that aClass will contain a field1 variable so you can carry on without the poor compiler getting confused.
The reason you can't cast down from NSObject to Class1 follows the same principle. aClass could be anything, and the compiler doesn't know how to anything to a Class1. You can cast the other way because all aClass are NSObjects, but not all NSObjects are aClass. :D

Why not have both of the possible classes inherit from one base class that implements the property you are trying to define?
Or, create a category with that property that both classes implement, and instead of defining an NSObject variable say:
id <MyClassCategory> aClass;

Related

Casting Class type

I know it's possible to define Class property which responds to a given protocol, like:
Class <MyProtocol> class = [object class];
But is there any way in Objective-C to cast Class type to my class?
Class unknownClass = [object class];
[((MyClass)unknownClass) myMethod]; // How can I cast Class to MyClass?
What you are asking doesn't really make any sense.
unknownClass points to a class object. Class is just a type that can hold any pointer to a class object. You call a class method by sending a message to the class object.
Class, like id, turns off static type checking. That means the compiler won't complain that the object might not respond to the method. So you should just send a message to it. "Casting" doesn't make any sense. If you are getting en error that there is no interface that declares this method, then you got a completely unrelated problem that has nothing to do with types; instead the method is not declared in any visible header.
You say in comments to another answer that "I know that 'unknownClass' is in fact MyClass type." That makes your question make even less sense -- why not just use MyClass directly then? instead of unknownClass? Like [MyClass myMethod];
obj->isa = [NewClass class];
This should change an object's class.
When doing so I trust you know what you are doing.

How do I get the Objective-C class of an ivar?

I have a bunch of simple NSManagedObjects I create in a unit test. They just have a single name attribute of type NSString *. I always give my NSManagedObject the same entityName and Class name.
I want to avoid having to write the following code 30 times to set up a unit test:
#interface FooTest : GHTestCase {
Foo *foo;
}
#end
#implementation FooTest
- (void) setUp {
[super setUp];
foo = [NSEntityDescription insertNewObjectForEntityForName:#"Foo"
inManagedObjectContext:managedObjectContext];
foo.name = #"foo";
}
#end
Since foo is an ivar, I would think I should be able to write a macro to grab the type of foo (Foo), and use to create my Foo:
#define InsertManagedObjectByVariable(variable) \
do { \
variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])]; \
variable.name = (NSString *) CFSTR(#variable);
} while(0)
However, this causes the following warning in clang:
variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])];
^
Expected expression
I also thought I could try to determine the type using the objective-c runtime IVar from Ivar class_getInstanceVariable(Class cls, const char* name), but the only IVar type information available from the type encoding from ivar_getTypeEncoding is id, which isn't enough.
Can someone think of a way to obtain the type information of an IVar either at compile time or runtime?
I haven't tried obtaining class information from an ivar, but I know that #property declarations do encode information about the class. For instance, this property declaration:
#property (copy) NSString *normalString;
results in this attribute string (retrieved using property_getAttributes()) at runtime:
T#"NSString",C,VnormalString
I've written some open source parsing code for this information.
Once you have the class name, you can convert it into an actual Class object using NSClassFromString(), and message the result from there.
Disclaimer: This probably shouldn't be depended upon for production applications, as it is undocumented.
An id is an id. At runtime, all Objective-C objects have the same type (objc_object). This is tied up in the dynamic nature of ObjC. For example, an object can change classes at runtime, new classes can be created, and the class hierarchy can change. You can ask a specific instance what its type is (since this is stored in objc_object), but a pointer to an object is just a pointer to an object. Even less than that: it's really just a pointer to a C struct that happens to have extra memory allocated at the end (to hold subclass ivars).
Your macro seems interesting, but you'll probably need to pass the classname as the second parameter rather than autodetecting it.
Maybe i misunderstand what you are trying to achieve.
To get the class of an iVar, can't you use the class method of the iVar?
like:
NSString *aString = #"random string";
NSLog(#"%#",NSStringFromClass([aString class]));

Objective-C: id, accessing instance properties, synthesize?

I'm very new to Objective-C, I'm wondering if there is a simple way to set an id to be an object instance (which has synthesized properties), and directly get/set those properties like:
id myID = myInstance;
myID.myProperty = something;
Where myInstance is an object with a synthesized property called myProperty. When I just do:
myInstance.myProperty = something;
It works, but when I've switched it for an id I get the error
Property 'myProperty' not found on object of type '_strong id'
Do I have to manually make getter/setter methods instead of using synthesize when using an id? Because I do seem to be able to make the id perform the instances methods.
If the object must be of type id, you can use messages (rather than dot notation) to access getters/setters:
id myID = ...;
NSString *prop = [myID property];
[myID setProperty:#"new value"];
But you have better alternatives:
Declaring a new variable
If you know the object's class, just make a variable with that type.
id myID; // defined elsewhere
MyClass *obj = (MyClass *)myID; // if you know the class, make a variable with that type
obj.property = #"new value";
Casting
Use an inline cast to tell the compiler what the type is without making a new variable.
id myID; // defined elsewhere
((MyClass *)myID).property = #"new value";
Protocols
If you don't know the exact class of the object but you know that it must implement certain methods, you can create a protocol:
id<MyProtocol> myID; // the compiler knows the object implements MyProtocol
myID.property = #"new value";
Properties need more information respect to simple messages. So the answer is.. you can't call a property on an id object.
But you can use messages, casting (if you are not sure, use reflection to find out the object type), protocols...

Class Objects and Instance Variables in Objective-C

I'm having a hard time wrapping my head around this concept. I'll take the quote exactly from the book:
Class objects also inherit from the classes above them in the hierarchy. But because they don’t have instance variables (only instances do), they inherit only methods.
Correct me if I'm wrong, but a class object would be this:
NSString *aString = [[NSString alloc]initWithString:#"abc.."];
The class object in this case is *aString -- am I correct so far?
The thing that confuses me is the second sentence in the quote above, "But because they don’t have instance variables (only instances do), they inherit only methods."
I thought that an object (in this case *aString) was the instance of the NSString class.
The second sentence above is implying that an instance is something different. It's not making any sense to me.
You are incorrect.
NSString *aString = [[NSString alloc] initWithString:#"abc..."];
In this line, we have, from left-to-right:
A type: NSString *
A variable name: aString
an assignment
A Class: NSString
An invocation of a class method: +alloc
An invocation of an instance method on the return value of the class method: -initWithString:
An object being passed as a parameter to the instance method: #"abc..."
In Objective-C, a Class is actually a kind of object. You can interact with them in many of the same ways that you can instances, but since they are "classes", they cannot have instance variables (since instance variables, by definition, are only for instances). Classes only have methods. They inherit from other Classes, and this is how object inheritance is implemented.
For more information on this, check out this awesome blog post by Greg Parker: http://www.sealiesoftware.com/blog/archive/2009/04/14/objc_explain_Classes_and_metaclasses.html
In ObjectiveC the classes themselves are objects.
In your example, aString is an NSString object BUT NSString is also an object, it's a class object.
Class object have methods declared like this for example
#interface MyClass : NSObject
{
}
+(void) myClassMethod;
#end
To call the myClassMethod method you type :
[MyClass myClassMethod];
But there is no static variable like in C++ or Java so the class object (here MyClass) can't contain variable but an instance of the class MyClass can have variable.
So to resume NSString is a class object and aString is an instance object of NSString.
In Objective-C, there are instances, which are the objects that you create and use, and there are (semi-hidden) objects which are class objects, and which are created by the compiler. The class object is where the methods for the class are stored; each instance holds only its own data (i.e., instance variables).
Bob * myBob = [[Bob alloc] init];
Here, myBob is an instance. Every instance has a reference back to its class object.1 When you call a method on an instance:
[myBob frogBlastTheVentCore];
the runtime goes and looks up the method in the class object, then uses the instance and the instance's data to perform the method. That's the basic organization of objects in Obj-C: instance objects hold data and have references to their class objects, which hold methods. There is only one class object per class; all instances of that class have a reference to the same class object.
A class (considered as a "type" rather than an object for a moment2) is said to inherit from another class:
#interface Bob : NSObject {
NSColor * uniformColor;
}
+ (BOOL) willShootAtPlayer;
- (void) frogBlastTheVentCore;
#end
#interface VacuBob : Bob {}
#end
Here, VacuBob is a subclass of Bob; any instance of VacuBob has its own uniformColor instance variable. Likewise, there is a class object VacuBob created by the compiler; it too inherits from Bob -- from the Bob class object. This means that the VacuBob class object also has the method willShootAtPlayer.
In the line you posted:
... aString = [NSString alloc] ...
the class object is actually NSString here. You are calling the class method named +[NSString alloc]3 (class methods being denoted by + rather than -4). When a class name is used as the receiver of a message (the first half of the bracketed expression), it refers to the class object5. In this case, then, both NSString and aString are objects; they are just two different kinds of objects; aString is an instance.
Dave DeLong linked to a good post on this (the diagram in particular pretty much lays everything out); for more info, you should also check out Matt Neuberg's description of "The Secret Life of Classes" in his iOS book. It describes the creation of class objects, their uses, and the other things that they do besides holding methods.
1This is the isa pointer: myBob->isa refers to the Bob class object.
2A variable referring to a class object has type Class. An instance object's type is its class. So the type of Bob is Class and the type of myBob is Bob * (that is, a pointer to an object, whose type is Bob). The distinction between the type of a variable and the type of an object may be cause some confusion here.
3The return value of alloc happens to be an instance of NSString, on which you call the instance method initWithString:
4Class methods parallel instance methods in that they are called with the class object itself as an argument. Since class objects have no data of their own, the use of class methods is perhaps more limited than other OO languages; class methods are most often used for vending instances.
5When it is used in the declaration of a variable: NSString * mySting;, it is the name of the type of the variable.

Is there a link between an object named "a" and an object named "_a"?

I am new to iOS so take me slow. When i declare an object in my .h view controller named "_a" and i declare a property "a" and when i synthesize in the .m file
#synthesize a=_a;
must i use "a" or "_a" when i modify that object ? ( "a" is a UINavigationController in my case).
In another question, does my compiler automatically draw a connection from a object declared "ob" to a "_ob" declaration ?
Again, sorry for the poor explanation but this environment isn't quite something i am use to.
An object declared like this:
#interface Example : NSObject {
NSObject *_a;
}
#property (retain) NSObject *a;
#end
And implemented like this:
#import "Example.h"
#implementation Example
#synthesize a = _a;
#end
Makes an ivar named _a and two accessor methods in the Example object. The accessor methods have these signatures:
- (NSObject *)a;
- (void)setA:(NSObject *)theA;
Method a returns the object in the _a ivar. Method setA releases the object stored in _a (if not nil), assigns the parameter to _a, and sends the parameter an retain message.
These methods may also be access through dot notation:
Example *e = [[Example alloc] init];
// These two are equivalent.
e.a = anotherNSObject;
[e setA:anotherNSObject];
// These two are equivalent.
anotherNSObject = e.a;
anotherNSObject = [e a];
Accessing _a directly will circumvent the accessor methods, potentially causing problems such as memory leaks. For example if _a holds the only reference to an object and a new object reference is assigned to _a the old object will become a leaked object.
To directly answer your two questions:
You may use either a or _a. In most cases you'll be better off using _a when reading the value within methods of the object declaring a, and setA (or a in dot notation) when setting the value of _a. Objects that use Example objects should use the accessor methods (with or without dot notation).
The complier does not automatically make a connection between ob and _ob declarations. In this example the #synthesize a = _a; statement makes the connection with the optional = _a. The ivar may have any name. #synthesize a = george; would also be valid. Without the = _a part the compiler would make an ivar named a and two accessor methods.
One further note: You may omit the declaration of _a in the interface, which restricts the scope of the _a ivar to just the implementation of the Example object. Adding the optional = _a to the #synthesize statement will make as ivar of the same type as the property declared in the interface.
#synthesize tell to compiler to generate setter and getter methods for your property. You can use _a as ivar or self.a as property, there are no difference.
Also you can set your class variable from another class via this property
[myClassInstance setA:newA];
oldA = [myClassInstance a]; //oldA = myClassInstance.a