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

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...

Related

Objective-c coding

I'm really confused about using proprieties.
if i declare this
#property (nonatomic, strong) NSString* aString;
what is the difference between this
1.#synthesize aString = _aString
and
2.#synthesize aString;
if i want to use it, what is the difference between:
3. anOtherString = aString;
and
4. anOtherString = self.aString;
and
5. anOtherString = _aString;
I know that the _aString is the ivar, but the problem is the combination between 1,2,3,4,5.
for example, if i use 2 and 4, i'm i passing a reference to anOtherString or a copy of it ?
I usually use 2 and 4 is that the best choice for passing a reference ?
Your answer are here :
1.#synthesize aString = _aString
Ans: Your property name is aString but you are making an alias _aString. Now you can access aString, your accessors can be used by _aString only. From Xcode4.4 onwards this statement comes by default.
2.#synthesize aString;
Ans: This is the basic style of Objective-c synthesizing a property. From Xcode4.4 onwards this statement overrides the above one.
3.anOtherString = aString;
You are accessing the property by the reference variable/alias.
4.anOtherString = self.aString;
You are using accessor to get its value.
5.anOtherString = _aString;
You are accessing the property itself.
I usually use 2 and 4 is that the best choice for passing a reference ?
Ans : This is good way to do, as self. makes your class KVC compliant.
When you use your #synthesize declaration, this generates getters/setters for you. When you use the #synthesize declaration #synthesize aString = _aString you are making it so that your getter/setter methods will use setAString and aString. You are creating a private variable called _aString. This means that inside your class, you can get this variable by calling
NSString *tempString = _aString;
or
NSString *tempString = self.aString;
The latter uses the generated getter method to retrieve aString.
You can also set your variable using the following methods:
_aString = #"";
or
self.aString = #"";
The latter uses the generated setter method. This is very important, because if you have declared your property as retain (now strong) or copy, then your setter method performs some logic that you may not be aware of (please review strong/copy/weak properties). Essentially, if you have a strong property and you use the generated setter, your code releases it's previous reference on that variable and creates a strong reference to what you're assigning to your variable.
I personally try to always use the getter/setter approach unless it's a weak reference (then it really doesn't matter). I usually always use the #synthesize aString = _aString approach as well, so that I can name method parameters aString if I choose. It helps avoid naming conflicts.
Please let me know if I can clarify in any way.

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]));

"getter" keyword in #property declaration in Objective-C?

I noticed some code example in Apple's documentation shows the following style when declaring the property:
#property (nonatomic, getter=isActivated) BOOL activated;
I understand it allows you to specify a certain name for your getter method. I'd like to know what is the reason and advantage to use this style.
Will I be able to use the dot notation to get the value (e.g. BOOL aBool = someObject.isActivated)? Or should I use
[someObject isActivated];
to access the property? Thanks!
No, the getter keyword only changes the method name. The idea is that you'll access the property just like a variable:
if (self.activated) { ... }
self.activated = YES;
But when you're sending a message to the object, it's readable code: if ([self isActivated]) { ... }.
Kind of the latter. You don’t have to use the method—calling someObject.activated will still work—but it lets you improve the semantics of your class’s interface. A method called -activated could return the value of the ivar activated, or it could do something more esoteric (like activating the object); isActivated clearly returns a Boolean value for whether or not the object is “activated”.

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

How do I dynamically define an instance variable?

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;