Objective C - respondsToSelector for dynamic properties - objective-c

I am currently facing the problem to check whether a property of an Object (NSManagedObject) exists or not.
Unfortunately the method
[[MyObject class] respondsToSelector:#selector(myProperty)];
always returns NO.
I think it's because the property generated by CoreData is a new style property ala
#property (nonatomic, strong) NSString *myProperty
So any ideas how to solve this issue?
I would really appreciate all of your suggestions ;)
Thanks in advance!
Alex

[[MyObject class] respondsToSelector:...] asks whether the metaobject responds to that selector. So, in effect, it asks whether there is a class method with that selector. Your code would return YES if you had:
+ (NSString *)myProperty;
It returns NO because you have the equivalent of the instance method:
- (NSString *)myProperty;
You need to call respondsToSelector: on an instance of your class.
You could normally use instancesRespondToSelector: directly on the metaclass (so, [MyObject instancesRespondToSelector:...]) but Core Data synthesises the relevant method implementations only when you create an object, so that's a non-starter. You could however create an instance via the normal NSEntityDescription route and test respondsToSelector: on that.
Since it's all Core Data, an alternative would be to ask the NSManagedObjectModel for the relevant NSEntityDescription via its entitiesByName dictionary and inspect the entity description's propertiesByName dictionary.

The only cases I've required this has been to set things dynamically so I am only looking for the setter. I am just composing the signature for the setter and then testing that it exists and then using it.
NSArray * keys = [myObject allKeys];
for(NSString * key in keys)
{
NSString * string = [NSString stringWithFormat:#"set%#:", [key capitalizedString]];
SEL selector = NSSelectorFromString(string);
if([myObject respondsToSelector:selector] == YES)
{
id object = [dict objectForKey:key];
// To massage the compiler's warnings avoid performSelector
IMP imp = [card methodForSelector:selector];
void (*method)(id, SEL, id) = (void *)imp;
method(myObject, selector, object);
}
}
This code satisfies a need where you may not be digesting all the data you receive in the dictionary.
In this case it was sparse json, so some data may not always exist in the json so stepping thru myObjects attributes looking for their corresponding key would just be a lot of wasted effort.

Are you synthesizing the property in the class file?
#interface SomeClass : NSObject
{
#property (nonatomic, strong) NSString *myProperty
}
#end
#implementation SomeClass
#synthesize myProperty;
#end

Related

ios, KVC, why doesn't it invoke countOf<Key> when i invoke [[MyObject valueForKey:"MyArray" ] count]

..................
Environment:OSX10.8, Xcode4.5
Reference:
https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual
/KeyValueCoding/Articles/SearchImplementation.html#//apple_ref/doc/uid
/20000955-CJBBBFFA
If the countOf method and at least one of the other two possible methods are
found, a collection proxy object that responds to all NSArray methods is
returned. Each NSArray message sent to the collection proxy object will result
in some combination of countOf, objectInAtIndex:, and AtIndexes: messages being
sent to the original receiver of valueForKey:.
My steps:
1) Create a property for NSArray* arrs in MyObject.h.
2) in MyObject.m
#implementation MyObject
- (void)setArrs:(NSArray*)arrs
{ _arrs=arrs; }
- (NSUInteger) countOfArrs
{ NSLog("Im here");
return 0;}
- (id) objectInArrsAtIndex:(NSUInteger)index
{ NSLog(#"objectInArrs");
return nil;
}
#end
3) Testing code
MyObject* obj=[[MyObject alloc] init];
NSArray* arr=[NSarray arrayWithObjects:#"abc",nil];
[obj setArrs:arr];
NSLog(#"%d",[[obj valueForKey:#"arrs"]count]);
NSLog(#"%#",[[obj valueForKey:#"arrs"] objectobjectAtIndex:0])
My Question:
I expect it to invoke countOfArrs and objectInArrsAtIndex: automatically,
however, it didn't. All it does is return the normal NSArray, shows count quantity by 1
and 'abc'.
I didn't find any helpful samples,or maybe i misunderstand what the doc says, don't I?
My tangue language is not English, hope i didn't make any ambitious issues.
You have implemented more functionality than what is needed. Your #property declaration is adding the -<key> getter and -set<Key> accessor. As you were able to find out, your getter (called by valueForKey:#"arrs") is returning the actual NSArray assigned to the property which returns its count and object.
The guide you linked to has the reason why this didn't work in step 1 and step 2 of the Default Search Pattern for valueForKey: section.
Basically, your -countOf<Key> and -objectIn<Key>AtIndex: methods are only called when there isn't either a -<key>, -get<Key> or -is<Key> methods.
In order to get this to work, you need to remove the getter by removing the #property declaration, and then you'll need to add an instance variable to save your array.
Make this your interface and it should work
#interface MyObject : NSObject {
NSArray *_arrs;
}
#end

Does iOS change reference of objects?

I don't have too much experience with iOS, but I am working on some legacy code. In the project, we use an object as the key of a dictionary:
NSMutableDictionary * dict;
RoleContainer * role = [Class getRole];
[dict setObject:[Class getData] forKey:role];
We have the role passed to another function. When we try to retrieve the data:
data = [dict objectForKey:role];
Sometimes the return value is empty. It happens about 10% of time. I stepped through the code and found out after passing role to the function the reference of the "role" object had been changed! For example, from 0x002bf500 to 0x00222bad.
Why?
In order to play nicely with NSMutableDictionary your RoleContainer class must implement a hash and isEqual methods. Otherwise, equal roles may get recorded twice in the dictionary, or querying by a valid key may fail.
Here is a brief sample of how you could implement your hash/isEqual when your class has an identifying member:
#interface RoleContainer : NSObject
#property (nonatomic, readonly) NSString *name;
- (NSUInteger)hash;
- (BOOL)isEqual:(id)anObject;
#end
#implementation RoleContainer
#synthesize name = _name;
- (NSUInteger)hash {
return [name hash];
}
- (BOOL)isEqual:(id)anObject {
if (![anObject isKindOfClass:[RoleContainer class]]) {
return NO;
}
RoleContainer *other = (RoleContainer*)anObject;
return [_name isEqual:[other name]];
}
#end
In that code, dict is going to be nil, so you're sending messages to nothing. Is it actually pointing to something later on?
I'm assuming your RoleContainer responds to the stringValue method, which might be a good place to look at what is going on if it's overloaded.
If it's using the standard string value, then it's returning the class and memory location. This may not be reliable if someone down the line is resetting objects to keys.
You may also have an issue where the getData object is being released somewhere where it shouldn't be touched. Try enabling NSZombieEnabled in the debugger, or enable ARC.
try
NSMutableDictionary * dict = [NSMutableDictionary dictionary];
Also it would make sense to have a look at your Class. Is it a class, and getRole a class-method? is it an object?

setValue:forKey: operation?

I am curious what is happening with setValue:forKey: in the code snippet below: is it just setting the pointer to point to each array, similar to ...
[self setMyArray_1: animalArray];
[self setMyArray_2: animalArray];
[self setMyArray_3: animalArray];
Also: does setValue:forKey retain the array? I am guessing it does (as the above would)
Code Snippet:
// INTERFACE
#property(nonatomic, retain) NSArray *myArray_1;
#property(nonatomic, retain) NSArray *myArray_2;
#property(nonatomic, retain) NSArray *myArray_3;
// IMPLEMENTATION
#synthesize myArray_1;
#synthesize myArray_2;
#synthesize myArray_3;
for(counter=1; counter<=3; counter++) {
NSArray *animalArray = [[NSArray alloc] initWithObjects:#"cat", #"rat", nil];
NSString *propertyName = [[NSString alloc] initWithFormat:#"myArray_%d", counter];
[self setValue:animalArray forKey:propertyName];
[animalArray release];
[propertyName release];
}
gary
The answer is yes, the two code snippets essentially do the same thing. setValue:forKey doesn't retain the array, but it finds the synthesized setMyArray_x method which in turn retains the array. iVarName should better be called propertyName or keyName. However, if you hadn't declared and synthesized the properties, but instead just had four ivars, setValue:forKey would still be able to set them to point to animalArray but it wouldn't be retained.
First of all [self setMyArray_1: animalArray]; does not just set pointers, but also retains input array - as it calls automatically generated setter method and its behaviour is defined in corresponding property attributes:
#property(nonatomic, retain) NSArray *myArray_1; // retain !
How accessor method is searched described in Accessor Search Implementation Details in "KVC Coding Guide":
When the default implementation of
setValue:forKey: is invoked for a
property the following search pattern
is used:
The receiver’s class is searched for
an accessor method whose name matches
the pattern -set<Key>:.
So as your class has necessary accesor method (declared via property) this method (setMyArray_i) will get called (and retain your array).

Is there a difference between an "instance variable" and a "property" in Objective-c?

Is there a difference between an "instance variable" and a "property" in Objective-c?
I'm not very sure about this. I think that an "property" is an instance variable that has accessor methods, but I might think wrong.
A property is a more abstract concept. An instance variable is literally just a storage slot, like a slot in a struct. Normally other objects are never supposed to access them directly. A property, on the other hand, is an attribute of your object that can be accessed (it sounds vague and it's supposed to). Usually a property will return or set an instance variable, but it could use data from several or none at all. For example:
#interface Person : NSObject {
NSString *name;
}
#property(copy) NSString *name;
#property(copy) NSString *firstName;
#property(copy) NSString *lastName;
#end
#implementation Person
#synthesize name;
- (NSString *)firstName {
[[name componentsSeparatedByString:#" "] objectAtIndex:0];
}
- (NSString *)lastName {
[[name componentsSeparatedByString:#" "] lastObject];
}
- (NSString *)setFirstName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:#" "];
NSArray *newNameArray [[NSArray arrayWithObjects:newName, nil] arrayByAddingObjectsFromArray:[nameArray subarrayWithRange:NSMakeRange(1, [nameArray size]-1)]];
self.name = [newNameArray componentsJoinedByString:#" "];
}
- (NSString *)setLastName:(NSString *)newName {
NSArray *nameArray = [name componentsSeparatedByString:#" "];
NSArray *newNameArray [[nameArray subarrayWithRange:NSMakeRange(0, [nameArray size]-2)] arrayByAddingObjectsFromArray:[NSArray arrayWithObjects:newName, nil]];
self.name = [newNameArray componentsJoinedByString:#" "];
}
#end
(Note: The above code is buggy in that it assumes the name already exists and has at least two components (e.g. "Bill Gates" rather than just "Gates"). I felt that fixing those assumptions would make the actual point of the code less clear, so I'm just pointing it out here so nobody innocently repeats those mistakes.)
A property is a friendly way of implementing a getter/setter for some value, with additional useful features and syntax. A property can be backed by an instance variable, but you can also define the getter/setter to do something a bit more dynamic, e.g. you might define a lowerCase property on a string which dynamically creates the result rather than returning the value of some member variable.
Here's an example:
// === In your .h ===
#interface MyObject {
NSString *propertyName;
}
// ...
#property (nonatomic, retain) NSString *propertyName;
// === In your .m #implementation ===
#synthesize propertyName /* = otherVarName */;
The #property line defines a property called propertyName of type NSString *. This can be get/set using the following syntax:
myObject.propertyName = #"Hello World!";
NSLog("Value: %#", myObject.propertyName);
When you assign to or read from myObject.propertyName you are really calling setter/getter methods on the object.
The #synthesize line tells the compiler to generate these getter/setters for you, using the member variable with the same name of the property to store the value (or otherVarName if you use the syntax in comments).
Along with #synthesize you can still override one of the getter/setters by defining your own. The naming convention for these methods is setPropertyName: for the setter and propertyName (or getPropertyName, not standard) for the getter. The other will still be generated for you.
In your #property line you can define a number of attributes in parens for the property that can automate things like thread-safety and memory management. By default a property is atomic meaning the compiler will wrap #synthesized get/set calls with appropriate locks to prevent concurrency issues. You can specify the nonatomic attribute to disable this (for example on the iPhone you want to default most properties to nonatomic).
There are 3 attribute values that control memory management for any #synthesized setters. The first is retain which will automatically send release to old values of the property, and retain to the new values. This is very useful.
The second is copy which will make a copy of any values passed in rather than retaining them. It is good practice to use copy for NSString because a caller could pass in an NSMutableString and change it out from under you. copy will make a new copy of the input which only you have access to.
The third is assign which does a straight pointer assign without calling retain/release on the old or new object.
Lastly you can also use the readonly attribute to disable the setter for the property.
I use properties for the interface part - where the object interfaces with other objects
and instance variables are stuff that you need inside your class - nobody but you is supposed to see and manipulate those.
By default, a readwrite property will be backed by an instance variable, which will again be synthesized automatically by the compiler.
An instance variable is a variable that exists and holds its value for the life of the object. The memory used for instance variables is allocated when the object is first created (through alloc), and freed when the object is deallocated.
Unless you specify otherwise, the synthesized instance variable has the same name as the property, but with an underscore prefix. For a property called firstName, for example, the synthesized instance variable will be called _firstName.
Previously people use properties publicly and ivars for private usage, but since several years ago, you can also define properties in #implementation to use them privately. But I'd still use ivars when possible, since there are less letters to type, and it runs faster according to this article. It makes sense since properties are mean to be "heavy": they are supposed to be accessed from either generated getters/setters or the ones manually written.
However, in recent codes from Apple, ivars are not used anymore. I guess because it's more like objc rather than C/C++, plus it's easier to use properties with assign, nullable, etc.
Objective-C Property vs Instance variable (iVar)
[Swift variable, property...]
Instance variable
#interface SomeClass: NSObject
NSString *someVariable;
#end
Property
#interface SomeClass: NSObject
#property (nonatomic, strong) NSString *someVariable;
#end
Property uses Instance variable inside. property = variable + bounded getter/setter. It is a method call with variable syntax and access
#property generates getter and setter methods(accessor methods) which uses backing ivar(aka backing field) which you can use via underscore _<var_name> (_someVariable).
Since it calls a method - method dispatch mechanism is used that is why KVO[About] can be applied
When you override accessor methods backing iVar is not generated that is why you can declare a new property explicitly or use #synthesize[About] to generate a new one or link with existing
#import "SomeClass.h"
#interface SomeClass()
#property (nonatomic, strong) NSString *someVariable;
#end
#implementation SomeClass
- (void) foo {
//property getter method
NSString *a1 = self.someVariable; //NSString *a1 = [self someVariable];
//property setter method
self.someVariable = #"set someVariable"; //[self setSomeVariable:#"set someVariable"];
//iVar read
NSString *a2 = _someVariable;
//iVar write
_someVariable = #"set iVar";
}
//if you overriding someVariable getter and setter the iVar(_someVariable) is not generated, that is why you can:
//1. create some variable explicitly
NSString *_someVariable;
//or
//2. use #synthesize
#synthesize someVariable = _someVariable;
//overriding
- (NSString*) someVariable {
return _someVariable;
}
- (void)setSomeVariable: (NSString*) updatedSomeVariable {
_someVariable = updatedSomeVariable;
}
#end
[property attributes]

How to ensure no memory leak for Objective-C class that is called by many other class

I have the following controller class which will do different tasks based on combination of the flag and param property. The value of these two properties will be set by many other classes having a reference to this controller. The question is how does each of the calling class assign value and when should they release it so that there will be no memory leak ?
#interface SampleController {
NSMutableArray *param;
NSString *flag;
}
#property (nonatomic, retain) NSMutableArray *param;
#property (nonatomic, retain) NSString *flag;
#end
#implementation SampleController
#synthesize param;
#synthesize flag;
- (id)init
{
param = [[NSMutableArray alloc] initWithCapacity:0];
flag = #"nothing";
}
#end
Well it depends on how you call your controller :
in an instance variable of an other object : you have to release it in this object's deallocate methode
in a function : you should release it when you do not need it anymore (retained by another object for example or it finished the job in this function), if you want to return it, just sent the message "autorelease" to it and the NSAutoReleasePool will do the job for you.
To assign value, you can
set the mutable array with the setParam:(*NSMutableArray)theArrayYouWantToReplaceYourArrayWith
access it directly with [[yourSampleController param]addObject:(id)objectYouWantToAdd]...
or more convenient : [yourSampleController.param addObject:(id)objectYouWantToAdd]
The addObject: message here is an example, you can see the methods for modifying an array (remove, sort,...) in the NSMutableArray class reference.
You will not be able to modify your string since it is a NSString and not a NSMutableString, but you can accessit by
[yourSampleController getParam]
[yourSampleController param]
yourSampleController.param
If you want to avoid leaks in general, build your project with the Instrument tool in leak mode and look at the objects that are leaked if you found some that are declared in your functions.
You can also check the Clang Static Analyzer (free static debugger) which is quite good if you have a lot of files.
I hope i helped you
Julien